]> git.mxchange.org Git - flightgear.git/commitdiff
Merge FG_Tools as subdirectory
authorTim Moore <timoore@redhat.com>
Mon, 14 Sep 2009 11:43:55 +0000 (13:43 +0200)
committerTim Moore <timoore@redhat.com>
Mon, 14 Sep 2009 11:43:55 +0000 (13:43 +0200)
190 files changed:
1  2 
Tools/Areas/Makefile.am
Tools/Areas/area.cxx
Tools/Areas/area.hxx
Tools/Areas/main.cxx
Tools/Array/Makefile.am
Tools/Array/array.cxx
Tools/Array/array.hxx
Tools/Array/testarray.cxx
Tools/AssemTris/Makefile.am
Tools/AssemTris/assemtris.cxx
Tools/AssemTris/assemtris.hxx
Tools/CVSROOT/checkoutlist
Tools/CVSROOT/commitinfo
Tools/CVSROOT/cvswrappers
Tools/CVSROOT/editinfo
Tools/CVSROOT/loginfo
Tools/CVSROOT/modules
Tools/CVSROOT/notify
Tools/CVSROOT/rcsinfo
Tools/CVSROOT/taginfo
Tools/Clipper/Makefile.am
Tools/Clipper/clipper.cxx
Tools/Clipper/clipper.hxx
Tools/Clipper/testclipper.cxx
Tools/Combine/Makefile.am
Tools/Combine/genfans.cxx
Tools/Combine/genfans.hxx
Tools/Construct/Makefile.am
Tools/DEM/Makefile.am
Tools/DEM/dem.cxx
Tools/DEM/dem.hxx
Tools/DemChop/Makefile.am
Tools/DemChop/demchop.cxx
Tools/DemChop/point2d.cxx
Tools/DemChop/point2d.hxx
Tools/DemInfo/Makefile.am
Tools/DemInfo/deminfo.cxx
Tools/DemInfo/gather-dem-info.pl
Tools/DemRaw2ascii/Makefile.am
Tools/DemRaw2ascii/main.c
Tools/DemRaw2ascii/rawdem.c
Tools/DemRaw2ascii/rawdem.h
Tools/FixNode/Makefile.am
Tools/FixNode/fixnode.cxx
Tools/FixNode/fixnode.hxx
Tools/FixNode/main.cxx
Tools/FixObj/Makefile.am
Tools/FixObj/main.cxx
Tools/FixObj/obj.cxx
Tools/FixObj/obj.hxx
Tools/GenAirports/Makefile.am
Tools/GenAirports/area.cxx
Tools/GenAirports/area.hxx
Tools/GenAirports/convex_hull.cxx
Tools/GenAirports/convex_hull.hxx
Tools/GenAirports/main.cxx
Tools/GenAirports/point2d.cxx
Tools/GenAirports/point2d.hxx
Tools/GenOutput/Makefile.am
Tools/GenOutput/genobj.cxx
Tools/GenOutput/genobj.hxx
Tools/Lib/Makefile.am
Tools/Main/Makefile.am
Tools/Main/construct.cxx
Tools/Main/construct_types.hxx
Tools/Makedir/Makefile.am
Tools/Makedir/makedir.cxx
Tools/Polygon/Makefile.am
Tools/Polygon/index.cxx
Tools/Polygon/index.hxx
Tools/Polygon/names.cxx
Tools/Polygon/names.hxx
Tools/Prep/Makefile.am
Tools/ShapeFile/Makefile.am
Tools/ShapeFile/main.cxx
Tools/ShapeFile/shape.cxx
Tools/ShapeFile/shape.hxx
Tools/SplitTris/Makefile.am
Tools/SplitTris/splittris.cxx
Tools/SplitTris/splittris.hxx
Tools/Stripe_u/Makefile.am
Tools/Stripe_u/add.c
Tools/Stripe_u/add.h
Tools/Stripe_u/bands.c
Tools/Stripe_u/common.c
Tools/Stripe_u/common.h
Tools/Stripe_u/define.h
Tools/Stripe_u/extend.h
Tools/Stripe_u/free.c
Tools/Stripe_u/free.h
Tools/Stripe_u/global.h
Tools/Stripe_u/glove.h
Tools/Stripe_u/init.c
Tools/Stripe_u/init.h
Tools/Stripe_u/local.c
Tools/Stripe_u/local.h
Tools/Stripe_u/my_global.h
Tools/Stripe_u/newpolve.c
Tools/Stripe_u/options.c
Tools/Stripe_u/options.h
Tools/Stripe_u/output.c
Tools/Stripe_u/output.h
Tools/Stripe_u/outputex.c
Tools/Stripe_u/outputex.h
Tools/Stripe_u/partial.c
Tools/Stripe_u/partial.h
Tools/Stripe_u/polverts.h
Tools/Stripe_u/polvertsex.h
Tools/Stripe_u/queue.c
Tools/Stripe_u/queue.h
Tools/Stripe_u/sgi_triang.c
Tools/Stripe_u/sgi_triangex.c
Tools/Stripe_u/struct.c
Tools/Stripe_u/struct.h
Tools/Stripe_u/structex.c
Tools/Stripe_u/sturcts.h
Tools/Stripe_u/sturctsex.h
Tools/Stripe_u/ties.c
Tools/Stripe_u/ties.h
Tools/Stripe_u/triangulate.h
Tools/Stripe_u/triangulatex.h
Tools/Stripe_u/util.c
Tools/Stripe_u/util.h
Tools/Stripe_w/Makefile.am
Tools/Stripe_w/add.c
Tools/Stripe_w/add.h
Tools/Stripe_w/bands.c
Tools/Stripe_w/common.c
Tools/Stripe_w/common.h
Tools/Stripe_w/extend.h
Tools/Stripe_w/free.c
Tools/Stripe_w/free.h
Tools/Stripe_w/global.h
Tools/Stripe_w/init.c
Tools/Stripe_w/init.h
Tools/Stripe_w/local.c
Tools/Stripe_w/local.h
Tools/Stripe_w/newpolve.c
Tools/Stripe_w/options.c
Tools/Stripe_w/options.h
Tools/Stripe_w/output.c
Tools/Stripe_w/output.h
Tools/Stripe_w/outputex.c
Tools/Stripe_w/outputex.h
Tools/Stripe_w/partial.c
Tools/Stripe_w/partial.h
Tools/Stripe_w/polverts.h
Tools/Stripe_w/polyvertsex.h
Tools/Stripe_w/queue.c
Tools/Stripe_w/queue.h
Tools/Stripe_w/sgi_triang.c
Tools/Stripe_w/sgi_triangex.c
Tools/Stripe_w/struct.c
Tools/Stripe_w/structex.c
Tools/Stripe_w/sturcts.h
Tools/Stripe_w/sturctsex.h
Tools/Stripe_w/ties.c
Tools/Stripe_w/ties.h
Tools/Stripe_w/triangulate.h
Tools/Stripe_w/triangulatex.h
Tools/Stripe_w/util.c
Tools/Stripe_w/util.h
Tools/Tools/Makefile.am
Tools/Tools/README
Tools/Tools/Todo
Tools/Tools/process-dem.pl
Tools/Tools/scenery_version.hxx
Tools/Tri2obj/Makefile.am
Tools/Tri2obj/tri2obj.cxx
Tools/Tri2obj/tri2obj.hxx
Tools/Triangle/A.poly
Tools/Triangle/Makefile.am
Tools/Triangle/README
Tools/Triangle/showme.c
Tools/Triangle/triangle.c
Tools/Triangle/triangle.doc
Tools/Triangle/triangle.h
Tools/Triangle/tricall.c
Tools/Triangulate/Makefile.am
Tools/Triangulate/triangle.cxx
Tools/Triangulate/triangle.hxx
Tools/Triangulate/trieles.cxx
Tools/Triangulate/trieles.hxx
Tools/Triangulate/trinodes.cxx
Tools/Triangulate/trinodes.hxx
Tools/Triangulate/tripoly.cxx
Tools/Triangulate/tripoly.hxx
Tools/Triangulate/trisegs.cxx
Tools/Triangulate/trisegs.hxx
Tools/Utils/Makefile.am

index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7c6106189098e644a5e6597820f4de03df942203
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,62 @@@
++#---------------------------------------------------------------------------
++# Makefile
++#
++# Written by Curtis Olson, started January 1998.
++#
++# Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++# $Id$
++# (Log is kept at end of this file)
++#---------------------------------------------------------------------------
++
++
++bin_PROGRAMS = areas
++
++areas_SOURCES = area.cxx area.hxx main.cxx
++
++areas_LDADD = \
++      $(top_builddir)/Lib/Bucket/libBucket.a \
++      $(base_LIBS)
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
++
++
++#---------------------------------------------------------------------------
++# $Log$
++# Revision 1.3  1998/11/04 23:01:43  curt
++# Changes to the automake/autoconf system to reduce the number of libraries
++# that are unnecessarily linked into the various executables.
++#
++# Revision 1.2  1998/07/30 23:49:18  curt
++# Removed libtool support.
++#
++# Revision 1.1  1998/07/20 12:54:53  curt
++# Whoops, need to commit Makefile.am, not Makefile.
++#
++# Revision 1.2  1998/04/14 02:25:59  curt
++# Code reorganizations.  Added a Lib/ directory for more general libraries.
++#
++# Revision 1.1  1998/04/08 22:54:57  curt
++# Adopted Gnu automake/autoconf system.
++#
++# Revision 1.2  1998/01/21 02:55:46  curt
++# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
++#
++# Revision 1.1  1998/01/15 02:45:25  curt
++# Initial revision.
++#
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2dabe331de9a43fb0a16389134fc83a58eca756a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,161 @@@
++// area.c -- routines to assist with inserting "areas" into FG terrain
++//
++// Written by Curtis Olson, started March 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#include <math.h>
++#include <stdio.h>
++
++#include <Include/fg_constants.h>
++
++#include "area.hxx"
++
++
++// calc new x, y for a rotation
++double rot_x(double x, double y, double theta) {
++    return ( x * cos(theta) + y * sin(theta) );
++}
++
++
++// calc new x, y for a rotation
++double rot_y(double x, double y, double theta) {
++    return ( -x * sin(theta) + y * cos(theta) );
++}
++
++
++// calc new lon/lat given starting lon/lat, and offset radial, and
++// distance.  NOTE: distance is specified in meters (and converted
++// internally to radians)
++point2d calc_lon_lat( point2d orig, point2d offset ) {
++    point2d result;
++
++    offset.dist *= METER_TO_NM * NM_TO_RAD;
++
++    result.lat = asin( sin(orig.lat) * cos(offset.dist) + 
++                     cos(orig.lat) * sin(offset.dist) * cos(offset.theta) );
++
++    if ( cos(result.lat) < FG_EPSILON ) {
++        result.lon = orig.lon;      // endpoint a pole
++    } else {
++        result.lon = 
++          fmod(orig.lon - asin( sin(offset.theta) * sin(offset.dist) / 
++                                cos(result.lat) ) + FG_PI, FG_2PI) - FG_PI;
++    }
++
++    return(result);
++}
++
++
++point2d cart_to_polar_2d(point2d in) {
++    point2d result;
++    result.dist = sqrt( in.x * in.x + in.y * in.y );
++    result.theta = atan2(in.y, in.x);    
++
++    return(result);
++}
++
++
++void batch_cart_to_polar_2d(point2d *in, point2d *out, int size) {
++    int i;
++
++    for ( i = 0; i < size; i++ ) {
++      out[i] = cart_to_polar_2d( in[i] );
++    }
++}
++
++
++// given a set of 2d coordinates relative to a center point, and the
++// lon, lat of that center point, as well as a potential orientation
++// angle, generate the corresponding lon and lat of the original 2d
++// verticies.
++void make_area(point2d orig, point2d *cart, point2d *result, 
++             int size, double angle ) {
++    point2d rad[size];
++    int i;
++
++    // convert to polar coordinates
++    batch_cart_to_polar_2d(cart, rad, size);
++    for ( i = 0; i < size; i++ ) {
++      printf("(%.2f, %.2f)\n", rad[i].dist, rad[i].theta);
++    }
++    printf("\n");
++
++    // rotate by specified angle
++    for ( i = 0; i < size; i++ ) {
++      rad[i].theta += angle;
++      while ( rad[i].theta > FG_2PI ) {
++          rad[i].theta -= FG_2PI;
++      }
++      printf("(%.2f, %.2f)\n", rad[i].dist, rad[i].theta);
++    }
++    printf("\n");
++
++    for ( i = 0; i < size; i++ ) {
++      result[i] = calc_lon_lat(orig, rad[i]);
++      printf("(%.8f, %.8f)\n", result[i].lon, result[i].lat);
++    }
++    printf("\n");
++}
++
++
++// generate an area for a runway
++void gen_runway_area( double lon, double lat, double heading, 
++                    double length, double width,
++                    point2d *result, int *count) 
++{
++    point2d cart[4];
++    point2d orig;
++    double l, w;
++    int i;
++
++    orig.lon = lon;
++    orig.lat = lat;
++    l = (length / 2.0) + (length * 0.1);
++    w = (width / 2.0) + (width * 0.1);
++
++    // generate untransformed runway area vertices
++    cart[0].x =  l; cart[0].y =  w;
++    cart[1].x =  l; cart[1].y = -w;
++    cart[2].x = -l; cart[2].y = -w;
++    cart[3].x = -l; cart[3].y =  w;
++    for ( i = 0; i < 4; i++ ) {
++      printf("(%.2f, %.2f)\n", cart[i].x, cart[i].y);
++    }
++    printf("\n");
++
++    make_area(orig, cart, result, 4, heading);
++
++    for ( i = 0; i < 4; i++ ) {
++      printf("(%.8f, %.8f)\n", result[i].lon, result[i].lat);
++    }
++    printf("\n");
++
++    *count = 4;
++}
++
++
++// $Log$
++// Revision 1.1  1998/07/20 12:54:05  curt
++// Initial revision.
++//
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..584e5f6a003d0f6700d4ea6537e012ab77a2522d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,57 @@@
++// area.h -- routines to assist with inserting "areas" into FG terrain
++//
++// Written by Curtis Olson, started February 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#ifndef _AREA_H
++#define _AREA_H
++
++
++typedef struct {
++    union {
++      double x;
++      double dist;
++      double lon;
++    };
++    union {
++      double y;
++      double theta;
++      double lat;
++    };
++} point2d;
++
++
++// generate an area for a runway
++void gen_runway_area( double lon, double lat, double heading, 
++                    double length, double width,
++                    point2d *result, int *count );
++
++
++#endif // _AREA_H
++
++
++// $Log$
++// Revision 1.1  1998/07/20 12:54:05  curt
++// Initial revision.
++//
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1f6d635b81de03ca7f3a6fc6f629e77228baac76
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,130 @@@
++// main.c -- main loop
++//
++// Written by Curtis Olson, started March 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#ifdef HAVE_STDLIB_H
++#include <stdlib.h>
++#endif
++
++#include <stdio.h>
++#include <string.h>
++
++#include "area.hxx"
++
++#include <Bucket/bucketutils.h>
++#include <Include/fg_constants.h>
++
++
++int main( int argc, char **argv ) {
++    fgBUCKET b;
++    point2d nodes[4];
++    FILE *fd;
++    char base[256], path[256], command[256], file[256], exfile[256];
++    double lon, lat, elevation, heading;
++    double length, width;
++    long int index;
++    int i, count;
++
++    if ( argc != 2 ) {
++      printf("Usage %s <work dir>\n", argv[0]);
++      exit(0);
++    }
++
++    // P13 (Globe, AZ)
++    // lon = -110.6642442;
++    // lat = 33.3528903;
++    // heading = 102.0 * DEG_TO_RAD;
++    // length = 1769;
++    // width = 23;
++
++    // KANE
++    lon = -93.2113889;
++    lat = 45.145;
++    elevation = 912 * FEET_TO_METER;
++    heading = 270.0 * DEG_TO_RAD;
++    length = 1220;
++    width = 23;
++
++    gen_runway_area( lon * DEG_TO_RAD, lat * DEG_TO_RAD, 
++                   heading, length, width, nodes, &count );
++
++    fgBucketFind(lon, lat, &b);
++    printf( "Bucket = lon,lat = %d,%d  x,y index = %d,%d\n", 
++          b.lon, b.lat, b.x, b.y);
++
++    index = fgBucketGenIndex(&b);
++    fgBucketGenBasePath(&b, base);
++    sprintf(path, "%s/Scenery/%s", argv[1], base);
++    sprintf(command, "mkdir -p %s\n", path);
++    system(command);
++    
++    sprintf(exfile, "%s/%ld.node.ex", path, index);
++    sprintf(file, "%s/%ld.poly", path, index);
++    printf( "extra node file = %s\n", exfile);
++    printf( "poly file = %s\n", file);
++
++    // output extra nodes
++    if ( (fd = fopen(exfile, "w")) == NULL ) {
++        printf("Cannot open file: %s\n", exfile);
++        exit(-1);
++    }
++
++    fprintf(fd, "%d 2 0 0\n", count);
++    for ( i = 0; i < count; i++ ) {
++      fprintf( fd, "%d %.2f %.2f %.2f\n", i + 1, 
++               nodes[i].lon * RAD_TO_ARCSEC, nodes[i].lat * RAD_TO_ARCSEC, 
++               elevation);
++    }
++    fclose(fd);
++
++    // output poly
++    if ( (fd = fopen(file, "w")) == NULL ) {
++        printf("Cannot open file: %s\n", file);
++        exit(-1);
++    }
++
++    // output empty node list
++    fprintf(fd, "0 2 0 0\n");
++
++    // output segments
++    fprintf(fd, "%d 0\n", count);
++    for ( i = 0; i < count - 1; i++ ) {
++      fprintf( fd, "%d %d %d\n", i + 1, i + 1, i + 2 );
++    }
++    fprintf( fd, "%d %d %d\n", count, count, 1 );
++
++    // output hole center
++    fprintf( fd, "1\n");
++    fprintf( fd, "1 %.2f %.2f\n", lon * 3600.0, lat * 3600);
++
++    fclose(fd);
++}
++
++
++// $Log: main.c,v
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a62648005132887e62bd365c735bf73990896dc1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,25 @@@
++noinst_LIBRARIES = libArray.a
++
++libArray_a_SOURCES = array.cxx array.hxx
++
++bin_PROGRAMS = testarray
++
++testarray_SOURCES = testarray.cxx
++
++testarray_LDADD = \
++      $(top_builddir)/Tools/Construct/Array/libArray.a \
++      $(top_builddir)/Lib/Bucket/libBucket.a \
++      $(top_builddir)/Lib/Math/libMath.a \
++      $(top_builddir)/Lib/Misc/libMisc.a \
++      $(top_builddir)/Lib/zlib/libz.a
++
++INCLUDES += \
++      -I$(top_builddir) \
++      -I$(top_builddir)/Lib \
++      -I$(top_builddir)/Tools/Construct
++
++# We can't build this with "-O2" (optimization) since this causes a seg fault
++# I haven't found a way to strip this out of the CXXFLAGS, so I'm just
++# setting it to "-g"
++# CXXFLAGS = -g
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2b7d2a625c02fc9edceedb12753a6efdeb223807
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,607 @@@
++// array.cxx -- Array management class
++//
++// Written by Curtis Olson, started March 1998.
++//
++// Copyright (C) 1998 - 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifdef HAVE_CONFIG_H
++#  include <config.h>
++#endif
++
++#include <Include/compiler.h>
++
++// #include <ctype.h>    // isspace()
++// #include <stdlib.h>   // atoi()
++// #include <math.h>     // rint()
++// #include <stdio.h>
++// #include <string.h>
++// #ifdef HAVE_SYS_STAT_H
++// #  include <sys/stat.h> // stat()
++// #endif
++// #ifdef FG_HAVE_STD_INCLUDES
++// #  include <cerrno>
++// #else
++// #  include <errno.h>
++// #endif
++// #ifdef HAVE_UNISTD_H
++// # include <unistd.h>   // stat()
++// #endif
++
++#include STL_STRING
++
++#include <Include/fg_constants.h>
++#include <Misc/fgstream.hxx>
++#include <Misc/strutils.hxx>
++#include <Math/leastsqs.hxx>
++
++#include "array.hxx"
++
++FG_USING_STD(string);
++
++
++FGArray::FGArray( void ) {
++    // cout << "class FGArray CONstructor called." << endl;
++    in_data = new float[ARRAY_SIZE_1][ARRAY_SIZE_1];
++    // out_data = new float[ARRAY_SIZE_1][ARRAY_SIZE_1];
++}
++
++
++FGArray::FGArray( const string &file ) {
++    // cout << "class FGArray CONstructor called." << endl;
++    in_data = new float[ARRAY_SIZE_1][ARRAY_SIZE_1];
++    // out_data = new float[ARRAY_SIZE_1][ARRAY_SIZE_1];
++
++    FGArray::open(file);
++}
++
++
++// open an Array file
++int
++FGArray::open( const string& file ) {
++    // open input file (or read from stdin)
++    if ( file ==  "-" ) {
++      cout << "  Opening array data pipe from stdin" << endl;
++      // fd = stdin;
++      // fd = gzdopen(STDIN_FILENO, "r");
++      cout << "  Not yet ported ..." << endl;
++      return 0;
++    } else {
++      in = new fg_gzifstream( file );
++      if ( ! in->is_open() ) {
++          cout << "  Cannot open " << file << endl;
++          return 0;
++      }
++      cout << "  Opening array data file: " << file << endl;
++    }
++
++    return 1;
++}
++
++
++// close an Array file
++int
++FGArray::close() {
++    // the fg_gzifstream doesn't seem to have a close()
++
++    delete in;
++
++    return 1;
++}
++
++
++// parse Array file, pass in the bucket so we can make up values when
++// the file wasn't found.
++int
++FGArray::parse( FGBucket& b ) {
++    if ( in->is_open() ) {
++      // file open, parse
++      *in >> originx >> originy;
++      *in >> cols >> col_step;
++      *in >> rows >> row_step;
++
++      cout << "    origin  = " << originx << "  " << originy << endl;
++      cout << "    cols = " << cols << "  rows = " << rows << endl;
++      cout << "    col_step = " << col_step 
++           << "  row_step = " << row_step <<endl;
++
++      for ( int i = 0; i < cols; i++ ) {
++          for ( int j = 0; j < rows; j++ ) {
++              *in >> in_data[i][j];
++          }
++      }
++
++      cout << "    Done parsing\n";
++    } else {
++      // file not open (not found?), fill with zero'd data
++
++      originx = ( b.get_center_lon() - 0.5 * b.get_width() ) * 3600.0;
++      originy = ( b.get_center_lat() - 0.5 * b.get_height() ) * 3600.0;
++
++      double max_x = ( b.get_center_lon() + 0.5 * b.get_width() ) * 3600.0;
++      double max_y = ( b.get_center_lat() + 0.5 * b.get_height() ) * 3600.0;
++
++      cols = 3;
++      col_step = (max_x - originx) / (cols - 1);
++      rows = 3;
++      row_step = (max_y - originy) / (rows - 1);
++
++      cout << "    origin  = " << originx << "  " << originy << endl;
++      cout << "    cols = " << cols << "  rows = " << rows << endl;
++      cout << "    col_step = " << col_step 
++           << "  row_step = " << row_step <<endl;
++
++      for ( int i = 0; i < cols; i++ ) {
++          for ( int j = 0; j < rows; j++ ) {
++              in_data[i][j] = 0.0;
++          }
++      }
++
++      cout << "    File not open, so using zero'd data" << endl;
++    }
++
++    return 1;
++}
++
++
++// add a node to the output corner node list
++void FGArray::add_corner_node( int i, int j, double val ) {
++    
++    double x = (originx + i * col_step) / 3600.0;
++    double y = (originy + j * row_step) / 3600.0;
++    // cout << "originx = " << originx << "  originy = " << originy << endl;
++    // cout << "corner = " << Point3D(x, y, val) << endl;
++    corner_list.push_back( Point3D(x, y, val) );
++}
++
++
++// add a node to the output fitted node list
++void FGArray::add_fit_node( int i, int j, double val ) {
++    double x = (originx + i * col_step) / 3600.0;
++    double y = (originy + j * row_step) / 3600.0;
++    // cout << Point3D(x, y, val) << endl;
++    node_list.push_back( Point3D(x, y, val) );
++}
++
++
++// Use least squares to fit a simpler data set to dem data.  Return
++// the number of fitted nodes
++int FGArray::fit( double error ) {
++    double x[ARRAY_SIZE_1], y[ARRAY_SIZE_1];
++    double m, b, max_error, error_sq;
++    double x1, y1;
++    // double ave_error;
++    double cury, lasty;
++    int n, row, start, end;
++    int colmin, colmax, rowmin, rowmax;
++    bool good_fit;
++    // FILE *dem, *fit, *fit1;
++
++    error_sq = error * error;
++
++    cout << "  Initializing fitted node list" << endl;
++    corner_list.clear();
++    node_list.clear();
++
++    // determine dimensions
++    colmin = 0;
++    colmax = cols;
++    rowmin = 0;
++    rowmax = rows;
++    cout << "  Fitting region = " << colmin << "," << rowmin << " to " 
++       << colmax << "," << rowmax << endl;;
++    
++    // generate corners list
++    add_corner_node( colmin, rowmin, in_data[colmin][rowmin] );
++    add_corner_node( colmin, rowmax-1, in_data[colmin][rowmax] );
++    add_corner_node( colmax-1, rowmin, in_data[colmax][rowmin] );
++    add_corner_node( colmax-1, rowmax-1, in_data[colmax][rowmax] );
++
++    cout << "  Beginning best fit procedure" << endl;
++    lasty = 0;
++
++    for ( row = rowmin; row < rowmax; row++ ) {
++      // fit  = fopen("fit.dat",  "w");
++      // fit1 = fopen("fit1.dat", "w");
++
++      start = colmin;
++
++      // cout << "    fitting row = " << row << endl;
++
++      while ( start < colmax - 1 ) {
++          end = start + 1;
++          good_fit = true;
++
++          x[0] = start * col_step;
++          y[0] = in_data[start][row];
++
++          x[1] = end * col_step;
++          y[1] = in_data[end][row];
++
++          n = 2;
++
++          // cout << "Least square of first 2 points" << endl;
++          least_squares(x, y, n, &m, &b);
++
++          end++;
++
++          while ( (end < colmax) && good_fit ) {
++              ++n;
++              // cout << "Least square of first " << n << " points" << endl;
++              x[n-1] = x1 = end * col_step;
++              y[n-1] = y1 = in_data[end][row];
++              least_squares_update(x1, y1, &m, &b);
++              // ave_error = least_squares_error(x, y, n, m, b);
++              max_error = least_squares_max_error(x, y, n, m, b);
++
++              /*
++              printf("%d - %d  ave error = %.2f  max error = %.2f  y = %.2f*x + %.2f\n", 
++              start, end, ave_error, max_error, m, b);
++              
++              f = fopen("gnuplot.dat", "w");
++              for ( j = 0; j <= end; j++) {
++                  fprintf(f, "%.2f %.2f\n", 0.0 + ( j * col_step ), 
++                          in_data[row][j]);
++              }
++              for ( j = start; j <= end; j++) {
++                  fprintf(f, "%.2f %.2f\n", 0.0 + ( j * col_step ), 
++                          in_data[row][j]);
++              }
++              fclose(f);
++
++              printf("Please hit return: "); gets(junk);
++              */
++
++              if ( max_error > error_sq ) {
++                  good_fit = false;
++              }
++              
++              end++;
++          }
++
++          if ( !good_fit ) {
++              // error exceeded the threshold, back up
++              end -= 2;  // back "end" up to the last good enough fit
++              n--;       // back "n" up appropriately too
++          } else {
++              // we popped out of the above loop while still within
++              // the error threshold, so we must be at the end of
++              // the data set
++              end--;
++          }
++          
++          least_squares(x, y, n, &m, &b);
++          // ave_error = least_squares_error(x, y, n, m, b);
++          max_error = least_squares_max_error(x, y, n, m, b);
++
++          /*
++          printf("\n");
++          printf("%d - %d  ave error = %.2f  max error = %.2f  y = %.2f*x + %.2f\n", 
++                 start, end, ave_error, max_error, m, b);
++          printf("\n");
++
++          fprintf(fit1, "%.2f %.2f\n", x[0], m * x[0] + b);
++          fprintf(fit1, "%.2f %.2f\n", x[end-start], m * x[end-start] + b);
++          */
++
++          if ( start > colmin ) {
++              // skip this for the first line segment
++              cury = m * x[0] + b;
++              add_fit_node( start, row, (lasty + cury) / 2 );
++              // fprintf(fit, "%.2f %.2f\n", x[0], (lasty + cury) / 2);
++          }
++
++          lasty = m * x[end-start] + b;
++          start = end;
++      }
++
++      /*
++      fclose(fit);
++      fclose(fit1);
++
++      dem = fopen("gnuplot.dat", "w");
++      for ( j = 0; j < ARRAY_SIZE_1; j++) {
++          fprintf(dem, "%.2f %.2f\n", 0.0 + ( j * col_step ), 
++                  in_data[j][row]);
++      } 
++      fclose(dem);
++      */
++
++      // NOTICE, this is for testing only.  This instance of
++        // output_nodes should be removed.  It should be called only
++        // once at the end once all the nodes have been generated.
++      // newmesh_output_nodes(&nm, "mesh.node");
++      // printf("Please hit return: "); gets(junk);
++    }
++
++    // outputmesh_output_nodes(fg_root, p);
++
++    // return fit nodes + 4 corners
++    return node_list.size() + 4;
++}
++
++
++// return the current altitude based on grid data.  We should rewrite
++// this to interpolate exact values, but for now this is good enough
++double FGArray::interpolate_altitude( double lon, double lat ) const {
++    // we expect incoming (lon,lat) to be in arcsec for now
++
++    double xlocal, ylocal, dx, dy, zA, zB, elev;
++    int x1, x2, x3, y1, y2, y3;
++    float z1, z2, z3;
++    int xindex, yindex;
++
++    /* determine if we are in the lower triangle or the upper triangle 
++       ______
++       |   /|
++       |  / |
++       | /  |
++       |/   |
++       ------
++
++       then calculate our end points
++     */
++
++    xlocal = (lon - originx) / col_step;
++    ylocal = (lat - originy) / row_step;
++
++    xindex = (int)(xlocal);
++    yindex = (int)(ylocal);
++
++    // printf("xindex = %d  yindex = %d\n", xindex, yindex);
++
++    if ( xindex + 1 == cols ) {
++      xindex--;
++    }
++
++    if ( yindex + 1 == rows ) {
++      yindex--;
++    }
++
++    if ( (xindex < 0) || (xindex + 1 >= cols) ||
++       (yindex < 0) || (yindex + 1 >= rows) ) {
++      cout << "WARNING: Attempt to interpolate value outside of array!!!" 
++           << endl;
++      return 0;
++    }
++
++    dx = xlocal - xindex;
++    dy = ylocal - yindex;
++
++    if ( dx > dy ) {
++      // lower triangle
++      // printf("  Lower triangle\n");
++
++      x1 = xindex; 
++      y1 = yindex; 
++      z1 = in_data[x1][y1];
++
++      x2 = xindex + 1; 
++      y2 = yindex; 
++      z2 = in_data[x2][y2];
++                                
++      x3 = xindex + 1; 
++      y3 = yindex + 1; 
++      z3 = in_data[x3][y3];
++
++      // printf("  dx = %.2f  dy = %.2f\n", dx, dy);
++      // printf("  (x1,y1,z1) = (%d,%d,%d)\n", x1, y1, z1);
++      // printf("  (x2,y2,z2) = (%d,%d,%d)\n", x2, y2, z2);
++      // printf("  (x3,y3,z3) = (%d,%d,%d)\n", x3, y3, z3);
++
++      zA = dx * (z2 - z1) + z1;
++      zB = dx * (z3 - z1) + z1;
++      
++      // printf("  zA = %.2f  zB = %.2f\n", zA, zB);
++
++      if ( dx > FG_EPSILON ) {
++          elev = dy * (zB - zA) / dx + zA;
++      } else {
++          elev = zA;
++      }
++    } else {
++      // upper triangle
++      // printf("  Upper triangle\n");
++
++      x1 = xindex; 
++      y1 = yindex; 
++      z1 = in_data[x1][y1];
++
++      x2 = xindex; 
++      y2 = yindex + 1; 
++      z2 = in_data[x2][y2];
++                                
++      x3 = xindex + 1; 
++      y3 = yindex + 1; 
++      z3 = in_data[x3][y3];
++
++      // printf("  dx = %.2f  dy = %.2f\n", dx, dy);
++      // printf("  (x1,y1,z1) = (%d,%d,%d)\n", x1, y1, z1);
++      // printf("  (x2,y2,z2) = (%d,%d,%d)\n", x2, y2, z2);
++      // printf("  (x3,y3,z3) = (%d,%d,%d)\n", x3, y3, z3);
++ 
++      zA = dy * (z2 - z1) + z1;
++      zB = dy * (z3 - z1) + z1;
++      
++      // printf("  zA = %.2f  zB = %.2f\n", zA, zB );
++      // printf("  xB - xA = %.2f\n", col_step * dy / row_step);
++
++      if ( dy > FG_EPSILON ) {
++          elev = dx * (zB - zA) / dy    + zA;
++      } else {
++          elev = zA;
++      }
++    }
++
++    return(elev);
++}
++
++
++#if 0
++// Write out a node file that can be used by the "triangle" program.
++// Check for an optional "index.node.ex" file in case there is a .poly
++// file to go along with this node file.  Include these nodes first
++// since they are referenced by position from the .poly file.
++void FGArray::outputmesh_output_nodes( const string& fg_root, FGBucket& p )
++{
++    double exnodes[MAX_EX_NODES][3];
++    struct stat stat_buf;
++    string dir, file;
++    char exfile[256];
++#ifdef WIN32
++    char tmp_path[256];
++#endif
++    string command;
++    FILE *fd;
++    int colmin, colmax, rowmin, rowmax;
++    int i, j, count, excount, result;
++
++    // determine dimensions
++    colmin = p.get_x() * ( (cols - 1) / 8);
++    colmax = colmin + ( (cols - 1) / 8);
++    rowmin = p.get_y() * ( (rows - 1) / 8);
++    rowmax = rowmin + ( (rows - 1) / 8);
++    cout << "  dumping region = " << colmin << "," << rowmin << " to " <<
++      colmax << "," << rowmax << "\n";
++
++    // generate the base directory
++    string base_path = p.gen_base_path();
++    cout << "  fg_root = " << fg_root << "  Base Path = " << base_path << endl;
++    dir = fg_root + "/Scenery/" + base_path;
++    cout << "  Dir = " << dir << endl;
++    
++    // stat() directory and create if needed
++    errno = 0;
++    result = stat(dir.c_str(), &stat_buf);
++    if ( result != 0 && errno == ENOENT ) {
++      cout << "  Creating directory\n";
++
++      command = "mkdir -p " + dir + "\n";
++      system( command.c_str() );
++    } else {
++      // assume directory exists
++    }
++
++    // get index and generate output file name
++    file = dir + "/" + p.gen_index_str() + ".node";
++
++    // get (optional) extra node file name (in case there is matching
++    // .poly file.
++    exfile = file + ".ex";
++
++    // load extra nodes if they exist
++    excount = 0;
++    if ( (fd = fopen(exfile, "r")) != NULL ) {
++      int junki;
++      fscanf(fd, "%d %d %d %d", &excount, &junki, &junki, &junki);
++
++      if ( excount > MAX_EX_NODES - 1 ) {
++          printf("Error, too many 'extra' nodes, increase array size\n");
++          exit(-1);
++      } else {
++          printf("    Expecting %d 'extra' nodes\n", excount);
++      }
++
++      for ( i = 1; i <= excount; i++ ) {
++          fscanf(fd, "%d %lf %lf %lf\n", &junki, 
++                 &exnodes[i][0], &exnodes[i][1], &exnodes[i][2]);
++          printf("(extra) %d %.2f %.2f %.2f\n", 
++                  i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
++      }
++      fclose(fd);
++    }
++
++    printf("Creating node file:  %s\n", file);
++    fd = fopen(file, "w");
++
++    // first count regular nodes to generate header
++    count = 0;
++    for ( j = rowmin; j <= rowmax; j++ ) {
++      for ( i = colmin; i <= colmax; i++ ) {
++          if ( out_data[i][j] > -9000.0 ) {
++              count++;
++          }
++      }
++      // printf("    count = %d\n", count);
++    }
++    fprintf(fd, "%d 2 1 0\n", count + excount);
++
++    // now write out extra node data
++    for ( i = 1; i <= excount; i++ ) {
++      fprintf(fd, "%d %.2f %.2f %.2f\n", 
++              i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
++    }
++
++    // write out actual node data
++    count = excount + 1;
++    for ( j = rowmin; j <= rowmax; j++ ) {
++      for ( i = colmin; i <= colmax; i++ ) {
++          if ( out_data[i][j] > -9000.0 ) {
++              fprintf(fd, "%d %.2f %.2f %.2f\n", 
++                      count++, 
++                      originx + (double)i * col_step, 
++                      originy + (double)j * row_step,
++                      out_data[i][j]);
++          }
++      }
++      // printf("    count = %d\n", count);
++    }
++
++    fclose(fd);
++}
++#endif
++
++
++FGArray::~FGArray( void ) {
++    // printf("class FGArray DEstructor called.\n");
++    delete [] in_data;
++    // delete [] out_data;
++}
++
++
++// $Log$
++// Revision 1.8  1999/04/05 02:15:23  curt
++// Make dem fitting more robust in cases when no dem file available.
++//
++// Revision 1.7  1999/03/27 14:05:10  curt
++// More sensible handling of the case where no dem file for this tile exists
++// (or has been generated).
++//
++// Revision 1.6  1999/03/27 05:20:13  curt
++// Handle corner nodes separately from the rest of the fitted nodes.
++// Fixed some "const" related warnings.
++//
++// Revision 1.5  1999/03/25 19:03:50  curt
++// Minor tweaks related to FGBucket usage.
++//
++// Revision 1.4  1999/03/20 20:32:51  curt
++// First mostly successful tile triangulation works.  There's plenty of tweaking
++// to do, but we are marching in the right direction.
++//
++// Revision 1.3  1999/03/17 23:48:17  curt
++// Removed forced -g compile flag.
++// Fixed a couple compiler warnings.
++//
++// Revision 1.2  1999/03/13 23:50:26  curt
++// Tweaked output formatting a bit.
++//
++// Revision 1.1  1999/03/13 18:45:02  curt
++// Initial revision. (derived from libDEM.a code.)
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2ec9e2a51a6ab128d0b5080058e90dd8386ef72a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,146 @@@
++// array.hxx -- Array management class
++//
++// Written by Curtis Olson, started March 1998.
++//
++// Copyright (C) 1998 - 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef _ARRAY_HXX
++#define _ARRAY_HXX
++
++
++#ifndef __cplusplus                                                          
++# error This library requires C++
++#endif                                   
++
++
++#include <Include/compiler.h>
++
++#include <vector>
++
++#include <Bucket/newbucket.hxx>
++#include <Math/point3d.hxx>
++#include <Misc/fgstream.hxx>
++
++#include <Main/construct_types.hxx>
++
++FG_USING_STD(vector);
++
++
++#define ARRAY_SIZE 1200
++#define ARRAY_SIZE_1 1201
++
++
++class FGArray {
++
++private:
++
++    // file pointer for input
++    // gzFile fd;
++    fg_gzifstream *in;
++
++    // coordinates (in arc seconds) of south west corner
++    double originx, originy;
++    
++    // number of columns and rows
++    int cols, rows;
++    
++    // Distance between column and row data points (in arc seconds)
++    double col_step, row_step;
++    
++    // pointers to the actual grid data allocated here
++    float (*in_data)[ARRAY_SIZE_1];
++    // float (*out_data)[ARRAY_SIZE_1];
++
++    // output nodes
++    point_list corner_list;
++    point_list node_list;
++
++public:
++
++    // Constructor
++    FGArray( void );
++    FGArray( const string& file );
++
++    // Destructor
++    ~FGArray( void );
++
++    // open an Array file (use "-" if input is coming from stdin)
++    int open ( const string& file );
++
++    // close a Array file
++    int close();
++
++    // parse a Array file
++    int parse( FGBucket& b );
++
++    // Use least squares to fit a simpler data set to dem data.
++    // Return the number of fitted nodes
++    int fit( double error );
++
++    // add a node to the output corner node list
++    void add_corner_node( int i, int j, double val );
++
++    // add a node to the output fitted node list
++    void add_fit_node( int i, int j, double val );
++
++    // return the current altitude based on grid data.  We should
++    // rewrite this to interpolate exact values, but for now this is
++    // good enough
++    double interpolate_altitude( double lon, double lat ) const;
++
++    // Informational methods
++    inline double get_originx() const { return originx; }
++    inline double get_originy() const { return originy; }
++    inline int get_cols() const { return cols; }
++    inline int get_rows() const { return rows; }
++    inline double get_col_step() const { return col_step; }
++    inline double get_row_step() const { return row_step; }
++
++    inline point_list get_corner_node_list() const { return corner_list; }
++    inline point_list get_fit_node_list() const { return node_list; }
++};
++
++
++#endif // _ARRAY_HXX
++
++
++// $Log$
++// Revision 1.6  1999/04/05 02:15:24  curt
++// Make dem fitting more robust in cases when no dem file available.
++//
++// Revision 1.5  1999/03/29 13:11:02  curt
++// Shuffled stl type names a bit.
++// Began adding support for tri-fanning (or maybe other arrangments too.)
++//
++// Revision 1.4  1999/03/27 05:20:14  curt
++// Handle corner nodes separately from the rest of the fitted nodes.
++// Fixed some "const" related warnings.
++//
++// Revision 1.3  1999/03/20 20:32:52  curt
++// First mostly successful tile triangulation works.  There's plenty of tweaking
++// to do, but we are marching in the right direction.
++//
++// Revision 1.2  1999/03/13 23:50:27  curt
++// Tweaked output formatting a bit.
++//
++// Revision 1.1  1999/03/13 18:45:02  curt
++// Initial revision. (derived from libDEM.a code.)
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1a0a4d55c933449293bdc4373e9cafa7c488c547
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,33 @@@
++#include <Bucket/newbucket.hxx>
++
++#include "array.hxx"
++
++main(int argc, char **argv) {
++    double lon, lat;
++
++    if ( argc != 2 ) {
++      cout << "Usage: " << argv[0] << " work_dir" << endl;
++      exit(-1);
++    }
++
++    string work_dir = argv[1];
++   
++    lon = -146.248360; lat = 61.133950;  // PAVD (Valdez, AK)
++    lon = -110.664244; lat = 33.352890;  // P13
++
++    FGBucket b( lon, lat );
++    string base = b.gen_base_path();
++    string path = work_dir + "/Scenery/" + base;
++
++    string arrayfile = path + "/" + b.gen_index_str() + ".dem";
++    cout << "arrayfile = " << arrayfile << endl;
++    
++    FGArray a(arrayfile);
++    a.parse( b );
++
++    lon *= 3600;
++    lat *= 3600;
++    cout << "  " << a.interpolate_altitude(lon, lat) << endl;
++
++    a.fit( 100 );
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5e830c88b35835f6d6a29c7ceb031fbaac0c0851
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,62 @@@
++#---------------------------------------------------------------------------
++# Makefile
++#
++# Written by Curtis Olson, started January 1998.
++#
++# Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++# $Id$
++# (Log is kept at end of this file)
++#---------------------------------------------------------------------------
++
++
++bin_PROGRAMS = assemtris
++
++assemtris_SOURCES = assemtris.cxx assemtris.hxx
++
++assemtris_LDADD = \
++      $(top_builddir)/Lib/Bucket/libBucket.a \
++      $(base_LIBS)
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
++
++
++#---------------------------------------------------------------------------
++# $Log$
++# Revision 1.5  1998/11/04 23:01:45  curt
++# Changes to the automake/autoconf system to reduce the number of libraries
++# that are unnecessarily linked into the various executables.
++#
++# Revision 1.4  1998/09/25 19:35:25  curt
++# Renamed assemtris.[ch] to assemtris.[ch]xx
++#
++# Revision 1.3  1998/07/30 23:49:23  curt
++# Removed libtool support.
++#
++# Revision 1.2  1998/04/14 02:25:59  curt
++# Code reorganizations.  Added a Lib/ directory for more general libraries.
++#
++# Revision 1.1  1998/04/08 22:54:57  curt
++# Adopted Gnu automake/autoconf system.
++#
++# Revision 1.2  1998/01/21 02:55:46  curt
++# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
++#
++# Revision 1.1  1998/01/15 02:45:25  curt
++# Initial revision.
++#
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1c87851e3588cf11f666704dbe3bf0bb515bbd0d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,600 @@@
++// assemtris.cxx -- reassemble the pieces produced by splittris
++//
++// Written by Curtis Olson, started January 1998.
++//
++// Copyright (C) 1997  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include <math.h>
++#include <stdio.h>
++#include <stdlib.h>   // for atoi()
++#include <string.h>
++#include <sys/stat.h> // for stat()
++#include <unistd.h>   // for stat()
++
++#include "assemtris.hxx"
++
++#include <Include/fg_constants.h>
++#include <Bucket/bucketutils.h>
++
++
++// #define OFFSET_LON 0.1
++// #define OFFSET_LAT 0.1
++
++#define OFFSET_LON 0.0
++#define OFFSET_LAT 0.0
++
++int nodecount = 0;
++int excount = 0;
++
++static double nodes[MAX_NODES][3];
++static double exnodes[MAX_NODES][3];
++
++
++fgBUCKET my_index;
++fgBUCKET ne_index, nw_index, sw_index, se_index;
++fgBUCKET north_index, south_index, east_index, west_index;
++
++
++// return the file base name ( foo/bar/file.ext = file.ext )
++void extract_file(char *in, char *base) {
++    int len, i;
++
++    len = strlen(in);
++
++    i = len - 1;
++    while ( (i >= 0) && (in[i] != '/') ) {
++      i--;
++    }
++
++    in += (i + 1);
++    strcpy(base, in);
++}
++
++
++// return the file path name ( foo/bar/file.ext = foo/bar )
++void extract_path(char *in, char *base) {
++    int len, i;
++
++    len = strlen(in);
++    strcpy(base, in);
++
++    i = len - 1;
++    while ( (i >= 0) && (in[i] != '/') ) {
++      i--;
++    }
++
++    base[i] = '\0';
++}
++
++
++// check to see if specified node is in the extra list
++int is_extra_node(double *n) {
++    int i;
++
++    for ( i = 1; i <= excount; i++ ) {
++      // we only check lon/lat in case the height got fooled with
++      // along the way
++      if ( (fabs(n[0] - exnodes[i][0]) < FG_EPSILON) &&
++           (fabs(n[1] - exnodes[i][1]) < FG_EPSILON) ) {
++          return(i);
++      }
++    }
++
++    return(0);
++}
++
++// Read all the extra nodes.  These typically define inner areas to
++// exclude from triangulations.  There will be a .poly file that
++// refers to these by position number which assumes all the extra
++// nodes come first in the generated .node file.
++void read_extra_nodes(char *exfile) {
++    FILE *fd;
++    int i, junk1, junk2, junk3;
++
++    // load extra nodes if they exist
++    excount = 0;
++    if ( (fd = fopen(exfile, "r")) != NULL ) {
++      printf("Found and 'extra' node file = %s\n", exfile);
++      fscanf(fd, "%d %d %d %d", &excount, &junk1, &junk2, &junk3);
++
++      if ( excount > MAX_NODES - 1 ) {
++          printf("Error, too many 'extra' nodes, increase array size\n");
++          exit(-1);
++      } else {
++          printf("    Expecting %d 'extra' nodes\n", excount);
++      }
++
++      for ( i = 1; i <= excount; i++ ) {
++          fscanf(fd, "%d %lf %lf %lf\n", &junk1, 
++                 &exnodes[i][0], &exnodes[i][1], &exnodes[i][2]);
++          printf("(extra) %d %.2f %.2f %.2f\n", 
++                  i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
++      }
++        fclose(fd);
++    }
++}
++
++
++// check if a file exists
++int file_exists(char *file) {
++    struct stat stat_buf;
++    int result;
++
++    printf("checking %s ... ", file);
++
++    result = stat(file, &stat_buf);
++
++    if ( result != 0 ) {
++      // stat failed, no file
++      printf("not found.\n");
++      return(0);
++    } else {
++      // stat succeeded, file exists
++      printf("exists.\n");
++      return(1);
++    }
++}
++
++
++// check to see if a shared object exists
++int shared_object_exists(char *basepath, char *ext, char *file) {
++    char scene_path[256];
++    long int index;
++
++    if ( strcmp(ext, ".sw") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&west_index, scene_path);
++      index = fgBucketGenIndex(&west_index);
++      sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&sw_index, scene_path);
++      index = fgBucketGenIndex(&sw_index);
++      sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&south_index, scene_path);
++      index = fgBucketGenIndex(&south_index);
++      sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".se") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&east_index, scene_path);
++      index = fgBucketGenIndex(&east_index);
++      sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&se_index, scene_path);
++      index = fgBucketGenIndex(&se_index);
++      sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&south_index, scene_path);
++      index = fgBucketGenIndex(&south_index);
++      sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".ne") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&east_index, scene_path);
++      index = fgBucketGenIndex(&east_index);
++      sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&ne_index, scene_path);
++      index = fgBucketGenIndex(&ne_index);
++      sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&north_index, scene_path);
++      index = fgBucketGenIndex(&north_index);
++      sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".nw") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&west_index, scene_path);
++      index = fgBucketGenIndex(&west_index);
++      sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&nw_index, scene_path);
++      index = fgBucketGenIndex(&nw_index);
++      sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&north_index, scene_path);
++      index = fgBucketGenIndex(&north_index);
++      sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".south") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.south", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&south_index, scene_path);
++      index = fgBucketGenIndex(&south_index);
++      sprintf(file, "%s/%s/%ld.1.north", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".north") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.north", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&north_index, scene_path);
++      index = fgBucketGenIndex(&north_index);
++      sprintf(file, "%s/%s/%ld.1.south", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".west") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.west", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&west_index, scene_path);
++      index = fgBucketGenIndex(&west_index);
++      sprintf(file, "%s/%s/%ld.1.east", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".east") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.east", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&east_index, scene_path);
++      index = fgBucketGenIndex(&east_index);
++      sprintf(file, "%s/%s/%ld.1.west", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".body") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.body", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    return(0);
++}
++
++
++// my custom file opening routine ... don't open if a shared edge or
++// vertex alread exists
++FILE *my_open(char *basename, char *basepath, char *ext) {
++    FILE *fp;
++    char filename[256];
++
++    // check if a shared object already exists
++    if ( shared_object_exists(basepath, ext, filename) ) {
++      // not an actual file open error, but we've already got the
++        // shared edge, so we don't want to create another one
++      fp = fopen(filename, "r");
++      printf("Opening %s\n", filename);
++      return(fp);
++    } else {
++      // open the file
++      printf("not opening\n");
++      return(NULL);
++    }
++}
++
++
++// given a file pointer, read all the gdn (geodetic nodes from it.)
++// The specified offset values (in arcsec) are used to overlap the
++// edges of the tile slightly to cover gaps induced by floating point
++// precision problems.  1 arcsec == about 100 feet so 0.01 arcsec ==
++// about 1 foot
++void read_nodes(FILE *fp, double offset_lon, double offset_lat) {
++    double n[3];
++    char line[256];
++    int ex_index;
++
++    offset_lon = offset_lat = 0.0;
++
++    while ( fgets(line, 250, fp) != NULL ) {
++      if ( strncmp(line, "gdn ", 4) == 0 ) {
++          sscanf(line, "gdn %lf %lf %lf\n", &n[0], &n[1], &n[2]);
++
++          ex_index = is_extra_node(n);
++
++          if ( ex_index == 0 ) {
++              // not an extra node
++              nodes[nodecount][0] = n[0] + offset_lon;
++              nodes[nodecount][1] = n[1] + offset_lat;
++              nodes[nodecount][2] = n[2];
++
++              // printf("read_nodes(%d) %.2f %.2f %.2f %s", nodecount, 
++              //        nodes[nodecount][0], nodes[nodecount][1], 
++              //        nodes[nodecount][2], line);
++                   
++
++              nodecount++;
++          } else {
++              // is an extra node
++              printf("found extra node %.2f %.2f %.2f\n", n[0], n[1], n[2]);
++              // preserve the DEM altitude for now
++              exnodes[ex_index][2] = n[2];
++          }
++      }
++    }
++}
++
++
++// load in nodes from the various split and shared pieces to
++// reconstruct a tile
++void build_node_list(char *basename, char *basepath) {
++    char exfile[256];
++    FILE *ne, *nw, *se, *sw, *north, *south, *east, *west, *body;
++
++    // load extra nodes if they exist
++    strcpy(exfile, basename);
++    strcat(exfile, ".node.ex");
++    read_extra_nodes(exfile);
++
++    ne = my_open(basename, basepath, ".ne");
++    read_nodes(ne, OFFSET_LON, OFFSET_LAT);
++    fclose(ne);
++
++    nw = my_open(basename, basepath, ".nw");
++    read_nodes(nw, -1.0 * OFFSET_LON, OFFSET_LAT);
++    fclose(nw);
++
++    se = my_open(basename, basepath, ".se");
++    read_nodes(se, OFFSET_LON, -1.0 * OFFSET_LAT);
++    fclose(se);
++
++    sw = my_open(basename, basepath, ".sw");
++    read_nodes(sw, -1.0 * OFFSET_LON, -1.0 * OFFSET_LAT);
++    fclose(sw);
++
++    north = my_open(basename, basepath, ".north");
++    read_nodes(north, 0.0, OFFSET_LAT);
++    fclose(north);
++
++    south = my_open(basename, basepath, ".south");
++    read_nodes(south, 0.0, -1.0 * OFFSET_LAT);
++    fclose(south);
++
++    east = my_open(basename, basepath, ".east");
++    read_nodes(east, OFFSET_LON, 0.0);
++    fclose(east);
++
++    west = my_open(basename, basepath, ".west");
++    read_nodes(west, -1.0 * OFFSET_LON, 0.0);
++    fclose(west);
++
++    body = my_open(basename, basepath, ".body");
++    read_nodes(body, 0.0, 0.0);
++    fclose(body);
++}
++
++
++// dump in WaveFront .obj format
++void dump_nodes(char *basename) {
++    char file[256];
++    FILE *fd;
++    int i;
++
++    // generate output file name
++    strcpy(file, basename);
++    // len = strlen(file);
++    // file[len-2] = '\0';
++    strcat(file, ".node");
++    
++    // dump vertices
++    printf("Creating node file:  %s\n", file);
++    printf("  writing vertices in .node format.\n");
++    fd = fopen(file, "w");
++
++    fprintf(fd, "%d 2 1 0\n", excount + nodecount);
++
++    // now write out extra node data
++    for ( i = 1; i <= excount; i++ ) {
++      fprintf(fd, "%d %.2f %.2f %.2f 0\n", 
++              i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
++    }
++
++    // now write out actual node data
++    for ( i = 0; i < nodecount; i++ ) {
++      fprintf(fd, "%d %.2f %.2f %.2f 0\n", excount + i + 1,
++             nodes[i][0], nodes[i][1], nodes[i][2]);
++    }
++
++    fclose(fd);
++}
++
++
++int main(int argc, char **argv) {
++    char basename[256], basepath[256], temp[256];
++    long int tmp_index;
++    int len;
++
++    // derive base name
++    strcpy(basename, argv[1]);
++    len = strlen(basename);
++
++    // find the base path of the file
++    extract_path(basename, basepath);
++    extract_path(basepath, basepath);
++    extract_path(basepath, basepath);
++    printf("%s\n", basepath);
++
++    // find the index of the current file
++    extract_file(basename, temp);
++    // len = strlen(temp);
++    // if ( len >= 2 ) {
++    //    temp[len-2] = '\0';
++    // }
++    tmp_index = atoi(temp);
++    printf("%ld\n", tmp_index);
++    fgBucketParseIndex(tmp_index, &my_index);
++
++    printf("bucket = %d %d %d %d\n", 
++         my_index.lon, my_index.lat, my_index.x, my_index.y);
++    // generate the indexes of the neighbors
++    fgBucketOffset(&my_index, &ne_index,  1,  1);
++    fgBucketOffset(&my_index, &nw_index, -1,  1);
++    fgBucketOffset(&my_index, &se_index,  1, -1);
++    fgBucketOffset(&my_index, &sw_index, -1, -1);
++
++    fgBucketOffset(&my_index, &north_index,  0,  1);
++    fgBucketOffset(&my_index, &south_index,  0, -1);
++    fgBucketOffset(&my_index, &east_index,  1,  0);
++    fgBucketOffset(&my_index, &west_index, -1,  0);
++
++    // printf("Corner indexes = %ld %ld %ld %ld\n", 
++    //        ne_index, nw_index, sw_index, se_index);
++    // printf("Edge indexes = %ld %ld %ld %ld\n",
++    //        north_index, south_index, east_index, west_index);
++        
++
++    // load the input data files
++    build_node_list(basename, basepath);
++
++    // dump in WaveFront .obj format
++    dump_nodes(basename);
++
++    return(0);
++}
++
++
++// $Log$
++// Revision 1.3  1998/11/02 18:25:40  curt
++// Check for __CYGWIN__ (b20) as well as __CYGWIN32__ (pre b20 compilers)
++// Other misc. tweaks.
++//
++// Revision 1.2  1998/09/25 19:38:01  curt
++// Minor tweaks so that this actually compiles.
++//
++// Revision 1.1  1998/09/25 19:35:29  curt
++// Renamed assemtris.[ch] to assemtris.[ch]xx
++//
++// Revision 1.13  1998/09/21 20:56:30  curt
++// Changes to avoid setting airport area nodes back to their original
++// elevations if they have been changed.
++//
++//
++// Revision 1.12  1998/09/09 16:24:51  curt
++// Fixed a bug in the handling of exclude files which was causing
++//   a crash by calling fclose() on an invalid file handle.
++// Removed overlapping offsets.
++//
++// Revision 1.11  1998/08/06 12:47:59  curt
++// Removed overlap in tiles as a test.
++//
++// Revision 1.10  1998/07/21 04:34:20  curt
++// Mods to handle extra nodes (i.e. preserve cutouts).
++//
++// Revision 1.9  1998/07/04 00:55:39  curt
++// typedef'd struct fgBUCKET.
++//
++// Revision 1.8  1998/06/01 17:58:19  curt
++// Added a slight border overlap to try to minimize pixel wide gaps between
++// tiles due to round off error.  This is not a perfect solution, but helps.
++//
++// Revision 1.7  1998/04/14 02:26:00  curt
++// Code reorganizations.  Added a Lib/ directory for more general libraries.
++//
++// Revision 1.6  1998/04/08 22:54:58  curt
++// Adopted Gnu automake/autoconf system.
++//
++// Revision 1.5  1998/03/03 16:00:52  curt
++// More c++ compile tweaks.
++//
++// Revision 1.4  1998/01/31 00:41:23  curt
++// Made a few changes converting floats to doubles.
++//
++// Revision 1.3  1998/01/27 18:37:00  curt
++// Lots of updates to get back in sync with changes made over in .../Src/
++//
++// Revision 1.2  1998/01/15 21:33:36  curt
++// Assembling triangles and building a new .node file with the proper shared
++// vertices now works.  Now we just have to use the shared normals and we'll
++// be all set.
++//
++// Revision 1.1  1998/01/15 02:45:26  curt
++// Initial revision.
++//
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3c96881f4c5324d5dd570d1c0f2987ed1b5540a8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,51 @@@
++// splittris.hxx -- reassemble the pieces produced by splittris
++//
++// Written by Curtis Olson, started January 1998.
++//
++// Copyright (C) 1997  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++
++#ifndef ASSEMTRIS_H
++#define ASSEMTRIS_H
++
++
++#include <stdio.h>
++#include <string.h>
++
++
++#define MAX_NODES 200000
++#define MAX_TRIS  400000
++
++
++#endif // SPLITTRIS_H
++
++
++// $Log$
++// Revision 1.2  1998/09/25 19:38:03  curt
++// Minor tweaks so that this actually compiles.
++//
++// Revision 1.1  1998/09/25 19:35:31  curt
++// Renamed assemtris.[ch] to assemtris.[ch]xx
++//
++// Revision 1.1  1998/01/15 02:45:26  curt
++// Initial revision.
++//
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b04b3501f5efd94313942eb7439457bc82f5a2f5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,13 @@@
++# The "checkoutlist" file is used to support additional version controlled
++# administrative files in $CVSROOT/CVSROOT, such as template files.
++#
++# The first entry on a line is a filename which will be checked out from
++# the corresponding RCS file in the $CVSROOT/CVSROOT directory.
++# The remainder of the line is an error message to use if the file cannot
++# be checked out.
++#
++# File format:
++#
++#     [<whitespace>]<filename><whitespace><error message><end-of-line>
++#
++# comment lines begin with '#'
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b19e7b7a63e8e90cdb49c43f02035646c4a76e0a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++# The "commitinfo" file is used to control pre-commit checks.
++# The filter on the right is invoked with the repository and a list 
++# of files to check.  A non-zero exit of the filter program will 
++# cause the commit to be aborted.
++#
++# The first entry on a line is a regular expression which is tested
++# against the directory that the change is being committed to, relative
++# to the $CVSROOT.  For the first match that is found, then the remainder
++# of the line is the name of the filter to run.
++#
++# If the repository name does not match any of the regular expressions in this
++# file, the "DEFAULT" line is used, if it is specified.
++#
++# If the name "ALL" appears as a regular expression it is always used
++# in addition to the first matching regex or "DEFAULT".
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5047bf1c5a053ce46a0adc97b1698ea27cb51d99
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++# This file describes wrappers and other binary files to CVS.
++#
++# Wrappers are the concept where directories of files are to be
++# treated as a single file.  The intended use is to wrap up a wrapper
++# into a single tar such that the tar archive can be treated as a
++# single binary file in CVS.
++#
++# To solve the problem effectively, it was also necessary to be able to
++# prevent rcsmerge from merging these files.
++#
++# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
++#
++#  wildcard   [option value][option value]...
++#
++#  where option is one of
++#  -f         from cvs filter         value: path to filter
++#  -t         to cvs filter           value: path to filter
++#  -m         update methodology      value: MERGE or COPY
++#
++#  and value is a single-quote delimited value.
++#
++# For example:
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d78886c1522b6eae3470c13da218c3d8e197cf71
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,21 @@@
++# The "editinfo" file is used to allow verification of logging
++# information.  It works best when a template (as specified in the
++# rcsinfo file) is provided for the logging procedure.  Given a
++# template with locations for, a bug-id number, a list of people who
++# reviewed the code before it can be checked in, and an external
++# process to catalog the differences that were code reviewed, the
++# following test can be applied to the code:
++#
++#   Making sure that the entered bug-id number is correct.
++#   Validating that the code that was reviewed is indeed the code being
++#       checked in (using the bug-id number or a seperate review
++#       number to identify this particular code set.).
++#
++# If any of the above test failed, then the commit would be aborted.
++#
++# Actions such as mailing a copy of the report to each reviewer are
++# better handled by an entry in the loginfo file.
++#
++# One thing that should be noted is the the ALL keyword is not
++# supported.  There can be only one entry that matches a given
++# repository.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..226e93771063fe5504eb2c55dd3bd629dd6c6e59
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,19 @@@
++# The "loginfo" file is used to control where "cvs commit" log information is
++# sent.  The first entry on a line is a regular expression which is tested
++# against the directory that the change is being made to, relative to the
++# $CVSROOT.  For the first match that is found, the remainder of the line is a
++# filter program that should expect log information on its standard input
++#
++# If the repository name does not match any of the regular expressions in the
++# first field of this file, the "DEFAULT" line is used, if it is specified.
++#
++# If the name "ALL" appears as a regular expression it is always used
++# in addition to the first matching regex or "DEFAULT".
++#
++# The filter program may use one and only one "%s" modifier (ala printf).  If
++# such a "%s" is specified in the filter program, a brief title is included
++# (as one argument, enclosed in single quotes) showing the relative directory
++# name and listing the modified file names.
++#
++# For example:
++#DEFAULT              (echo ""; who am i; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cb9e9efc94b342879a5fff24b425473fc11edd01
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,26 @@@
++# Three different line formats are valid:
++#     key     -a    aliases...
++#     key [options] directory
++#     key [options] directory files...
++#
++# Where "options" are composed of:
++#     -i prog         Run "prog" on "cvs commit" from top-level of module.
++#     -o prog         Run "prog" on "cvs checkout" of module.
++#     -e prog         Run "prog" on "cvs export" of module.
++#     -t prog         Run "prog" on "cvs rtag" of module.
++#     -u prog         Run "prog" on "cvs update" of module.
++#     -d dir          Place module in directory "dir" instead of module name.
++#     -l              Top-level directory only -- do not recurse.
++#
++# NOTE:  If you change any of the "Run" options above, you'll have to
++# release and re-checkout any working directories of these modules.
++#
++# And "directory" is a path to a directory relative to $CVSROOT.
++#
++# The "-a" option specifies an alias.  An alias is interpreted as if
++# everything on the right of the "-a" had been typed on the command line.
++#
++# You can encode a module within a module by using the special '&'
++# character to interpose another module into the current module.  This
++# can be useful for creating a module that consists of many directories
++# spread out over the entire source repository.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..34f0bc288808e56e499d0852a9bfc9a3214b02d9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,12 @@@
++# The "notify" file controls where notifications from watches set by
++# "cvs watch add" or "cvs edit" are sent.  The first entry on a line is
++# a regular expression which is tested against the directory that the
++# change is being made to, relative to the $CVSROOT.  If it matches,
++# then the remainder of the line is a filter program that should contain
++# one occurrence of %s for the user to notify, and information on its
++# standard input.
++#
++# "ALL" or "DEFAULT" can be used in place of the regular expression.
++#
++# For example:
++#ALL mail %s -s "CVS notification"
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..49e59f4d0df9b432c5b99c0b806378a77c9cd870
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,13 @@@
++# The "rcsinfo" file is used to control templates with which the editor
++# is invoked on commit and import.
++#
++# The first entry on a line is a regular expression which is tested
++# against the directory that the change is being made to, relative to the
++# $CVSROOT.  For the first match that is found, then the remainder of the
++# line is the name of the file that contains the template.
++#
++# If the repository name does not match any of the regular expressions in this
++# file, the "DEFAULT" line is used, if it is specified.
++#
++# If the name "ALL" appears as a regular expression it is always used
++# in addition to the first matching regex or "DEFAULT".
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..274a46dd5b61069f1cea62395178b09aa3120248
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,20 @@@
++# The "taginfo" file is used to control pre-tag checks.
++# The filter on the right is invoked with the following arguments:
++#
++# $1 -- tagname
++# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d
++# $3 -- repository
++# $4->  file revision [file revision ...]
++#
++# A non-zero exit of the filter program will cause the tag to be aborted.
++#
++# The first entry on a line is a regular expression which is tested
++# against the directory that the change is being committed to, relative
++# to the $CVSROOT.  For the first match that is found, then the remainder
++# of the line is the name of the filter to run.
++#
++# If the repository name does not match any of the regular expressions in this
++# file, the "DEFAULT" line is used, if it is specified.
++#
++# If the name "ALL" appears as a regular expression it is always used
++# in addition to the first matching regex or "DEFAULT".
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..87a59e28bf05add9999447c75bc32656bc0ab346
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++noinst_LIBRARIES = libClipper.a
++
++libClipper_a_SOURCES = clipper.cxx clipper.hxx
++
++bin_PROGRAMS = testclipper
++
++testclipper_SOURCES = testclipper.cxx
++
++testclipper_LDADD = $(top_builddir)/Tools/Construct/Clipper/libClipper.a \
++      $(top_builddir)/Tools/Lib/Polygon/libPolygon.a \
++      $(top_builddir)/Lib/Debug/libDebug.a \
++      $(top_builddir)/Lib/Misc/libMisc.a \
++      $(top_builddir)/Lib/zlib/libz.a \
++      -lgfc -lgpc
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a088f0ffb127c2fc2269d9a70fbc603a603c4f9d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,304 @@@
++// clipper.cxx -- top level routines to take a series of arbitrary areas and
++//                produce a tight fitting puzzle pieces that combine to make a
++//                tile
++//
++// Written by Curtis Olson, started February 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++ 
++
++
++#include <Debug/logstream.hxx>
++#include <Include/fg_constants.h>
++#include <Misc/fgstream.hxx>
++#include <Polygon/names.hxx>
++
++#include "clipper.hxx"
++
++
++// Constructor
++FGClipper::FGClipper( void ) {
++}
++
++
++// Destructor
++FGClipper::~FGClipper( void ) {
++}
++
++
++// Initialize Clipper (allocate and/or connect structures)
++bool FGClipper::init() {
++    v_list.num_vertices = 0;
++    v_list.vertex = new gpc_vertex[FG_MAX_VERTICES];;
++
++    return true;
++}
++
++
++// Load a polygon definition file
++bool FGClipper::load_polys(const string& path) {
++    string poly_name;
++    AreaType poly_type = DefaultArea;
++    int contours, count, i, j;
++    double startx, starty, x, y, lastx, lasty;
++
++    FG_LOG( FG_CLIPPER, FG_INFO, "Loading " << path << " ..." );
++
++    fg_gzifstream in( path );
++
++    if ( !in ) {
++        FG_LOG( FG_CLIPPER, FG_ALERT, "Cannot open file: " << path );
++      exit(-1);
++    }
++
++    gpc_polygon *poly = new gpc_polygon;
++    poly->num_contours = 0;
++    poly->contour = NULL;
++
++    in >> skipcomment;
++    while ( !in.eof() ) {
++      in >> poly_name;
++      cout << "poly name = " << poly_name << endl;
++      poly_type = get_area_type( poly_name );
++      cout << "poly type (int) = " << (int)poly_type << endl;
++      in >> contours;
++      cout << "num contours = " << contours << endl;
++
++      for ( i = 0; i < contours; ++i ) {
++          in >> count;
++
++          if ( count < 3 ) {
++              FG_LOG( FG_CLIPPER, FG_ALERT, 
++                      "Polygon with less than 3 data points." );
++              exit(-1);
++          }
++
++          in >> startx;
++          in >> starty;
++          v_list.vertex[0].x = startx;
++          v_list.vertex[0].y = starty;
++          FG_LOG( FG_CLIPPER, FG_BULK, "0 = " 
++                  << startx << ", " << starty );
++
++          for ( j = 1; j < count - 1; ++j ) {
++              in >> x;
++              in >> y;
++              v_list.vertex[j].x = x;
++              v_list.vertex[j].y = y;
++              FG_LOG( FG_CLIPPER, FG_BULK, j << " = " << x << ", " << y );
++          }
++          v_list.num_vertices = count - 1;
++
++          in >> lastx;
++          in >> lasty;
++
++          if ( (fabs(startx - lastx) < FG_EPSILON) 
++               && (fabs(starty - lasty) < FG_EPSILON) ) {
++              // last point same as first, discard
++          } else {
++              v_list.vertex[count - 1].x = lastx;
++              v_list.vertex[count - 1].y = lasty;
++              ++v_list.num_vertices;
++              FG_LOG( FG_CLIPPER, FG_BULK, count - 1 << " = " 
++                      << lastx << ", " << lasty );
++          }
++
++          gpc_add_contour( poly, &v_list );
++
++      }
++
++      in >> skipcomment;
++    }
++
++    int area = (int)poly_type;
++    if ( area < FG_MAX_AREA_TYPES ) {
++      polys_in.polys[area].push_back(poly);
++    } else {
++      FG_LOG( FG_CLIPPER, FG_ALERT, "Polygon type out of range = " 
++              << (int)poly_type);
++      exit(-1);
++    }
++
++    // FILE *ofp= fopen("outfile", "w");
++    // gpc_write_polygon(ofp, &polys.landuse);
++
++    return true;
++}
++
++
++// Do actually clipping work
++bool FGClipper::clip_all(const point2d& min, const point2d& max) {
++    gpc_polygon accum, result_union, tmp;
++    gpc_polygon *result_diff, *remains;
++    gpcpoly_iterator current, last;
++
++    FG_LOG( FG_CLIPPER, FG_INFO, "Running master clipper" );
++
++    accum.num_contours = 0;
++
++    cout << "  (" << min.x << "," << min.y << ") (" 
++       << max.x << "," << max.y << ")" << endl;
++
++    // set up clipping tile
++    v_list.vertex[0].x = min.x;
++    v_list.vertex[0].y = min.y;
++
++    v_list.vertex[1].x = max.x;
++    v_list.vertex[1].y = min.y;
++
++    v_list.vertex[2].x = max.x;
++    v_list.vertex[2].y = max.y;
++
++    v_list.vertex[3].x = min.x;
++    v_list.vertex[3].y = max.y;
++
++    v_list.num_vertices = 4;
++
++    polys_in.safety_base.num_contours = 0;
++    polys_in.safety_base.contour = NULL;
++    gpc_add_contour( &polys_in.safety_base, &v_list );
++
++    // process polygons in priority order
++    for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
++      // cout << "num polys of this type = " 
++      //       << polys_in.polys[i].size() << endl;
++      current = polys_in.polys[i].begin();
++      last = polys_in.polys[i].end();
++      for ( ; current != last; ++current ) {
++          FG_LOG( FG_CLIPPER, FG_DEBUG, get_area_name( (AreaType)i ) 
++                  << " = " << (*current)->contour->num_vertices );
++
++#ifdef EXTRA_SAFETY_CLIP
++          // clip to base tile
++          gpc_polygon_clip(GPC_INT, *current, &polys_in.safety_base, &tmp);
++#else
++          tmp = *current;
++#endif
++
++          // clip current polygon against previous higher priority
++          // stuff
++          result_diff = new gpc_polygon;
++          result_diff->num_contours = 0;
++          result_diff->contour = NULL;
++
++          if ( accum.num_contours == 0 ) {
++              *result_diff = tmp;
++              result_union = tmp;
++          } else {
++              // cout << "DIFF: tmp.num_contours = " << tmp.num_contours
++              //      << " accum.num_contours = " << accum.num_contours
++              //      << endl;
++              // tmp output accum
++              FILE *ofp= fopen("tmp-debug", "w");
++              gpc_write_polygon(ofp, &tmp);
++              fclose(ofp);
++
++              ofp= fopen("accum-debug", "w");
++              gpc_write_polygon(ofp, &accum);
++              fclose(ofp);
++
++              gpc_polygon_clip(GPC_DIFF, &tmp, &accum, result_diff);
++              gpc_polygon_clip(GPC_UNION, &tmp, &accum, &result_union);
++          }
++
++          /*
++          cout << "original contours = " << tmp.num_contours << endl;
++
++          for ( int j = 0; j < tmp.num_contours; j++ ) {
++              for (int k = 0;k < tmp.contour[j].num_vertices;k++ ) {
++                  cout << tmp.contour[j].vertex[k].x << ","
++                       << tmp.contour[j].vertex[k].y << endl;
++              }
++          }
++
++          cout << "clipped contours = " << result_diff->num_contours << endl;
++
++          for ( int j = 0; j < result_diff->num_contours; j++ ) {
++              for (int k = 0;k < result_diff->contour[j].num_vertices;k++ ) {
++                  cout << result_diff->contour[j].vertex[k].x << ","
++                       << result_diff->contour[j].vertex[k].y << endl;
++              }
++          }
++          */
++
++          // only add to output list if the clip left us with a polygon
++          if ( result_diff->num_contours > 0 ) {
++              polys_clipped.polys[i].push_back(result_diff);
++          }
++          accum = result_union;
++      }
++    }
++
++    // finally, what ever is left over goes to base terrain
++
++    // clip to accum against original base tile
++    remains = new gpc_polygon;
++    remains->num_contours = 0;
++    remains->contour = NULL;
++    gpc_polygon_clip(GPC_DIFF, &polys_in.safety_base, &accum, 
++                   remains);
++    if ( remains->num_contours > 0 ) {
++      polys_clipped.polys[0].push_back(remains);
++    }
++
++    // tmp output accum
++    FILE *ofp= fopen("accum", "w");
++    gpc_write_polygon(ofp, &accum);
++    fclose(ofp);
++
++    // tmp output safety_base
++    ofp= fopen("remains", "w");
++    gpc_write_polygon(ofp, remains);
++    fclose(ofp);
++
++    return true;
++}
++
++
++// $Log$
++// Revision 1.9  1999/03/31 23:46:38  curt
++// Debuggin output tweaks.
++//
++// Revision 1.8  1999/03/30 23:49:22  curt
++// Added some debugging output.
++//
++// Revision 1.7  1999/03/30 13:41:38  curt
++// Working towards better handling of multi-contoured polygons.
++//
++// Revision 1.6  1999/03/27 05:20:53  curt
++// Pass along default area explicitely to triangulator.
++//
++// Revision 1.5  1999/03/19 22:28:46  curt
++// Only add non-null polygons to output list.
++//
++// Revision 1.4  1999/03/19 00:26:18  curt
++// Fixed a clipping bug (polygons specified in wrong order).
++// Touched up a few compiler warnings.
++//
++// Revision 1.3  1999/03/17 23:48:58  curt
++// minor renaming and a bit of rearranging.
++//
++// Revision 1.2  1999/03/13 23:51:33  curt
++// Renamed main.cxx to testclipper.cxx
++// Converted clipper routines to a class FGClipper.
++//
++// Revision 1.1  1999/03/01 15:39:39  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..469691a2ae020b8eec01adcd561b2978c49cb893
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,129 @@@
++// clipper.hxx -- top level routines to take a series of arbitrary areas and
++//                produce a tight fitting puzzle pieces that combine to make a
++//                tile
++//
++// Written by Curtis Olson, started February 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++ 
++
++
++#ifndef _CLIPPER_HXX
++#define _CLIPPER_HXX
++
++
++#ifndef __cplusplus                                                          
++# error This library requires C++
++#endif                                   
++
++
++#include <Include/compiler.h>
++
++
++// include Generic Polygon Clipping Library
++//
++//    http://www.cs.man.ac.uk/aig/staff/alan/software/
++//
++extern "C" {
++#include <gpc.h>
++}
++
++#include STL_STRING
++#include <vector>
++
++FG_USING_STD(string);
++FG_USING_STD(vector);
++
++
++typedef vector < gpc_polygon * > gpcpoly_container;
++typedef gpcpoly_container::iterator gpcpoly_iterator;
++typedef gpcpoly_container::const_iterator const_gpcpoly_iterator;
++
++
++#define FG_MAX_AREA_TYPES 20
++#define EXTRA_SAFETY_CLIP
++#define FG_MAX_VERTICES 100000
++
++
++class point2d {
++public:
++    double x, y;
++};
++
++
++class FGgpcPolyList {
++public:
++    gpcpoly_container polys[FG_MAX_AREA_TYPES];
++    gpc_polygon safety_base;
++};
++
++
++class FGClipper {
++
++private:
++
++    gpc_vertex_list v_list;
++    // static gpc_polygon poly;
++    FGgpcPolyList polys_in, polys_clipped;
++
++public:
++
++    // Constructor
++    FGClipper( void );
++
++    // Destructor
++    ~FGClipper( void );
++
++    // Initialize Clipper (allocate and/or connect structures)
++    bool init();
++
++    // Load a polygon definition file
++    bool load_polys(const string& path);
++
++    // Do actually clipping work
++    bool clip_all(const point2d& min, const point2d& max);
++
++    // return output poly list
++    inline FGgpcPolyList get_polys_clipped() const { return polys_clipped; }
++};
++
++
++#endif // _CLIPPER_HXX
++
++
++// $Log$
++// Revision 1.5  1999/03/19 00:26:19  curt
++// Fixed a clipping bug (polygons specified in wrong order).
++// Touched up a few compiler warnings.
++//
++// Revision 1.4  1999/03/18 04:31:10  curt
++// Let's not pass copies of huge structures on the stack ... ye might see a
++// segfault ... :-)
++//
++// Revision 1.3  1999/03/17 23:48:59  curt
++// minor renaming and a bit of rearranging.
++//
++// Revision 1.2  1999/03/13 23:51:34  curt
++// Renamed main.cxx to testclipper.cxx
++// Converted clipper routines to a class FGClipper.
++//
++// Revision 1.1  1999/03/01 15:39:39  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2a0477b48c66e79b29c4b1bbeac91372747a6167
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,119 @@@
++// main.cxx -- sample use of the clipper lib
++//
++// Written by Curtis Olson, started February 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++ 
++
++
++#include <Debug/logstream.hxx>
++#include <Bucket/newbucket.hxx>
++
++#include "clipper.hxx"
++
++
++int main( int argc, char **argv ) {
++    point2d global_min, global_max;
++
++    fglog().setLogLevels( FG_ALL, FG_DEBUG );
++
++    global_min.x = global_min.y = 200;
++    global_max.y = global_max.x = -200;
++
++    FGClipper clipper;
++    clipper.init();
++
++    if ( argc < 2 ) {
++      FG_LOG( FG_CLIPPER, FG_ALERT, "Usage: " << argv[0] 
++              << " file1 file2 ..." );
++      exit(-1);
++    }
++
++    // process all specified polygon files
++    for ( int i = 1; i < argc; i++ ) {
++      string full_path = argv[i];
++
++      // determine bucket for this polygon
++      int pos = full_path.rfind("/");
++      string file_name = full_path.substr(pos + 1);
++      cout << "file name = " << file_name << endl;
++
++      pos = file_name.find(".");
++      string base_name = file_name.substr(0, pos);
++      cout << "base_name = " << base_name << endl;
++
++      long int index;
++      sscanf( base_name.c_str(), "%ld", &index);
++      FGBucket b(index);
++      cout << "bucket = " << b << endl;
++
++      // calculate bucket dimensions
++      point2d c, min, max;
++
++      c.x = b.get_center_lon();
++      c.y = b.get_center_lat();
++      double span = bucket_span(c.y);
++
++      if ( (c.y >= -89.0) && (c.y < 89.0) ) {
++          min.x = c.x - span / 2.0;
++          max.x = c.x + span / 2.0;
++          min.y = c.y - FG_HALF_BUCKET_SPAN;
++          max.y = c.y + FG_HALF_BUCKET_SPAN;
++      } else if ( c.y < -89.0) {
++          min.x = -90.0;
++          max.x = -89.0;
++          min.y = -180.0;
++          max.y = 180.0;
++      } else if ( c.y >= 89.0) {
++          min.x = 89.0;
++          max.x = 90.0;
++          min.y = -180.0;
++          max.y = 180.0;
++      } else {
++          FG_LOG ( FG_GENERAL, FG_ALERT, 
++                   "Out of range latitude in clip_and_write_poly() = " 
++                   << c.y );
++      }
++
++      if ( min.x < global_min.x ) global_min.x = min.x;
++      if ( min.y < global_min.y ) global_min.y = min.y;
++      if ( max.x > global_max.x ) global_max.x = max.x;
++      if ( max.y > global_max.y ) global_max.y = max.y;
++
++      // finally, load the polygon(s) from this file
++      clipper.load_polys( full_path );
++    }
++
++    // do the clipping
++    clipper.clip_all(global_min, global_max);
++
++    FG_LOG( FG_CLIPPER, FG_INFO, "finished main" );
++
++    return 0;
++}
++
++// $Log$
++// Revision 1.1  1999/03/13 23:51:36  curt
++// Renamed main.cxx to testclipper.cxx
++// Converted clipper routines to a class FGClipper.
++//
++// Revision 1.1  1999/03/01 15:39:39  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c8c64020252cca74e7b128d24fee692723276b2d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,9 @@@
++noinst_LIBRARIES = libCombine.a
++
++libCombine_a_SOURCES = genfans.cxx genfans.hxx
++
++INCLUDES += \
++      -I$(top_builddir) \
++      -I$(top_builddir)/Lib \
++      -I$(top_builddir)/Tools/Lib \
++      -I$(top_builddir)/Tools/Construct
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..856a3d79cd9541b6ab1674fc0cbd46ed057a625e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,266 @@@
++// genfans.cxx -- Combine individual triangles into more optimal fans.
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include "genfans.hxx"
++
++
++// make sure the list is expanded at least to hold "n" and then push
++// "i" onto the back of the "n" list.
++void FGGenFans::add_and_expand( reverse_list& by_node, int n, int i ) {
++    int_list empty;
++
++    int size = (int)by_node.size();
++    if ( size > n ) {
++      // ok
++    } else {
++      // cout << "capacity = " << by_node.capacity() << endl;
++      // cout << "size = " << size << "  n = " << n
++      //      << " need to push = " << n - size + 1 << endl;
++      for ( int i = 0; i < n - size + 1; ++i ) {
++          by_node.push_back(empty);
++      }
++    }
++
++    by_node[n].push_back(i);
++}
++
++
++// given an input triangle, shuffle nodes so that "center" is the
++// first node, but maintain winding order.
++static FGTriEle canonify( const FGTriEle& t, int center ) {
++    if ( t.get_n1() == center ) {
++      // already ok
++      return t;
++    } else if ( t.get_n2() == center ) {
++      return FGTriEle( t.get_n2(), t.get_n3(), t.get_n1(), 0.0 );
++    } else if ( t.get_n3() == center ) {
++      return FGTriEle( t.get_n3(), t.get_n1(), t.get_n2(), 0.0 );
++    } else {
++      cout << "ERROR, index doesn't refer to this triangle!!!" << endl;
++      exit(-1);
++    }
++}
++
++// returns a list of triangle indices
++static int_list make_best_fan( const triele_list& master_tris, 
++                             const int center, const int_list& local_tris )
++{
++    int_list best_result;
++
++    // try starting with each of local_tris to find the best fan
++    // arrangement
++    for ( int start = 0; start < (int)local_tris.size(); ++start ) {
++      // cout << "trying with first triangle = " << local_tris[start] << endl;
++
++      int_list tmp_result;
++      tmp_result.clear();
++
++      FGTriEle current_tri;
++      FGTriEle test;
++      current_tri = canonify( master_tris[local_tris[start]], center );
++      tmp_result.push_back( local_tris[start] );
++
++      // follow the ring
++      int next = -1;
++      bool matches = true;
++      while ( (next != start) && matches ) {
++          // find next triangle in ring
++          matches = false;
++          for ( int i = 0; i < (int)local_tris.size(); ++i ) {
++              test = canonify( master_tris[local_tris[i]], center );
++              if ( current_tri.get_n3() == test.get_n2() ) {
++                  if ( i != start ) {
++                      // cout << " next triangle = " << local_tris[i] << endl;
++                      current_tri = test;
++                      tmp_result.push_back( local_tris[i] );
++                      matches = true;
++                      next = i;
++                      break;
++                  }
++              }
++          }
++      }
++
++      if ( tmp_result.size() == local_tris.size() ) {
++          // we found a complete usage, no need to go on
++          // cout << "we found a complete usage, no need to go on" << endl;
++          best_result = tmp_result;
++          break;
++      } else if ( tmp_result.size() > best_result.size() ) {
++          // we found a better way to fan
++          // cout << "we found a better fan arrangement" << endl;
++          best_result = tmp_result;
++      }
++    }
++
++    return best_result;
++}
++
++
++static bool in_fan(int index, const int_list& fan ) {
++    const_int_list_iterator current = fan.begin();
++    const_int_list_iterator last = fan.end();
++
++    for ( ; current != last; ++current ) {
++      if ( index == *current ) {
++          return true;
++      }
++    }
++
++    return false;
++}
++
++
++// recursive build fans from triangle list
++fan_list FGGenFans::greedy_build( triele_list tris ) {
++    cout << "starting greedy build of fans" << endl;
++
++    fans.clear();
++
++    while ( ! tris.empty() ) {
++      // cout << "building reverse_list" << endl;
++      reverse_list by_node;
++      by_node.clear();
++
++      // traverse the triangle list and for each node, build a list of
++      // triangles that attach to it.
++
++      for ( int i = 0; i < (int)tris.size(); ++i ) {
++          int n1 = tris[i].get_n1();
++          int n2 = tris[i].get_n2();
++          int n3 = tris[i].get_n3();
++
++          add_and_expand( by_node, n1, i );
++          add_and_expand( by_node, n2, i );
++          add_and_expand( by_node, n3, i );
++      }
++
++      // find the node in the tris list that attaches to the most
++      // triangles
++
++      // cout << "find most connected node" << endl;
++
++      int_list biggest_group;
++      reverse_list_iterator r_current = by_node.begin();
++      reverse_list_iterator r_last = by_node.end();
++      int index = 0;
++      int counter = 0;
++      for ( ; r_current != r_last; ++r_current ) {
++          if ( r_current->size() > biggest_group.size() ) {
++              biggest_group = *r_current;
++              index = counter;
++          }
++          ++counter;
++      }
++      // cout << "triangle pool = " << tris.size() << endl;
++      // cout << "biggest_group = " << biggest_group.size() << endl;
++      // cout << "center node = " << index << endl;
++
++      // make the best fan we can out of this group
++      // cout << "before make_best_fan()" << endl;
++      int_list best_fan = make_best_fan( tris, index, biggest_group );
++      // cout << "after make_best_fan()" << endl;
++
++      // generate point form of best_fan
++      int_list node_list;
++      node_list.clear();
++
++      int_list_iterator i_start = best_fan.begin();
++      int_list_iterator i_current = i_start;
++      int_list_iterator i_last = best_fan.end();
++      for ( ; i_current != i_last; ++i_current ) {
++          FGTriEle t = canonify( tris[*i_current], index );
++          if ( i_start == i_current ) {
++              node_list.push_back( t.get_n1() );
++              node_list.push_back( t.get_n2() );
++          }
++          node_list.push_back( t.get_n3() );
++      }
++      // cout << "best list size = " << node_list.size() << endl;
++
++      // add this fan to the fan list
++      fans.push_back( node_list );
++
++      // delete the triangles in best_fan out of tris and repeat
++      triele_list_iterator t_current = tris.begin();
++      triele_list_iterator t_last = tris.end();
++      counter = 0;
++      while ( t_current != t_last ) {
++          if ( in_fan(counter, best_fan) ) {
++              // cout << "erasing " 
++              //      << t_current->get_n1() << ","
++              //      << t_current->get_n2() << ","
++              //      << t_current->get_n3()
++              //      << " from master tri pool"
++              //      << endl;
++              tris.erase( t_current );
++          } else {
++              ++t_current;
++          }
++          ++counter;
++      }
++    }
++
++    cout << "end of greedy build of fans" << endl;
++    cout << "average fan size = " << ave_size() << endl;
++
++    return fans;
++}
++
++
++// report average fan size
++double FGGenFans::ave_size() {
++    double sum = 0.0;
++
++    fan_list_iterator current = fans.begin();
++    fan_list_iterator last = fans.end();
++    for ( ; current != last; ++current ) {
++      sum += current->size();
++    }
++
++    return sum / (double)fans.size();
++}
++
++
++// $Log$
++// Revision 1.6  1999/04/05 02:16:02  curt
++// Fixed a compiler warning.
++//
++// Revision 1.5  1999/03/31 23:46:49  curt
++// Debugging output tweaks.
++//
++// Revision 1.4  1999/03/31 13:26:39  curt
++// Debugging output tweeaks.
++//
++// Revision 1.3  1999/03/31 05:35:04  curt
++// Fixed bug in genfans (deleting the wrong triangles from the available pool.)
++//
++// Revision 1.2  1999/03/30 23:50:15  curt
++// Fannifier is clearly bugging ... working on debugging it.  I suspect there
++// is a problem related to deleting triangles from the triangle pool as they
++// are combined into fans.
++//
++// Revision 1.1  1999/03/29 13:08:35  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..55af05d70e70de400b29894f5bdb209373716459
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,85 @@@
++// genfans.hxx -- Combine individual triangles into more optimal fans.
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef _GENFANS_HXX
++#define _GENFANS_HXX
++
++
++#ifndef __cplusplus                                                          
++# error This library requires C++
++#endif                                   
++
++
++#include <Include/compiler.h>
++
++#include <vector>
++
++#include <Main/construct_types.hxx>
++#include <Triangulate/trieles.hxx>
++
++FG_USING_STD(vector);
++
++
++typedef vector < int_list > fan_list;
++typedef fan_list::iterator fan_list_iterator;
++typedef fan_list::const_iterator const_fan_list_iterator;
++
++typedef vector < int_list > reverse_list;
++typedef reverse_list::iterator reverse_list_iterator;
++typedef reverse_list::const_iterator const_reverse_list_iterator;
++
++
++
++class FGGenFans {
++
++private:
++
++    fan_list fans;
++
++    // make sure the list is expanded at least to hold "n" and then
++    // push "i" onto the back of the "n" list.
++    void add_and_expand( reverse_list& by_node, int n, int i );
++
++public:
++
++    // Constructor && Destructor
++    inline FGGenFans() { }
++    inline ~FGGenFans() { }
++
++    // recursive build fans from triangle list
++    // fan_list greedy_build( triele_list tris );
++    fan_list greedy_build( triele_list tris );
++
++    // report average fan size
++    double ave_size();
++};
++
++
++#endif // _GENFANS_HXX
++
++
++// $Log$
++// Revision 1.1  1999/03/29 13:08:35  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f19226325bb1aac24f05d36d36f737ef8be5b32d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++SUBDIRS = \
++      Array \
++      Clipper \
++      Combine \
++      GenOutput \
++      Triangulate \
++      Main
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..91bfd90d6cfc45eddb51b3b2b24e853ef3b4a476
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++noinst_LIBRARIES = libDEM.a
++
++libDEM_a_SOURCES = dem.cxx dem.hxx
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
++
++# We can't build this with "-O2" (optimization) since this causes a seg fault
++# I haven't found a way to strip this out of the CXXFLAGS, so I'm just
++# setting it to "-g"
++# CXXFLAGS = -g
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e4661a3c70b7896816700732797e08c243a752da
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,977 @@@
++// dem.cxx -- DEM management class
++//
++// Written by Curtis Olson, started March 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifdef HAVE_CONFIG_H
++#  include <config.h>
++#endif
++
++#include <Include/compiler.h>
++
++#include <ctype.h>    // isspace()
++#include <stdlib.h>   // atoi()
++#include <math.h>     // rint()
++#include <stdio.h>
++#include <string.h>
++
++#ifdef HAVE_SYS_STAT_H
++#  include <sys/stat.h> // stat()
++#endif
++
++#ifdef FG_HAVE_STD_INCLUDES
++#  include <cerrno>
++#else
++#  include <errno.h>
++#endif
++
++#ifdef HAVE_UNISTD_H
++# include <unistd.h>   // stat()
++#endif
++
++#include <Misc/fgstream.hxx>
++#include <Misc/strutils.hxx>
++#include <Include/fg_constants.h>
++
++#include "dem.hxx"
++
++
++#define MAX_EX_NODES 10000
++
++#if 0
++#ifdef WIN32
++# ifdef __BORLANDC__
++#  include <dir.h>
++#  define MKDIR(a) mkdir(a)
++# else
++#  define MKDIR(a) mkdir(a,S_IRWXU)  // I am just guessing at this flag (NHV)
++# endif // __BORLANDC__
++#endif // WIN32
++#endif //0
++
++
++FGDem::FGDem( void ) {
++    // cout << "class FGDem CONstructor called." << endl;
++    dem_data = new float[DEM_SIZE_1][DEM_SIZE_1];
++    output_data = new float[DEM_SIZE_1][DEM_SIZE_1];
++}
++
++
++FGDem::FGDem( const string &file ) {
++    // cout << "class FGDem CONstructor called." << endl;
++    dem_data = new float[DEM_SIZE_1][DEM_SIZE_1];
++    output_data = new float[DEM_SIZE_1][DEM_SIZE_1];
++
++    FGDem::open(file);
++}
++
++
++// open a DEM file
++int
++FGDem::open ( const string& file ) {
++    // open input file (or read from stdin)
++    if ( file ==  "-" ) {
++      printf("Loading DEM data file: stdin\n");
++      // fd = stdin;
++      // fd = gzdopen(STDIN_FILENO, "r");
++      printf("Not yet ported ...\n");
++      return 0;
++    } else {
++      in = new fg_gzifstream( file );
++      if ( !(*in) ) {
++          cout << "Cannot open " << file << endl;
++          return 0;
++      }
++      cout << "Loading DEM data file: " << file << endl;
++    }
++
++    return 1;
++}
++
++
++// close a DEM file
++int
++FGDem::close () {
++    // the fg_gzifstream doesn't seem to have a close()
++
++    delete in;
++
++    return 1;
++}
++
++
++// return next token from input stream
++string
++FGDem::next_token() {
++    string token;
++
++    *in >> token;
++
++    // cout << "    returning " + token + "\n";
++
++    return token;
++}
++
++
++// return next integer from input stream
++int
++FGDem::next_int() {
++    int result;
++    
++    *in >> result;
++
++    return result;
++}
++
++
++// return next double from input stream
++double
++FGDem::next_double() {
++    double result;
++
++    *in >> result;
++
++    return result;
++}
++
++
++// return next exponential num from input stream
++double
++FGDem::next_exp() {
++    string token;
++
++    token = next_token();
++
++    const char* p = token.c_str();
++    char buf[64];
++    char* bp = buf;
++    
++    for ( ; *p != 0; ++p )
++    {
++      if ( *p == 'D' )
++          *bp++ = 'E';
++      else
++          *bp++ = *p;
++    }
++    *bp = 0;
++    return ::atof( buf );
++}
++
++
++// read and parse DEM "A" record
++int
++FGDem::read_a_record() {
++    int i, inum;
++    double dnum;
++    string name, token;
++    char c;
++
++    // get the name field (144 characters)
++    for ( i = 0; i < 144; i++ ) {
++      in->get(c);
++      name += c;
++    }
++  
++    // clean off the trailing whitespace
++    name = trim(name);
++    cout << "    Quad name field: " << name << endl;
++
++    // DEM level code, 3 reflects processing by DMA
++    inum = next_int();
++    cout << "    DEM level code = " << inum << "\n";
++
++    if ( inum > 3 ) {
++      return 0;
++    }
++
++    // Pattern code, 1 indicates a regular elevation pattern
++    inum = next_int();
++    cout << "    Pattern code = " << inum << "\n";
++
++    // Planimetric reference system code, 0 indicates geographic
++    // coordinate system.
++    inum = next_int();
++    cout << "    Planimetric reference code = " << inum << "\n";
++
++    // Zone code
++    inum = next_int();
++    cout << "    Zone code = " << inum << "\n";
++
++    // Map projection parameters (ignored)
++    for ( i = 0; i < 15; i++ ) {
++      dnum = next_exp();
++      // printf("%d: %f\n",i,dnum);
++    }
++
++    // Units code, 3 represents arc-seconds as the unit of measure for
++    // ground planimetric coordinates throughout the file.
++    inum = next_int();
++    if ( inum != 3 ) {
++      cout << "    Unknown (X,Y) units code = " << inum << "!\n";
++      exit(-1);
++    }
++
++    // Units code; 2 represents meters as the unit of measure for
++    // elevation coordinates throughout the file.
++    inum = next_int();
++    if ( inum != 2 ) {
++      cout << "    Unknown (Z) units code = " << inum << "!\n";
++      exit(-1);
++    }
++
++    // Number (n) of sides in the polygon which defines the coverage of
++    // the DEM file (usually equal to 4).
++    inum = next_int();
++    if ( inum != 4 ) {
++      cout << "    Unknown polygon dimension = " << inum << "!\n";
++      exit(-1);
++    }
++
++    // Ground coordinates of bounding box in arc-seconds
++    dem_x1 = originx = next_exp();
++    dem_y1 = originy = next_exp();
++    cout << "    Origin = (" << originx << "," << originy << ")\n";
++
++    dem_x2 = next_exp();
++    dem_y2 = next_exp();
++
++    dem_x3 = next_exp();
++    dem_y3 = next_exp();
++
++    dem_x4 = next_exp();
++    dem_y4 = next_exp();
++
++    // Minimum/maximum elevations in meters
++    dem_z1 = next_exp();
++    dem_z2 = next_exp();
++    cout << "    Elevation range " << dem_z1 << " to " << dem_z2 << "\n";
++
++    // Counterclockwise angle from the primary axis of ground
++    // planimetric referenced to the primary axis of the DEM local
++    // reference system.
++    token = next_token();
++
++    // Accuracy code; 0 indicates that a record of accuracy does not
++    // exist and that no record type C will follow.
++
++    // DEM spacial resolution.  Usually (3,3,1) (3,6,1) or (3,9,1)
++    // depending on latitude
++
++    // I will eventually have to do something with this for data at
++    // higher latitudes */
++    token = next_token();
++    cout << "    accuracy & spacial resolution string = " << token << endl;
++    i = token.length();
++    cout << "    length = " << i << "\n";
++
++    inum = atoi( token.substr( 0, i - 36 ) );
++    row_step = atof( token.substr( i - 24, 12 ) );
++    col_step = atof( token.substr( i - 36, 12 ) );
++    cout << "    Accuracy code = " << inum << "\n";
++    cout << "    column step = " << col_step << 
++      "  row step = " << row_step << "\n";
++
++    // dimension of arrays to follow (1)
++    token = next_token();
++
++    // number of profiles
++    dem_num_profiles = cols = next_int();
++    cout << "    Expecting " << dem_num_profiles << " profiles\n";
++
++    return 1;
++}
++
++
++// read and parse DEM "B" record
++void
++FGDem::read_b_record( ) {
++    string token;
++    int i;
++
++    // row / column id of this profile
++    prof_row = next_int();
++    prof_col = next_int();
++    // printf("col id = %d  row id = %d\n", prof_col, prof_row);
++
++    // Number of columns and rows (elevations) in this profile
++    prof_num_rows = rows = next_int();
++    prof_num_cols = next_int();
++    // printf("    profile num rows = %d\n", prof_num_rows);
++
++    // Ground planimetric coordinates (arc-seconds) of the first
++    // elevation in the profile
++    prof_x1 = next_exp();
++    prof_y1 = next_exp();
++    // printf("    Starting at %.2f %.2f\n", prof_x1, prof_y1);
++
++    // Elevation of local datum for the profile.  Always zero for
++    // 1-degree DEM, the reference is mean sea level.
++    token = next_token();
++
++    // Minimum and maximum elevations for the profile.
++    token = next_token();
++    token = next_token();
++
++    // One (usually) dimensional array (prof_num_cols,1) of elevations
++    for ( i = 0; i < prof_num_rows; i++ ) {
++      prof_data = next_int();
++      dem_data[cur_col][i] = (float)prof_data;
++    }
++}
++
++
++// parse dem file
++int
++FGDem::parse( ) {
++    int i;
++
++    cur_col = 0;
++
++    if ( !read_a_record() ) {
++      return(0);
++    }
++
++    for ( i = 0; i < dem_num_profiles; i++ ) {
++      // printf("Ready to read next b record\n");
++      read_b_record();
++      cur_col++;
++
++      if ( cur_col % 100 == 0 ) {
++          cout << "    loaded " << cur_col << " profiles of data\n";
++      }
++    }
++
++    cout << "    Done parsing\n";
++
++    return 1;
++}
++
++
++// write out the area of data covered by the specified bucket.  Data
++// is written out column by column starting at the lower left hand
++// corner.
++int
++FGDem::write_area( const string& root, FGBucket& b, bool compress ) {
++    // calculate some boundaries
++    double min_x = ( b.get_center_lon() - 0.5 * b.get_width() ) * 3600.0;
++    double max_x = ( b.get_center_lon() + 0.5 * b.get_width() ) * 3600.0;
++
++    double min_y = ( b.get_center_lat() - 0.5 * b.get_height() ) * 3600.0;
++    double max_y = ( b.get_center_lat() + 0.5 * b.get_height() ) * 3600.0;
++
++    cout << b << endl;
++    cout << "width = " << b.get_width() << " height = " << b.get_height() 
++       << endl;
++
++    int start_x = (int)((min_x - originx) / col_step);
++    int span_x = (int)(b.get_width() * 3600.0 / col_step);
++
++    int start_y = (int)((min_y - originy) / row_step);
++    int span_y = (int)(b.get_height() * 3600.0 / row_step);
++
++    cout << "start_x = " << start_x << "  span_x = " << span_x << endl;
++    cout << "start_y = " << start_y << "  span_y = " << span_y << endl;
++
++    // Do a simple sanity checking.  But, please, please be nice to
++    // this write_area() routine and feed it buckets that coincide
++    // well with the underlying grid structure and spacing.
++
++    if ( ( min_x < originx )
++       || ( max_x > originx + cols * col_step )
++       || ( min_y < originy )
++       || ( max_y > originy + rows * row_step ) ) {
++      cout << "  ERROR: bucket at least partially outside DEM data range!" <<
++          endl;
++      return 0;
++    }
++
++    // generate output file name
++    string base = b.gen_base_path();
++    string path = root + "/Scenery/" + base;
++    string command = "mkdir -p " + path;
++    system( command.c_str() );
++
++    string demfile = path + "/" + b.gen_index_str() + ".dem";
++    cout << "demfile = " << demfile << endl;
++
++    // write the file
++    FILE *fp;
++    if ( (fp = fopen(demfile.c_str(), "w")) == NULL ) {
++      cout << "cannot open " << demfile << " for writing!" << endl;
++      exit(-1);
++    }
++
++    fprintf( fp, "%d %d\n", (int)min_x, (int)min_y );
++    fprintf( fp, "%d %d %d %d\n", span_x + 1, (int)col_step, 
++           span_y + 1, (int)row_step );
++    for ( int i = start_x; i <= start_x + span_x; ++i ) {
++      for ( int j = start_y; j <= start_y + span_y; ++j ) {
++          fprintf( fp, "%d ", (int)dem_data[i][j] );
++      }
++      fprintf( fp, "\n" );
++    }
++    fclose(fp);
++
++    if ( compress ) {
++      string command = "gzip --best -f " + demfile;
++      system( command.c_str() );
++    }
++
++    return 1;
++}
++
++
++#if 0
++
++// return the current altitude based on grid data.  We should rewrite
++// this to interpolate exact values, but for now this is good enough
++double FGDem::interpolate_altitude( double lon, double lat ) {
++    // we expect incoming (lon,lat) to be in arcsec for now
++
++    double xlocal, ylocal, dx, dy, zA, zB, elev;
++    int x1, x2, x3, y1, y2, y3;
++    float z1, z2, z3;
++    int xindex, yindex;
++
++    /* determine if we are in the lower triangle or the upper triangle 
++       ______
++       |   /|
++       |  / |
++       | /  |
++       |/   |
++       ------
++
++       then calculate our end points
++     */
++
++    xlocal = (lon - originx) / col_step;
++    ylocal = (lat - originy) / row_step;
++
++    xindex = (int)(xlocal);
++    yindex = (int)(ylocal);
++
++    // printf("xindex = %d  yindex = %d\n", xindex, yindex);
++
++    if ( xindex + 1 == cols ) {
++      xindex--;
++    }
++
++    if ( yindex + 1 == rows ) {
++      yindex--;
++    }
++
++    if ( (xindex < 0) || (xindex + 1 >= cols) ||
++       (yindex < 0) || (yindex + 1 >= rows) ) {
++      return(-9999);
++    }
++
++    dx = xlocal - xindex;
++    dy = ylocal - yindex;
++
++    if ( dx > dy ) {
++      // lower triangle
++      // printf("  Lower triangle\n");
++
++      x1 = xindex; 
++      y1 = yindex; 
++      z1 = dem_data[x1][y1];
++
++      x2 = xindex + 1; 
++      y2 = yindex; 
++      z2 = dem_data[x2][y2];
++                                
++      x3 = xindex + 1; 
++      y3 = yindex + 1; 
++      z3 = dem_data[x3][y3];
++
++      // printf("  dx = %.2f  dy = %.2f\n", dx, dy);
++      // printf("  (x1,y1,z1) = (%d,%d,%d)\n", x1, y1, z1);
++      // printf("  (x2,y2,z2) = (%d,%d,%d)\n", x2, y2, z2);
++      // printf("  (x3,y3,z3) = (%d,%d,%d)\n", x3, y3, z3);
++
++      zA = dx * (z2 - z1) + z1;
++      zB = dx * (z3 - z1) + z1;
++      
++      // printf("  zA = %.2f  zB = %.2f\n", zA, zB);
++
++      if ( dx > FG_EPSILON ) {
++          elev = dy * (zB - zA) / dx + zA;
++      } else {
++          elev = zA;
++      }
++    } else {
++      // upper triangle
++      // printf("  Upper triangle\n");
++
++      x1 = xindex; 
++      y1 = yindex; 
++      z1 = dem_data[x1][y1];
++
++      x2 = xindex; 
++      y2 = yindex + 1; 
++      z2 = dem_data[x2][y2];
++                                
++      x3 = xindex + 1; 
++      y3 = yindex + 1; 
++      z3 = dem_data[x3][y3];
++
++      // printf("  dx = %.2f  dy = %.2f\n", dx, dy);
++      // printf("  (x1,y1,z1) = (%d,%d,%d)\n", x1, y1, z1);
++      // printf("  (x2,y2,z2) = (%d,%d,%d)\n", x2, y2, z2);
++      // printf("  (x3,y3,z3) = (%d,%d,%d)\n", x3, y3, z3);
++ 
++      zA = dy * (z2 - z1) + z1;
++      zB = dy * (z3 - z1) + z1;
++      
++      // printf("  zA = %.2f  zB = %.2f\n", zA, zB );
++      // printf("  xB - xA = %.2f\n", col_step * dy / row_step);
++
++      if ( dy > FG_EPSILON ) {
++          elev = dx * (zB - zA) / dy    + zA;
++      } else {
++          elev = zA;
++      }
++    }
++
++    return(elev);
++}
++
++
++// Use least squares to fit a simpler data set to dem data
++void FGDem::fit( double error, FGBucket& p ) {
++    double x[DEM_SIZE_1], y[DEM_SIZE_1];
++    double m, b, ave_error, max_error;
++    double cury, lasty;
++    int n, row, start, end;
++    int colmin, colmax, rowmin, rowmax;
++    bool good_fit;
++    // FILE *dem, *fit, *fit1;
++
++    printf("Initializing output mesh structure\n");
++    outputmesh_init();
++
++    // determine dimensions
++    colmin = p.get_x() * ( (cols - 1) / 8);
++    colmax = colmin + ( (cols - 1) / 8);
++    rowmin = p.get_y() * ( (rows - 1) / 8);
++    rowmax = rowmin + ( (rows - 1) / 8);
++    printf("Fitting region = %d,%d to %d,%d\n", colmin, rowmin, colmax, rowmax);
++    
++    // include the corners explicitly
++    outputmesh_set_pt(colmin, rowmin, dem_data[colmin][rowmin]);
++    outputmesh_set_pt(colmin, rowmax, dem_data[colmin][rowmax]);
++    outputmesh_set_pt(colmax, rowmax, dem_data[colmax][rowmax]);
++    outputmesh_set_pt(colmax, rowmin, dem_data[colmax][rowmin]);
++
++    printf("Beginning best fit procedure\n");
++
++    for ( row = rowmin; row <= rowmax; row++ ) {
++      // fit  = fopen("fit.dat",  "w");
++      // fit1 = fopen("fit1.dat", "w");
++
++      start = colmin;
++
++      // printf("    fitting row = %d\n", row);
++
++      while ( start < colmax ) {
++          end = start + 1;
++          good_fit = true;
++
++          x[(end - start) - 1] = 0.0 + ( start * col_step );
++          y[(end - start) - 1] = dem_data[start][row];
++
++          while ( (end <= colmax) && good_fit ) {
++              n = (end - start) + 1;
++              // printf("Least square of first %d points\n", n);
++              x[end - start] = 0.0 + ( end * col_step );
++              y[end - start] = dem_data[end][row];
++              least_squares(x, y, n, &m, &b);
++              ave_error = least_squares_error(x, y, n, m, b);
++              max_error = least_squares_max_error(x, y, n, m, b);
++
++              /*
++              printf("%d - %d  ave error = %.2f  max error = %.2f  y = %.2f*x + %.2f\n", 
++              start, end, ave_error, max_error, m, b);
++              
++              f = fopen("gnuplot.dat", "w");
++              for ( j = 0; j <= end; j++) {
++                  fprintf(f, "%.2f %.2f\n", 0.0 + ( j * col_step ), 
++                          dem_data[row][j]);
++              }
++              for ( j = start; j <= end; j++) {
++                  fprintf(f, "%.2f %.2f\n", 0.0 + ( j * col_step ), 
++                          dem_data[row][j]);
++              }
++              fclose(f);
++
++              printf("Please hit return: "); gets(junk);
++              */
++
++              if ( max_error > error ) {
++                  good_fit = false;
++              }
++              
++              end++;
++          }
++
++          if ( !good_fit ) {
++              // error exceeded the threshold, back up
++              end -= 2;  // back "end" up to the last good enough fit
++              n--;       // back "n" up appropriately too
++          } else {
++              // we popped out of the above loop while still within
++              // the error threshold, so we must be at the end of
++              // the data set
++              end--;
++          }
++          
++          least_squares(x, y, n, &m, &b);
++          ave_error = least_squares_error(x, y, n, m, b);
++          max_error = least_squares_max_error(x, y, n, m, b);
++
++          /*
++          printf("\n");
++          printf("%d - %d  ave error = %.2f  max error = %.2f  y = %.2f*x + %.2f\n", 
++                 start, end, ave_error, max_error, m, b);
++          printf("\n");
++
++          fprintf(fit1, "%.2f %.2f\n", x[0], m * x[0] + b);
++          fprintf(fit1, "%.2f %.2f\n", x[end-start], m * x[end-start] + b);
++          */
++
++          if ( start > colmin ) {
++              // skip this for the first line segment
++              cury = m * x[0] + b;
++              outputmesh_set_pt(start, row, (lasty + cury) / 2);
++              // fprintf(fit, "%.2f %.2f\n", x[0], (lasty + cury) / 2);
++          }
++
++          lasty = m * x[end-start] + b;
++          start = end;
++      }
++
++      /*
++      fclose(fit);
++      fclose(fit1);
++
++      dem = fopen("gnuplot.dat", "w");
++      for ( j = 0; j < DEM_SIZE_1; j++) {
++          fprintf(dem, "%.2f %.2f\n", 0.0 + ( j * col_step ), 
++                  dem_data[j][row]);
++      } 
++      fclose(dem);
++      */
++
++      // NOTICE, this is for testing only.  This instance of
++        // output_nodes should be removed.  It should be called only
++        // once at the end once all the nodes have been generated.
++      // newmesh_output_nodes(&nm, "mesh.node");
++      // printf("Please hit return: "); gets(junk);
++    }
++
++    // outputmesh_output_nodes(fg_root, p);
++}
++
++
++// Initialize output mesh structure
++void FGDem::outputmesh_init( void ) {
++    int i, j;
++    
++    for ( j = 0; j < DEM_SIZE_1; j++ ) {
++      for ( i = 0; i < DEM_SIZE_1; i++ ) {
++          output_data[i][j] = -9999.0;
++      }
++    }
++}
++
++
++// Get the value of a mesh node
++double FGDem::outputmesh_get_pt( int i, int j ) {
++    return ( output_data[i][j] );
++}
++
++
++// Set the value of a mesh node
++void FGDem::outputmesh_set_pt( int i, int j, double value ) {
++    // printf("Setting data[%d][%d] = %.2f\n", i, j, value);
++   output_data[i][j] = value;
++}
++
++
++// Write out a node file that can be used by the "triangle" program.
++// Check for an optional "index.node.ex" file in case there is a .poly
++// file to go along with this node file.  Include these nodes first
++// since they are referenced by position from the .poly file.
++void FGDem::outputmesh_output_nodes( const string& fg_root, FGBucket& p )
++{
++    double exnodes[MAX_EX_NODES][3];
++    struct stat stat_buf;
++    string dir;
++    char file[256], exfile[256];
++#ifdef WIN32
++    char tmp_path[256];
++#endif
++    string command;
++    FILE *fd;
++    long int index;
++    int colmin, colmax, rowmin, rowmax;
++    int i, j, count, excount, result;
++
++    // determine dimensions
++    colmin = p.get_x() * ( (cols - 1) / 8);
++    colmax = colmin + ( (cols - 1) / 8);
++    rowmin = p.get_y() * ( (rows - 1) / 8);
++    rowmax = rowmin + ( (rows - 1) / 8);
++    cout << "  dumping region = " << colmin << "," << rowmin << " to " <<
++      colmax << "," << rowmax << "\n";
++
++    // generate the base directory
++    string base_path = p.gen_base_path();
++    cout << "fg_root = " << fg_root << "  Base Path = " << base_path << endl;
++    dir = fg_root + "/Scenery/" + base_path;
++    cout << "Dir = " << dir << endl;
++    
++    // stat() directory and create if needed
++    errno = 0;
++    result = stat(dir.c_str(), &stat_buf);
++    if ( result != 0 && errno == ENOENT ) {
++      cout << "Creating directory\n";
++
++// #ifndef WIN32
++
++      command = "mkdir -p " + dir + "\n";
++      system( command.c_str() );
++
++#if 0
++// #else // WIN32
++
++      // Cygwin crashes when trying to output to node file
++      // explicitly making directory structure seems OK on Win95
++
++      extract_path (base_path, tmp_path);
++
++      dir = fg_root + "/Scenery";
++      if (my_mkdir ( dir.c_str() )) { exit (-1); }
++
++      dir = fg_root + "/Scenery/" + tmp_path;
++      if (my_mkdir ( dir.c_str() )) { exit (-1); }
++
++      dir = fg_root + "/Scenery/" + base_path;
++      if (my_mkdir ( dir.c_str() )) { exit (-1); }
++
++// #endif // WIN32
++#endif //0
++
++    } else {
++      // assume directory exists
++    }
++
++    // get index and generate output file name
++    index = p.gen_index();
++    sprintf(file, "%s/%ld.node", dir.c_str(), index);
++
++    // get (optional) extra node file name (in case there is matching
++    // .poly file.
++    strcpy(exfile, file);
++    strcat(exfile, ".ex");
++
++    // load extra nodes if they exist
++    excount = 0;
++    if ( (fd = fopen(exfile, "r")) != NULL ) {
++      int junki;
++      fscanf(fd, "%d %d %d %d", &excount, &junki, &junki, &junki);
++
++      if ( excount > MAX_EX_NODES - 1 ) {
++          printf("Error, too many 'extra' nodes, increase array size\n");
++          exit(-1);
++      } else {
++          printf("    Expecting %d 'extra' nodes\n", excount);
++      }
++
++      for ( i = 1; i <= excount; i++ ) {
++          fscanf(fd, "%d %lf %lf %lf\n", &junki, 
++                 &exnodes[i][0], &exnodes[i][1], &exnodes[i][2]);
++          printf("(extra) %d %.2f %.2f %.2f\n", 
++                  i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
++      }
++      fclose(fd);
++    }
++
++    printf("Creating node file:  %s\n", file);
++    fd = fopen(file, "w");
++
++    // first count regular nodes to generate header
++    count = 0;
++    for ( j = rowmin; j <= rowmax; j++ ) {
++      for ( i = colmin; i <= colmax; i++ ) {
++          if ( output_data[i][j] > -9000.0 ) {
++              count++;
++          }
++      }
++      // printf("    count = %d\n", count);
++    }
++    fprintf(fd, "%d 2 1 0\n", count + excount);
++
++    // now write out extra node data
++    for ( i = 1; i <= excount; i++ ) {
++      fprintf(fd, "%d %.2f %.2f %.2f\n", 
++              i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
++    }
++
++    // write out actual node data
++    count = excount + 1;
++    for ( j = rowmin; j <= rowmax; j++ ) {
++      for ( i = colmin; i <= colmax; i++ ) {
++          if ( output_data[i][j] > -9000.0 ) {
++              fprintf(fd, "%d %.2f %.2f %.2f\n", 
++                      count++, 
++                      originx + (double)i * col_step, 
++                      originy + (double)j * row_step,
++                      output_data[i][j]);
++          }
++      }
++      // printf("    count = %d\n", count);
++    }
++
++    fclose(fd);
++}
++#endif
++
++
++FGDem::~FGDem( void ) {
++    // printf("class FGDem DEstructor called.\n");
++    delete [] dem_data;
++    delete [] output_data;
++}
++
++
++// $Log$
++// Revision 1.27  1999/03/25 19:04:36  curt
++// Minor tweaks related to FGBucket usage.
++//
++// Revision 1.26  1999/03/13 17:40:37  curt
++// Moved point interpolation and least squares fitting to contruction program
++// area.
++// Moved leastsqs.* to Lib/Math/
++//
++// Revision 1.25  1999/03/12 22:53:07  curt
++// Added a routine to dump out the portion of the dem data covered by a
++// specified bucket.  Other changes related to needs of scenery tools overhaul.
++//
++// Revision 1.24  1999/03/11 23:31:56  curt
++// Tweaks to use newbucket.hxx
++//
++// Revision 1.23  1999/03/10 01:09:12  curt
++// Tweaks to go along with scenery tools overhaul.
++// Added a new constructor that accepts the file name.
++//
++// Revision 1.22  1999/01/19 20:56:56  curt
++// MacOS portability changes contributed by "Robert Puyol" <puyol@abvent.fr>
++//
++// Revision 1.21  1998/11/06 14:04:32  curt
++// Changes due to updates in fgstream.
++//
++// Revision 1.20  1998/10/28 19:38:20  curt
++// Elliminate some unnecessary win32 specific stuff (by Norman Vine)
++//
++// Revision 1.19  1998/10/22 21:59:19  curt
++// Fixed a couple subtle bugs that resulted from some of my c++ conversions.
++// One bug could cause a segfault on certain input, and the other bug could
++// cause the whole procedure to go balistic and generate huge files (also only
++// on rare input combinations.)
++//
++// Revision 1.18  1998/10/18 01:17:09  curt
++// Point3D tweaks.
++//
++// Revision 1.17  1998/10/16 19:08:12  curt
++// Portability updates from Bernie Bright.
++//
++// Revision 1.16  1998/10/02 21:41:39  curt
++// Fixes for win32.
++//
++// Revision 1.15  1998/09/21 20:53:59  curt
++// minor tweaks to clean a few additional things up after the rewrite.
++//
++// Revision 1.14  1998/09/19 17:59:45  curt
++// Use c++ streams (fg_gzifstream).  Also converted many character arrays to
++// the string class.
++//
++// Revision 1.13  1998/09/09 16:24:04  curt
++// Fixed a bug in the handling of exclude files which was causing
++// a crash by calling fclose() on an invalid file handle.
++//
++// Revision 1.12  1998/08/24 20:03:31  curt
++// Eliminated a possible memory overrun error.
++// Use the proper free() rather than the incorrect delete().
++//
++// Revision 1.11  1998/07/20 12:46:11  curt
++// When outputing to a .node file, first check for an optional
++// "index.node.ex" file in case there is a .poly file to go along with this
++// node file.  Include these nodes first since they are referenced by position
++// from the .poly file.  This is my first pass at adding an area "cutout"
++// feature to the terrain generation pipeline.
++//
++// Revision 1.10  1998/07/13 20:58:02  curt
++// .
++//
++// Revision 1.9  1998/07/13 15:29:49  curt
++// Added #ifdef HAVE_CONFIG_H
++//
++// Revision 1.8  1998/07/04 00:47:18  curt
++// typedef'd struct fgBUCKET.
++//
++// Revision 1.7  1998/06/05 18:14:39  curt
++// Abort out early when reading the "A" record if it doesn't look like
++// a proper DEM file.
++//
++// Revision 1.6  1998/05/02 01:49:21  curt
++// Fixed a bug where the wrong variable was being initialized.
++//
++// Revision 1.5  1998/04/25 15:00:32  curt
++// Changed "r" to "rb" in gzopen() options.  This fixes bad behavior in win32.
++//
++// Revision 1.4  1998/04/22 13:14:46  curt
++// Fixed a bug in zlib usage.
++//
++// Revision 1.3  1998/04/18 03:53:05  curt
++// Added zlib support.
++//
++// Revision 1.2  1998/04/14 02:43:27  curt
++// Used "new" to auto-allocate large DEM parsing arrays in class constructor.
++//
++// Revision 1.1  1998/04/08 22:57:22  curt
++// Adopted Gnu automake/autoconf system.
++//
++// Revision 1.3  1998/04/06 21:09:41  curt
++// Additional win32 support.
++// Fixed a bad bug in dem file parsing that was causing the output to be
++// flipped about x = y.
++//
++// Revision 1.2  1998/03/23 20:35:41  curt
++// Updated to use FG_EPSILON
++//
++// Revision 1.1  1998/03/19 02:54:47  curt
++// Reorganized into a class lib called fgDEM.
++//
++// Revision 1.1  1998/03/19 01:46:28  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..46849e3a4ef8712786c1ea9679fa71ea2fa1d439
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,210 @@@
++// dem.hxx -- DEM management class
++//
++// Written by Curtis Olson, started March 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef _DEM_HXX
++#define _DEM_HXX
++
++
++#ifndef __cplusplus                                                          
++# error This library requires C++
++#endif                                   
++
++
++#include <Bucket/newbucket.hxx>
++#include <Misc/fgstream.hxx>
++
++
++#define DEM_SIZE 1200
++#define DEM_SIZE_1 1201
++
++
++class FGDem {
++
++private:
++
++    // file pointer for input
++    // gzFile fd;
++    fg_gzifstream *in;
++
++    // coordinates (in arc seconds) of south west corner
++    double originx, originy;
++    
++    // number of columns and rows
++    int cols, rows;
++    
++    // Distance between column and row data points (in arc seconds)
++    double col_step, row_step;
++    
++    // pointers to the actual grid data allocated here
++    float (*dem_data)[DEM_SIZE_1];
++    float (*output_data)[DEM_SIZE_1];
++
++    // Current "A" Record Information
++    char dem_description[80], dem_quadrangle[80];
++    double dem_x1, dem_y1, dem_x2, dem_y2, dem_x3, dem_y3, dem_x4, dem_y4;
++    double dem_z1, dem_z2;
++    int dem_resolution, dem_num_profiles;
++  
++    // Current "B" Record Information
++    int prof_col, prof_row;
++    int prof_num_cols, prof_num_rows;
++    double prof_x1, prof_y1;
++    int prof_data;
++
++    // temporary values for the class to use
++    char option_name[32];
++    int do_data;
++    int cur_col, cur_row;
++
++    // return next token from input stream
++    string next_token();
++
++    // return next integer from input stream
++    int next_int();
++
++    // return next double from input stream
++    double next_double();
++
++    // return next exponential num from input stream
++    double next_exp();
++
++public:
++
++    // Constructor
++    FGDem( void );
++    FGDem( const string& file );
++
++    // Destructor
++    ~FGDem( void );
++
++    // open a DEM file (use "-" if input is coming from stdin)
++    int open ( const string& file );
++
++    // close a DEM file
++    int close();
++
++    // parse a DEM file
++    int parse();
++
++    // read and parse DEM "A" record
++    int read_a_record();
++
++    // read and parse DEM "B" record
++    void read_b_record();
++
++    // write out the area of data covered by the specified bucket.
++    // Data is written out column by column starting at the lower left
++    // hand corner.
++    int write_area( const string& root, FGBucket& b, bool compress );
++
++#if 0
++    // return the current altitude based on grid data.  We should
++    // rewrite this to interpolate exact values, but for now this is
++    // good enough
++    double interpolate_altitude( double lon, double lat );
++
++    // Use least squares to fit a simpler data set to dem data
++    void fit( double error, FGBucket& p );
++
++    // Initialize output mesh structure
++    void outputmesh_init( void );
++
++    // Get the value of a mesh node
++    double outputmesh_get_pt( int i, int j );
++
++    // Set the value of a mesh node
++    void outputmesh_set_pt( int i, int j, double value );
++
++    // Write out a node file that can be used by the "triangle" program
++    void outputmesh_output_nodes( const string& fg_root, FGBucket& p );
++#endif
++
++    // Informational methods
++    inline double get_originx() const { return originx; }
++    inline double get_originy() const { return originy; }
++    inline int get_cols() const { return cols; }
++    inline int get_rows() const { return rows; }
++    inline double get_col_step() const { return col_step; }
++    inline double get_row_step() const { return row_step; }
++};
++
++
++#endif // _DEM_HXX
++
++
++// $Log$
++// Revision 1.13  1999/03/13 17:40:39  curt
++// Moved point interpolation and least squares fitting to contruction program
++// area.
++// Moved leastsqs.* to Lib/Math/
++//
++// Revision 1.12  1999/03/12 22:53:09  curt
++// Added a routine to dump out the portion of the dem data covered by a
++// specified bucket.  Other changes related to needs of scenery tools overhaul.
++//
++// Revision 1.11  1999/03/11 23:31:57  curt
++// Tweaks to use newbucket.hxx
++//
++// Revision 1.10  1999/03/10 01:09:13  curt
++// Tweaks to go along with scenery tools overhaul.
++// Added a new constructor that accepts the file name.
++//
++// Revision 1.9  1998/10/16 19:08:14  curt
++// Portability updates from Bernie Bright.
++//
++// Revision 1.8  1998/09/19 17:59:46  curt
++// Use c++ streams (fg_gzifstream).  Also converted many character arrays to
++// the string class.
++//
++// Revision 1.7  1998/07/04 00:47:19  curt
++// typedef'd struct fgBUCKET.
++//
++// Revision 1.6  1998/06/05 18:14:40  curt
++// Abort out early when reading the "A" record if it doesn't look like
++// a proper DEM file.
++//
++// Revision 1.5  1998/04/22 13:14:46  curt
++// Fixed a bug in zlib usage.
++//
++// Revision 1.4  1998/04/21 17:03:41  curt
++// Prepairing for C++ integration.
++//
++// Revision 1.3  1998/04/18 03:53:06  curt
++// Added zlib support.
++//
++// Revision 1.2  1998/04/14 02:43:28  curt
++// Used "new" to auto-allocate large DEM parsing arrays in class constructor.
++//
++// Revision 1.1  1998/04/08 22:57:23  curt
++// Adopted Gnu automake/autoconf system.
++//
++// Revision 1.2  1998/03/23 20:35:42  curt
++// Updated to use FG_EPSILON
++//
++// Revision 1.1  1998/03/19 02:54:47  curt
++// Reorganized into a class lib called fgDEM.
++//
++// Revision 1.1  1998/03/19 01:46:29  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9103e673b8da4d596c700edf7ed9dadbb6f81c81
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,58 @@@
++#---------------------------------------------------------------------------
++# Makefile
++#
++# Written by Curtis Olson, started March 1999.
++#
++# Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++# $Id$
++# (Log is kept at end of this file)
++#---------------------------------------------------------------------------
++
++
++bin_PROGRAMS = demchop
++
++demchop_SOURCES = \
++      demchop.cxx point2d.hxx
++
++demchop_LDADD = \
++      $(top_builddir)/Tools/Lib/DEM/libDEM.a \
++      $(top_builddir)/Lib/Bucket/libBucket.a \
++      $(top_builddir)/Lib/Misc/libMisc.a \
++      $(top_builddir)/Lib/Debug/libDebug.a \
++      $(top_builddir)/Lib/zlib/libz.a \
++      $(base_LIBS)
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib
++
++# We can't build this with "-O2" (optimization) since this causes a seg fault
++# I haven't found a way to strip this out of the CXXFLAGS, so I'm just
++# setting it to "-g"
++# CXXFLAGS = -g 
++
++
++#---------------------------------------------------------------------------
++# $Log$
++# Revision 1.3  1999/03/17 23:51:07  curt
++# Removed forced -g compiler flag.
++#
++# Revision 1.2  1999/03/12 22:53:45  curt
++# First working version!
++#
++# Revision 1.1  1999/03/10 01:02:54  curt
++# Initial revision.
++#
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8182c8d8ee3d12e2ed7b60aaae4ee6e5c2b6f402
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,113 @@@
++// demchop.cxx -- chop up a dem file into it's corresponding pieces and stuff
++//                them into the workspace directory
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1997  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include <Include/compiler.h>
++
++#include STL_STRING
++
++#include <Debug/logstream.hxx>
++#include <Bucket/newbucket.hxx>
++#include <DEM/dem.hxx>
++
++#include "point2d.hxx"
++
++FG_USING_STD(string);
++
++
++int main(int argc, char **argv) {
++    /*
++    fgDEM dem;
++    FGBucket p;
++    string fg_root;
++    string filename;
++    double error;
++    int i, j;
++    */
++
++    fglog().setLogLevels( FG_ALL, FG_DEBUG );
++
++    if ( argc != 3 ) {
++      FG_LOG( FG_GENERAL, FG_ALERT, 
++              "Usage " << argv[0] << " <dem_file> <work_dir>" );
++      exit(-1);
++    }
++
++    string dem_name = argv[1];
++    string work_dir = argv[2];
++    string command = "mkdir -p " + work_dir;
++    system( command.c_str() );
++
++    FGDem dem(dem_name);
++    dem.parse();
++    dem.close();
++
++    point2d min, max;
++    min.x = dem.get_originx() / 3600.0 + FG_HALF_BUCKET_SPAN;
++    min.y = dem.get_originy() / 3600.0 + FG_HALF_BUCKET_SPAN;
++    FGBucket b_min( min.x, min.y );
++
++    max.x = (dem.get_originx() + dem.get_cols() * dem.get_col_step()) / 3600.0 
++      - FG_HALF_BUCKET_SPAN;
++    max.y = (dem.get_originy() + dem.get_rows() * dem.get_row_step()) / 3600.0 
++      - FG_HALF_BUCKET_SPAN;
++    FGBucket b_max( max.x, max.y );
++
++    if ( b_min == b_max ) {
++      dem.write_area( work_dir, b_min, true );
++    } else {
++      FGBucket b_cur;
++      int dx, dy, i, j;
++
++      fgBucketDiff(b_min, b_max, &dx, &dy);
++      cout << "DEM file spans tile boundaries" << endl;
++      cout << "  dx = " << dx << "  dy = " << dy << endl;
++
++      if ( (dx > 20) || (dy > 20) ) {
++          cout << "somethings really wrong!!!!" << endl;
++          exit(-1);
++      }
++
++      for ( j = 0; j <= dy; j++ ) {
++          for ( i = 0; i <= dx; i++ ) {
++              b_cur = fgBucketOffset(min.x, min.y, i, j);
++              dem.write_area( work_dir, b_cur, true );
++          }
++      }
++    }
++
++    return 0;
++}
++
++
++// $Log$
++// Revision 1.3  1999/03/12 22:53:46  curt
++// First working version!
++//
++// Revision 1.2  1999/03/10 16:09:44  curt
++// Hacking towards the first working version.
++//
++// Revision 1.1  1999/03/10 01:02:54  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..817015f8acf22d540985b139e39d05a4ab9043fc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,44 @@@
++// point2d.cxx -- 2d coordinate routines
++//
++// Written by Curtis Olson, started September 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#include <math.h>
++
++#include "point2d.hxx"
++
++
++// convert a point from cartesian to polar coordinates
++point2d cart_to_polar_2d(point2d in) {
++    point2d result;
++    result.dist = sqrt( in.x * in.x + in.y * in.y );
++    result.theta = atan2(in.y, in.x);    
++
++    return(result);
++}
++
++
++// $Log$
++// Revision 1.1  1999/03/10 01:02:54  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e4df44488946b42e10fd72d9317238bf21e87722
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,62 @@@
++// point2d.hxx -- define a 2d point class
++//
++// Written by Curtis Olson, started February 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#ifndef _POINT2D_HXX
++#define _POINT2D_HXX
++
++
++#include <list>
++
++
++class point2d {
++public:
++    union {
++      double x;
++      double dist;
++      double lon;
++    };
++    union {
++      double y;
++      double theta;
++      double lat;
++    };
++};
++
++
++// convert a point from cartesian to polar coordinates
++point2d cart_to_polar_2d(point2d in);
++
++
++#endif // _POINT2D_HXX
++
++
++// $Log$
++// Revision 1.1  1999/03/10 16:09:45  curt
++// Hacking towards the first working version.
++//
++// Revision 1.1  1998/09/04 23:04:53  curt
++// Beginning of convex hull genereration routine.
++//
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b3d8d3aa7e375f43f8ddd4552faacad97f0a3688
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,70 @@@
++#---------------------------------------------------------------------------
++# Makefile
++#
++# Written by Curtis Olson, started June 1998.
++#
++# Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++# $Id$
++# (Log is kept at end of this file)
++#---------------------------------------------------------------------------
++
++
++bin_PROGRAMS = deminfo
++
++deminfo_SOURCES = \
++      deminfo.cxx
++
++deminfo_LDADD = \
++      $(top_builddir)/Tools/Lib/DEM/libDEM.a \
++      $(top_builddir)/Lib/Bucket/libBucket.a \
++      $(top_builddir)/Lib/Misc/libMisc.a \
++      $(top_builddir)/Lib/zlib/libz.a \
++      $(base_LIBS)
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib
++
++# We can't build this with "-O2" (optimization) since this causes a seg fault
++# I haven't found a way to strip this out of the CXXFLAGS, so I'm just
++# setting it to "-g"
++# CXXFLAGS = -g 
++
++
++#---------------------------------------------------------------------------
++# $Log$
++# Revision 1.7  1999/03/17 23:51:14  curt
++# Removed forced -g compiler flag.
++#
++# Revision 1.6  1999/03/08 22:00:46  curt
++# Lots of directory layout reorganization.
++#
++# Revision 1.5  1999/02/01 21:09:27  curt
++# Moving location of Lib/DEM/ to Tools/DEM/
++#
++# Revision 1.4  1998/11/04 23:01:48  curt
++# Changes to the automake/autoconf system to reduce the number of libraries
++# that are unnecessarily linked into the various executables.
++#
++# Revision 1.3  1998/09/19 18:01:21  curt
++# Support for changes to libDEM.a
++#
++# Revision 1.2  1998/07/30 23:49:24  curt
++# Removed libtool support.
++#
++# Revision 1.1  1998/06/04 19:18:04  curt
++# Initial revision.
++#
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..75f9c2f55cd0f553639160df08ceeeee888ff6a9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,78 @@@
++// deminfo.cxx -- main loop
++//
++// Written by Curtis Olson, started June 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <string>
++
++#include <DEM/dem.hxx>
++
++
++// static float dem_data[DEM_SIZE_1][DEM_SIZE_1];
++// static float output_data[DEM_SIZE_1][DEM_SIZE_1];
++
++
++int main(int argc, char **argv) {
++    // DEM data
++    FGDem dem;
++    string filename;
++    double error;
++    int i, j;
++
++    if ( argc != 2 ) {
++      printf("Usage: %s <file.dem>\n", argv[0]);
++      exit(-1);
++    }
++
++    // set input dem file name
++    filename = argv[1];
++
++    dem.open(filename);
++
++    if ( dem.read_a_record() ) {
++      cout << "Results = " << filename << "  "
++           << dem.get_originx() / 3600.0 << " "
++           << dem.get_originy() / 3600.0 << "\n";
++    } else {
++      cout << "Error parsing DEM file.\n";
++    }
++
++    dem.close();
++
++    return(0);
++}
++
++
++// $Log$
++// Revision 1.3  1999/03/12 22:54:04  curt
++// Convert fgDEM to FGDem ...
++//
++// Revision 1.2  1998/09/19 18:01:22  curt
++// Support for changes to libDEM.a
++//
++// Revision 1.1  1998/06/04 19:18:05  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..746d7120e4f69fccb46f9333f71b6e1f22a1ec16
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,61 @@@
++#!/usr/bin/perl
++
++#---------------------------------------------------------------------------
++# script to gather DEM position info so we can associate a file name with a
++# position.
++#
++# Written by Curtis Olson, started June 1998.
++#
++# Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++# $Id$
++# (Log is kept at end of this file)
++#---------------------------------------------------------------------------
++
++
++if ( $#ARGV < 0 ) {
++    die "Usage: $0 search_dir ... \n";
++}
++
++while ( $dir = shift(@ARGV) ) {
++    # print "processing $dir\n";
++
++    @allfiles = `find $dir -print`;
++
++    foreach $file (@allfiles) {
++      chop($file);
++      # print "trying $file\n";
++      if ( -f $file ) {
++          # print "really trying $file\n";
++          open ( INFO, "./deminfo $file |" );
++          while ( <INFO> ) {
++              if ( m/Results = / ) {
++                  $_ =~ s/Results = //;
++                  print $_;
++              }
++          }
++          close(INFO);
++      }
++    }
++}
++
++
++#---------------------------------------------------------------------------
++# $Log$
++# Revision 1.1  1998/06/04 19:18:06  curt
++# Initial revision.
++#
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b638e2e966a95f6876dd42d0502c712532bcf8e9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,47 @@@
++#---------------------------------------------------------------------------
++# Makefile
++#
++# Written by Curtis Olson, started February 1998.
++#
++# Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++# $Id$
++# (Log is kept at end of this file)
++#---------------------------------------------------------------------------
++
++
++bin_PROGRAMS = raw2ascii
++
++raw2ascii_SOURCES = main.c rawdem.c rawdem.h
++
++raw2ascii_LDADD = $(base_LIBS)
++
++INCLUDES += 
++
++
++#---------------------------------------------------------------------------
++# $Log$
++# Revision 1.3  1998/11/04 23:01:50  curt
++# Changes to the automake/autoconf system to reduce the number of libraries
++# that are unnecessarily linked into the various executables.
++#
++# Revision 1.2  1998/04/24 00:44:04  curt
++# Added zlib support.
++#
++# Revision 1.1  1998/04/18 03:59:44  curt
++# Incorporated into gnu automake/autoconf system.
++#
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8cc0f2ffaeb680987f5ba097c25189dfc2d7dcc6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,90 @@@
++/* main.c -- main loop
++ *
++ * Written by Curtis Olson, started February 1998.
++ *
++ * Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * $Id$
++ * (Log is kept at end of this file)
++ */
++
++
++#include <stdio.h>
++#include <string.h>
++
++#include "rawdem.h"
++
++
++int main(int argc, char **argv) {
++    fgRAWDEM raw;
++    char basename[256], output_dir[256], hdr_file[256], dem_file[256];
++    int i, start_lat, end_lat;
++
++    if ( argc != 3 ) {
++      printf("Usage: %s <input_file_basename> <output_dir>\n", argv[0]);
++      exit(-1);
++    }
++
++    /* get basename */
++    strcpy(basename, argv[1]);
++
++    /* get output dir */
++    strcpy(output_dir, argv[2]);
++
++    /* generate header file name */
++    strcpy(hdr_file, basename);
++    strcat(hdr_file, ".HDR");
++
++    /* generate input file name (raw dem) */
++    strcpy(dem_file, basename);
++    strcat(dem_file, ".DEM");
++    
++    printf("Header file = %s  Input file = %s\n", hdr_file, dem_file);
++    printf("Output Directory = %s\n", output_dir);
++
++    /* scan the header file and extract important values */
++    rawReadDemHdr(&raw, hdr_file);
++
++    /* open up the raw data file */
++    rawOpenDemFile(&raw, dem_file);
++
++    end_lat = raw.rooty / 3600;
++    start_lat = end_lat - ((raw.nrows * raw.ydim) / 3600);
++    printf("Latitude ranges from %d to %d\n", start_lat, end_lat);
++
++    for ( i = start_lat + 1; i <= end_lat; i++ ) {
++      rawProcessStrip(&raw, i, output_dir);
++    }
++
++    /* close the raw data file */
++    rawCloseDemFile(&raw);
++
++    return(0);
++}
++
++
++/* $Log$
++/* Revision 1.3  1998/03/03 21:54:50  curt
++/* Changes to process 30 arcsec binary DEM files.
++/*
++ * Revision 1.2  1998/03/03 13:10:28  curt
++ * Close to a working version.
++ *
++ * Revision 1.1  1998/03/02 23:31:01  curt
++ * Initial revision.
++ *
++ */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8411035bd28aeb51c5bc9cdc4b697c69654be843
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,485 @@@
++/* rawdem.c -- library of routines for processing raw dem files (30 arcsec)
++ *
++ * Written by Curtis Olson, started February 1998.
++ *
++ * Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * $Id$
++ * (Log is kept at end of this file)
++ */
++
++
++#ifdef HAVE_CONFIG_H
++#  include <config.h>
++#endif
++
++#include <math.h>      /* rint() */
++#include <stdio.h>
++#include <stdlib.h>    /* atoi() atof() */
++#include <string.h>    /* swab() */
++
++#include <sys/types.h> /* open() */
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <unistd.h>    /* close() */
++
++#include "rawdem.h"
++
++
++/* Read the DEM header to determine various key parameters for this
++ * DEM file */
++void rawReadDemHdr( fgRAWDEM *raw, char *hdr_file ) {
++    FILE *hdr;
++    char line[256], key[256], value[256];
++    int i, len, offset;
++    double tmp;
++
++    if ( (hdr = fopen(hdr_file, "r")) == NULL ) {
++      printf("Error opening DEM header file: %s\n", hdr_file);
++      exit(-1);
++    }
++
++    /* process each line */
++    while ( (fgets(line, 256, hdr) != NULL) ) {
++      /* printf("%s", line); */
++      len = strlen(line);
++
++      /* extract key */
++      i = 0;
++      while ( (line[i] != ' ') && (i < len) ) {
++          key[i] = line[i];
++          i++;
++      }
++      key[i] = '\0';
++
++      /* skip middle space */
++      while ( (line[i] == ' ') && (i < len) ) {
++          i++;
++      }
++      offset = i;
++
++      /* extract value */
++      while ( (line[i] != '\n') && (i < len) ) {
++          value[i-offset] = line[i];
++          i++;
++      }
++      value[i-offset] = '\0';
++      /* printf("key='%s'  value='%s'\n", key, value); */
++
++      if ( strcmp(key, "NROWS") == 0 ) {
++          raw->nrows = atoi(value);
++      } else if ( strcmp(key, "NCOLS") == 0 ) {
++          raw->ncols = atoi(value);
++      } else if ( strcmp(key, "ULXMAP") == 0 ) {
++          tmp = atof(value);
++#ifdef HAVE_RINT
++          raw->ulxmap = (int)rint(tmp * 3600.0); /* convert to arcsec */
++#else
++#  error Port me rint()
++#endif
++      } else if ( strcmp(key, "ULYMAP") == 0 ) {
++          tmp = atof(value);
++#ifdef HAVE_RINT
++          raw->ulymap = (int)rint(tmp * 3600.0); /* convert to arcsec */
++#else
++#  error Port me rint()
++#endif
++      } else if ( strcmp(key, "XDIM") == 0 ) {
++          tmp = atof(value);
++#ifdef HAVE_RINT
++          raw->xdim = (int)rint(tmp * 3600.0);   /* convert to arcsec */
++#else
++#  error Port me rint()
++#endif
++      } else if ( strcmp(key, "YDIM") == 0 ) {
++          tmp = atof(value);
++#ifdef HAVE_RINT
++          raw->ydim = (int)rint(tmp * 3600.0);   /* convert to arcsec */
++#else
++#  error Port me rint()
++#endif
++      } else {
++          /* ignore for now */
++      }
++    }
++
++    raw->rootx = raw->ulxmap - (raw->xdim / 2);
++    raw->rooty = raw->ulymap + (raw->ydim / 2);
++
++    printf("%d %d %d %d %d %d %d %d\n", raw->nrows, raw->ncols,
++           raw->ulxmap, raw->ulymap, raw->rootx, raw->rooty, raw->xdim,
++         raw->ydim);
++}
++
++
++/* Open a raw DEM file. */
++void rawOpenDemFile( fgRAWDEM *raw, char *raw_dem_file ) {
++    printf("Opening Raw DEM file: %s\n", raw_dem_file);
++    if ( (raw->fd = open(raw_dem_file ,O_RDONLY)) == -1 ) {
++      printf("Error opening Raw DEM file: %s\n", raw_dem_file);
++      exit(-1);
++    }
++}
++
++
++/* Close a raw DEM file. */
++void rawCloseDemFile( fgRAWDEM *raw ) {
++    close(raw->fd);
++}
++
++
++/* Advance file pointer position to correct latitude (row) */
++void rawAdvancePosition( fgRAWDEM *raw, int arcsec ) {
++    long offset, result;
++
++    offset = 2 * raw->ncols * ( arcsec  / raw->ydim );
++
++    if ( (result = lseek(raw->fd, offset, SEEK_SET)) == -1 ) {
++      printf("Error lseek filed trying to offset by %ld\n", offset);
++      exit(-1);
++    }
++
++    printf("Successful seek ahead of %ld bytes\n", result);
++}
++
++
++/* Read the next row of data */
++void rawReadNextRow( fgRAWDEM *raw, int index ) {
++    char buf[MAX_COLS_X_2];
++    int i, result;
++
++    if ( raw->ncols > MAX_ROWS ) {
++      printf("Error, buf needs to be bigger in rawReadNextRow()\n");
++      exit(-1);
++    }
++
++    /* printf("Attempting to read %d bytes\n", 2 * raw->ncols); */
++    result = read(raw->fd, buf, 2 * raw->ncols);
++    /* printf("Read %d bytes\n", result); */
++
++    /* reverse byte order */
++    /* it would be nice to test in advance some how if we need to do
++     * this */
++    /* swab(frombuf, tobuf, 2 * raw->ncols); */
++
++    for ( i = 0; i < raw->ncols; i++ ) {
++      /* printf("hi = %d  lo = %d\n", buf[2*i], buf[2*i + 1]); */
++      raw->strip[index][i] = ( (buf[2*i] + 1) << 8 ) + buf[2*i + 1];
++    }
++}
++
++
++/* Convert from pixel centered values to pixel corner values.  This is
++   accomplished by taking the average of the closes center nodes.  In
++   the following diagram "x" marks the data point location:
++
++   +-----+        x-----x
++   |     |        |     |
++   |  x  |  ===>  |     |
++   |     |        |     |
++   +-----+        x-----x
++   
++   */
++void rawConvertCenter2Edge( fgRAWDEM *raw ) {
++    int i, j;
++
++    /* derive corner nodes */
++    raw->edge[0][0]     = raw->center[0][0];
++    raw->edge[120][0]   = raw->center[119][0];
++    raw->edge[120][120] = raw->center[119][119];
++    raw->edge[0][120]   = raw->center[0][119];
++
++    /* derive edge nodes */
++    for ( i = 1; i < 120; i++ ) {
++      raw->edge[i][0] = (raw->center[i-1][0] + raw->center[i][0]) / 2.0;
++      raw->edge[i][120] = (raw->center[i-1][119] + raw->center[i][119]) / 2.0;
++      raw->edge[0][i] = (raw->center[0][i-1] + raw->center[0][i]) / 2.0;
++      raw->edge[120][i] = (raw->center[119][i-1] + raw->center[119][i]) / 2.0;
++    }
++
++    /* derive internal nodes */
++    for ( j = 1; j < 120; j++ ) {
++      for ( i = 1; i < 120; i++ ) {
++          raw->edge[i][j] = ( raw->center[i-1][j-1] + 
++                              raw->center[i]  [j-1] +
++                              raw->center[i]  [j]   +
++                              raw->center[i-1][j] ) / 4;
++      }
++    }
++}
++
++
++/* Dump out the ascii format DEM file */
++void rawDumpAsciiDEM( fgRAWDEM *raw, char *path, int ilon, int ilat ) {
++    char outfile[256];
++    char tmp[256];
++    int lon, lat;
++    char lon_sign, lat_sign;
++    int i, j;
++    FILE *fd;
++
++    /* Generate output file name */
++
++    if ( ilon >= 0 ) {
++      lon = ilon;
++      lon_sign = 'e';
++    } else {
++      lon = -ilon;
++      lon_sign = 'w';
++    }
++
++    if ( ilat >= 0 ) {
++      lat = ilat;
++      lat_sign = 'n';
++    } else {
++      lat = -ilat;
++      lat_sign = 's';
++    }
++
++    sprintf(outfile, "%s/%c%03d%c%03d.dem", path, lon_sign, lon, lat_sign, lat);
++
++    printf("outfile = %s\n", outfile);
++
++    if ( (fd = fopen(outfile, "w")) == NULL ) {
++      printf("Error opening output file = %s\n", outfile);
++      exit(-1);
++    }
++
++    /* Dump the "A" record */
++
++    /* print descriptive header (144 characters) */
++    sprintf(tmp, "%s - Generated from a 30 arcsec binary DEM", outfile);
++    fprintf(fd, "%-144s", tmp);
++
++    /* DEM level code, 3 reflects processing by DMA */
++    fprintf(fd, "%6d", 1);
++
++    /* Pattern code, 1 indicates a regular elevation pattern */
++    fprintf(fd, "%6d", 1);
++
++    /* Planimetric reference system code, 0 indicates geographic 
++     * coordinate system. */
++    fprintf(fd, "%6d", 0);
++
++    /* Zone code */
++    fprintf(fd, "%6d", 0);
++
++    /* Map projection parameters (ignored) */
++    for ( i = 0; i < 15; i++ ) {
++        fprintf(fd, "%6.1f%18s", 0.0, "");
++    }
++
++   /* Units code, 3 represents arc-seconds as the unit of measure for
++     * ground planimetric coordinates throughout the file. */
++    fprintf(fd, "%6d", 3);
++
++    /* Units code; 2 represents meters as the unit of measure for
++     * elevation coordinates throughout the file. */
++    fprintf(fd, "%6d", 2);
++
++    /* Number (n) of sides in the polygon which defines the coverage of
++     * the DEM file (usually equal to 4). */
++    fprintf(fd, "%6d", 4);
++
++    /* Ground coordinates of bounding box in arc-seconds */
++    fprintf(fd, "%20.15fD+06", ilon * 3600.0 / 1000000.0);
++    fprintf(fd, "%20.15fD+06", ilat * 3600.0 / 1000000.0);
++
++    fprintf(fd, "%20.15fD+06", ilon * 3600.0 / 1000000.0);
++    fprintf(fd, "%20.15fD+06", (ilat+1) * 3600.0 / 1000000.0);
++
++    fprintf(fd, "%20.15fD+06", (ilon+1) * 3600.0 / 1000000.0);
++    fprintf(fd, "%20.15fD+06", (ilat+1) * 3600.0 / 1000000.0);
++
++    fprintf(fd, "%20.15fD+06", (ilon+1) * 3600.0 / 1000000.0);
++    fprintf(fd, "%20.15fD+06", (ilat) * 3600.0 / 1000000.0);
++
++    /* Minimum/maximum elevations in meters */
++    fprintf(fd, "   %20.15E", (double)raw->tmp_min);
++    fprintf(fd, "   %20.15E", (double)raw->tmp_max);
++
++    /* Counterclockwise angle from the primary axis of ground
++     * planimetric referenced to the primary axis of the DEM local
++     * reference system. */
++    fprintf(fd, "%6.1f", 0.0);
++
++    /* Accuracy code; 0 indicates that a record of accuracy does not
++     * exist and that no record type C will follow. */
++    fprintf(fd, "%24d", 0);
++
++    /* DEM spacial resolution.  Usually (3,3) (3,6) or (3,9)
++     * depending on latitude */
++    fprintf(fd, "%12.6E", 30.0);
++    fprintf(fd, "%12.6E", 30.0);
++
++    /* accuracy code */
++    fprintf(fd, "%12.6E", 1.0);
++    
++    /* dimension of arrays to follow (1)*/
++    fprintf(fd, "%6d", 1);
++
++    /* number of profiles */
++    fprintf(fd, "%6d", 3600 / raw->ydim + 1);
++
++    /* pad the end */
++    fprintf(fd, "%160s", "");
++
++
++    /* Dump "B" records */
++
++    for ( j = 0; j <= 120; j++ ) {
++      /* row / column id of this profile */
++      fprintf(fd, "%6d%6d", 1, j + 1);
++
++      /* Number of rows and columns (elevation points) in this
++           profile */
++      fprintf(fd, "%6d%6d", 3600 / raw->xdim + 1, 1);
++
++      /* Ground planimetric coordinates (arc-seconds) of the first
++       * elevation in the profile */
++      fprintf(fd, "%20.15fD+06", ilon * 3600.0 / 1000000.0);
++      fprintf(fd, "%20.15fD+06", (ilat * 3600.0 + j * raw->ydim) / 1000000.0);
++
++      /* Elevation of local datum for the profile.  Always zero for
++       * 1-degree DEM, the reference is mean sea level. */
++      fprintf(fd, "%6.1f", 0.0);
++      fprintf(fd, "%18s", "");
++
++      /* Minimum and maximum elevations for the profile. */
++      fprintf(fd, "   %20.15E", 0.0);
++      fprintf(fd, "   %20.15E", 0.0);
++
++      /* One (usually) dimensional array (1,prof_num_cols) of
++           elevations */
++      for ( i = 0; i <= 120; i++ ) {
++          fprintf(fd, "%6.0f", raw->edge[j][i]);
++      }
++    }
++
++    fprintf(fd, "\n");
++
++    fclose(fd);
++}
++
++
++/* Read a horizontal strip of (1 vertical degree) from the raw DEM
++ * file specified by the upper latitude of the stripe specified in
++ * degrees.  The output the individual ASCII format DEM tiles.  */
++void rawProcessStrip( fgRAWDEM *raw, int lat_degrees, char *path ) {
++    int lat, yrange;
++    int i, j, index, row, col;
++    int min, max;
++    int span, num_degrees, tile_width;
++    int xstart, xend;
++
++    /* convert to arcsec */
++    lat = lat_degrees * 3600;
++
++    printf("Max Latitude = %d arcsec\n", lat);
++
++    /* validity check ... */
++    if ( (lat > raw->rooty) || 
++       (lat < (raw->rooty - raw->nrows * raw->ydim + 1)) ) {
++      printf("Latitude out of range for this DEM file\n");
++      return;
++    }
++
++    printf ("Reading strip starting at %d (top and working down)\n", lat);
++
++    /* advance to the correct latitude */
++    rawAdvancePosition(raw, (raw->rooty - lat));
++
++    /* printf("short = %d\n", sizeof(short)); */
++
++    yrange = 3600 / raw->ydim;
++
++    for ( i = 0; i < yrange; i++ ) {
++      index = yrange - i - 1;
++      /* printf("About to read into row %d\n", index); */
++      rawReadNextRow(raw, index);
++
++      for ( j = 0; j < raw->ncols; j++ ) {
++          if ( raw->strip[index][j] == -9999 ) {
++              /* map ocean to 0 for now */
++              raw->strip[index][j] = 0;
++          } 
++      }
++    }
++
++    /* extract individual tiles from the strip */
++    span = raw->ncols * raw->xdim;
++    num_degrees = span / 3600;
++    tile_width = raw->ncols / num_degrees;
++    printf("span = %d  num_degrees = %d  width = %d\n", 
++         span, num_degrees, tile_width);
++
++    for ( i = 0; i < num_degrees; i++ ) {
++      xstart = i * tile_width;
++      xend = xstart + 120;
++
++      min = 10000; max = -10000;
++      for ( row = 0; row < yrange; row++ ) {
++          for ( col = xstart; col < xend; col++ ) {
++              /* Copy from strip to pixel centered tile.  Yep,
++                 * row/col are reversed here.  raw->strip is backwards
++                 * for convenience.  I am converting to [x,y] now. */
++              raw->center[col-xstart][row] = raw->strip[row][col];
++
++              if ( raw->strip[row][col] < min) {
++                  min = raw->strip[row][col];
++              }
++              
++              if ( raw->strip[row][col] > max) {
++                  max = raw->strip[row][col];
++              }
++          }
++      }
++
++      raw->tmp_min = min;
++      raw->tmp_max = max;
++
++      /* Convert from pixel centered to pixel edge values */
++      rawConvertCenter2Edge(raw);
++
++      /* Dump out the ascii format DEM file */
++      rawDumpAsciiDEM(raw, path, (raw->rootx / 3600) + i, lat_degrees - 1);
++    }
++}
++
++
++/* $Log$
++/* Revision 1.6  1998/04/27 03:32:03  curt
++/* Wrapped rint()'s in #ifdef HAVE_RINT
++/*
++ * Revision 1.5  1998/04/18 03:59:46  curt
++ * Incorporated into gnu automake/autoconf system.
++ *
++ * Revision 1.4  1998/04/06 21:09:43  curt
++ * Additional win32 support.
++ * Fixed a bad bug in dem file parsing that was causing the output to be
++ * flipped about x = y.
++ *
++ * Revision 1.3  1998/03/03 13:10:29  curt
++ * Close to a working version.
++ *
++ * Revision 1.2  1998/03/03 02:04:01  curt
++ * Starting DEM Ascii format output routine.
++ *
++ * Revision 1.1  1998/03/02 23:31:01  curt
++ * Initial revision.
++ *
++ */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8877b2eaabe658d7bc1a5b0647b25845e4021f19
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,85 @@@
++/* rawdem.h -- library of routines for processing raw dem files (30 arcsec)
++ *
++ * Written by Curtis Olson, started February 1998.
++ *
++ * Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * $Id$
++ * (Log is kept at end of this file)
++ */
++
++
++#ifndef _RAWDEM_H
++#define _RAWDEM_H
++
++
++#define MAX_ROWS 6000
++#define MAX_COLS 7200
++#define MAX_COLS_X_2 14400
++
++typedef struct {
++    /* header info */
++    int nrows;       /* number of rows */
++    int ncols;       /* number of cols */
++    int ulxmap;      /* X coord of center of upper left pixel in arcsec */
++    int ulymap;      /* Y coord of center of upper left pixel in arcsec */
++    int rootx;       /* X coord of upper left *edge* of DEM region in degrees */
++    int rooty;       /* Y coord of upper left *edge* of DEM region in degrees */
++    int xdim;        /* X dimension of a pixel */
++    int ydim;        /* Y dimension of a pixel */
++    int tmp_min;     /* current 1x1 degree tile minimum */
++    int tmp_max;     /* current 1x1 degree tile maximum */
++
++    /* file ptr */
++    int fd;          /* Raw DEM file descriptor */
++
++    /* storage area for a 1 degree high strip of data.  Note, for
++     * convenience this is in y,x order */
++    short strip[120][MAX_ROWS];
++
++    short center[120][120];  /* tile with data taken at center of pixel */
++    float edge[121][121];    /* tile with data converted to corners */
++} fgRAWDEM;
++
++
++/* Read the DEM header to determine various key parameters for this
++ * DEM file */
++void rawReadDemHdr( fgRAWDEM *raw, char *hdr_file );
++
++/* Open a raw DEM file. */
++void rawOpenDemFile( fgRAWDEM *raw, char *raw_dem_file );
++
++/* Close a raw DEM file. */
++void rawCloseDemFile( fgRAWDEM *raw );
++
++/* Read a horizontal strip of (1 vertical degree) from the raw DEM
++ * file specified by the upper latitude of the stripe specified in
++ * degrees.  The output the individual ASCII format DEM tiles.  */
++void rawProcessStrip( fgRAWDEM *raw, int lat_degrees, char *path );
++
++
++#endif /* _RAWDEM_H */
++
++
++/* $Log$
++/* Revision 1.2  1998/03/03 13:10:30  curt
++/* Close to a working version.
++/*
++ * Revision 1.1  1998/03/02 23:31:02  curt
++ * Initial revision.
++ *
++ */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a245e6ac08ac8ce4ae33e034111b5e6c0d13164e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,95 @@@
++#---------------------------------------------------------------------------
++# Makefile
++#
++# Written by Curtis Olson, started October 1997.
++#
++# Copyright (C) 1997 - 1998  Curtis L. Olson  - curt@me.umn.edu
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++# $Id$
++# (Log is kept at end of this file)
++#---------------------------------------------------------------------------
++
++
++bin_PROGRAMS = fixnode
++
++fixnode_SOURCES = \
++      fixnode.cxx fixnode.hxx \
++      main.cxx
++
++fixnode_LDADD = \
++      $(top_builddir)/Tools/Lib/DEM/libDEM.a \
++        $(top_builddir)/Lib/Bucket/libBucket.a \
++        $(top_builddir)/Lib/Misc/libMisc.a \
++        $(top_builddir)/Lib/zlib/libz.a \
++      $(base_LIBS)
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib
++
++# We can't build this with "-O2" (optimization) since this causes a seg fault
++# I haven't found a way to strip this out of the CXXFLAGS, so I'm just
++# setting it to "-g"
++# CXXFLAGS = -g
++
++
++#---------------------------------------------------------------------------
++# $Log$
++# Revision 1.10  1999/03/17 23:50:59  curt
++# Removed forced -g compiler flag.
++#
++# Revision 1.9  1999/03/08 22:00:45  curt
++# Lots of directory layout reorganization.
++#
++# Revision 1.8  1999/02/01 21:09:30  curt
++# Moving location of Lib/DEM/ to Tools/DEM/
++#
++# Revision 1.7  1998/11/04 23:01:51  curt
++# Changes to the automake/autoconf system to reduce the number of libraries
++# that are unnecessarily linked into the various executables.
++#
++# Revision 1.6  1998/09/19 20:43:50  curt
++# C++-ified and STL-ified the code.  Combined triload.* and fixnode.* into
++# a single file.
++#
++# Revision 1.5  1998/09/19 18:01:26  curt
++# Support for changes to libDEM.a
++#
++# Revision 1.4  1998/07/30 23:49:24  curt
++# Removed libtool support.
++#
++# Revision 1.3  1998/04/18 04:02:54  curt
++# Added zlib support in placed and other misc. tweaks.
++#
++# Revision 1.2  1998/04/14 02:26:02  curt
++# Code reorganizations.  Added a Lib/ directory for more general libraries.
++#
++# Revision 1.1  1998/04/08 23:05:54  curt
++# Adopted Gnu automake/autoconf system.
++#
++# Revision 1.4  1998/04/06 21:09:44  curt
++# Additional win32 support.
++# Fixed a bad bug in dem file parsing that was causing the output to be
++# flipped about x = y.
++#
++# Revision 1.3  1998/03/19 02:50:19  curt
++# Updated to support -lDEM class.
++#
++# Revision 1.2  1998/01/21 02:55:50  curt
++# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
++#
++# Revision 1.1  1997/11/27 00:17:32  curt
++# Initial revision.
++#
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5269ac4596bdf35c657f398e1a1f4cfa1667adf3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,161 @@@
++// fixnode.cxx -- traverse the node file and fix the elevation of all the new
++//                interpolated points.
++//
++// Written by Curtis Olson, started November 1997.
++//
++// Copyright (C) 1997  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++#include <string>
++
++#ifdef HAVE_STDLIB_H
++#  include <stdlib.h>
++#endif // HAVE_STDLIB_H
++
++#include <Misc/fgstream.hxx>
++
++#include "fixnode.hxx"
++
++
++// load extra nodes
++void load_extra(const string& filename, container& extra_list) {
++}
++
++
++// load the node information
++void load_nodes(const string& filename, container& node_list) {
++    Point3D node;
++    int dim, junk1, junk2;
++    int i, nodecount;
++
++    cout << "Loading node file:  " << filename << " ...\n";
++
++    fg_gzifstream in( filename );
++    if ( !in ) {
++      cout << "Cannot open " + filename + "\n";
++      // exit immediately assuming an airport file for this tile
++      // doesn't exist.
++      exit(-1);
++    }
++
++    // Read header line
++    in >> nodecount >> dim >> junk1 >> junk2;
++    cout << "    Expecting " << nodecount << " nodes\n";
++
++    // start with an empty list :-)
++    node_list.erase( node_list.begin(), node_list.end() );
++
++    in >> skipcomment;
++    while ( ! in.eof() ) {
++      in >> junk1 >> node >> junk2;
++      in >> skipcomment;
++      node_list.push_back(node);
++    }
++}
++
++
++// fix the node elevations
++void fix_nodes( const string& filename, fgDEM& dem, container& node_list )
++{
++    string toname;
++    FILE *fd;
++    int i;
++
++    cout << "Fixing up node elevations\n";
++
++    iterator current;
++    iterator last = node_list.end();
++    for ( current = node_list.begin() ; current != last ; ++current ) {
++      // printf("Current: %d %.2f %.2f %.2f\n", i, nodes[i][0],
++      //        nodes[i][1], nodes[i][2]);
++
++      (*current).setz( 
++                      dem.interpolate_altitude( (*current).x(), 
++                                                (*current).y() ) );
++
++      // printf("Fixed: %d %.2f %.2f %.2f\n", i, nodes[i][0],
++      //        nodes[i][1], nodes[i][2]);
++    }
++
++
++    toname = filename + ".orig";
++    cout << "Moving " + filename + " to " + toname + "\n";
++    rename( filename.c_str(), toname.c_str() );
++
++    cout << "Saving new node file: " + filename + "\n";
++
++    fd = fopen(filename.c_str(), "w");
++
++    fprintf( fd, "%d 2 1 0\n", node_list.size() );
++
++    i = 1;
++    for ( current = node_list.begin() ; current != last ; ++current ) {
++      fprintf( fd, "%d %.2f %.2f %.2f 0\n", i,
++               (*current).x(), (*current).y(), (*current).z() );
++      ++i;
++    }
++
++    fclose(fd);
++}
++
++
++// $Log$
++// Revision 1.7  1998/11/06 21:33:55  curt
++// Updates to go along with changes in fgstream.
++//
++// Revision 1.6  1998/10/20 15:49:22  curt
++// Converted to Point3D class.
++//
++// Revision 1.5  1998/09/22 23:49:10  curt
++// eliminated a left over #include
++//
++// Revision 1.4  1998/09/19 20:43:52  curt
++// C++-ified and STL-ified the code.  Combined triload.* and fixnode.* into
++// a single file.
++//
++// Revision 1.3  1998/07/22 21:46:40  curt
++// Fixed a bug that was triggering a seg fault.
++//
++// Revision 1.2  1998/04/14 02:26:03  curt
++// Code reorganizations.  Added a Lib/ directory for more general libraries.
++//
++// Revision 1.1  1998/04/08 23:05:56  curt
++// Adopted Gnu automake/autoconf system.
++//
++// Revision 1.5  1998/03/19 02:50:19  curt
++// Updated to support -lDEM class.
++//
++// Revision 1.4  1998/03/03 16:00:57  curt
++// More c++ compile tweaks.
++//
++// Revision 1.3  1998/01/09 23:03:08  curt
++// Restructured to split 1deg x 1deg dem's into 64 subsections.
++//
++// Revision 1.2  1997/12/02 13:12:07  curt
++// Updated to fix every node.
++//
++// Revision 1.1  1997/11/27 00:17:33  curt
++// Initial revision.
++//
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..80b6eb2b6773f3c2e8b53291b62b6a2137fd0248
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,95 @@@
++// fixnode.hxx -- traverse the node file and fix the elevation of all the new
++//                interpolated points.
++//
++// Written by Curtis Olson, started November 1997.
++//
++// Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#ifndef _FIXNODE_H
++#define _FIXNODE_H
++
++
++#include <stdio.h>
++#include <string.h>
++#include <string>
++
++#include <vector>
++#include "Include/fg_stl_config.h"
++
++#ifdef NEEDNAMESPACESTD
++using namespace std;
++#endif
++
++#include <DEM/dem.hxx>
++#include <Math/point3d.hxx>
++
++
++typedef vector < Point3D > container;
++typedef container::iterator iterator;
++typedef container::const_iterator const_iterator;
++
++
++// Initialize a new mesh structure
++void load_nodes(const string& basename, container& node_list);
++
++
++// load the extra nodes.  These are always the first n nodes of the
++// .node file.  (???  These will be tagged with a code indicating what
++// needs to be done with this node's elevation such as adjust to local
++// DEM elevation, or massage the local DEM points to match this
++// elevation point. ???)
++void load_extra_nodes(const string& filename, container& node_list);
++
++
++// fix the node elevations
++void fix_nodes( const string& basename, fgDEM& dem, container& node_list );
++
++
++#endif // _FIXNODE_H
++
++
++// $Log$
++// Revision 1.4  1998/10/20 15:49:23  curt
++// Converted to Point3D class.
++//
++// Revision 1.3  1998/09/19 20:43:53  curt
++// C++-ified and STL-ified the code.  Combined triload.* and fixnode.* into
++// a single file.
++//
++// Revision 1.2  1998/07/22 21:46:41  curt
++// Fixed a bug that was triggering a seg fault.
++//
++// Revision 1.1  1998/04/08 23:05:56  curt
++// Adopted Gnu automake/autoconf system.
++//
++// Revision 1.4  1998/03/19 02:50:19  curt
++// Updated to support -lDEM class.
++//
++// Revision 1.3  1998/03/03 16:00:58  curt
++// More c++ compile tweaks.
++//
++// Revision 1.2  1997/12/02 13:12:07  curt
++// Updated to fix every node.
++//
++// Revision 1.1  1997/11/27 00:17:33  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..68e5408020461007cb7dd8033d825d315fe2a000
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,146 @@@
++// main.cxx -- read in a .node file and fix the z values of the interpolated 
++//             points
++//
++// Written by Curtis Olson, started November 1997.
++//
++// Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#include <sys/types.h>
++#include <dirent.h>
++// #include <stdio.h>
++#include <string.h>
++#include <string>
++
++#ifdef HAVE_STDLIB_H
++#  include <stdlib.h>
++#endif // HAVE_STDLIB_H
++
++#include <DEM/dem.hxx>
++
++#include "fixnode.hxx"
++
++
++// find all the matching files in the specified directory and fix them
++void process_files(const string& root_path, fgDEM& dem) {
++    container node_list;
++    DIR *d;
++    struct dirent *de;
++    string file_path;
++    char *ptr;
++    int len;
++
++    if ( (d = opendir( root_path.c_str() )) == NULL ) {
++        cout << "cannot open directory " + root_path + "\n";
++      exit(-1);
++    }
++
++    while ( (de = readdir(d)) != NULL ) {
++      len = strlen(de->d_name);
++      if ( len > 7 ) {
++          ptr = de->d_name;
++          ptr += (len - 7);
++          // printf("--> %s \n", ptr);
++
++          if ( strcmp(ptr, ".1.node") == 0 ) {
++              file_path =  root_path + "/" + de->d_name;
++              cout << "File = " + file_path + "\n";
++
++              // load the input data files
++              load_nodes(file_path, node_list);
++
++              fix_nodes(file_path, dem, node_list);
++          }
++      }
++    }
++}
++
++
++// main
++int main(int argc, char **argv) {
++    fgDEM dem;
++    string demfile, root_path;
++
++    if ( argc != 3 ) {
++      cout << "Usage " << argv[0] << " demfile root_path\n";
++      exit(-1);
++    }
++
++    cout << "Starting fixnode\n";
++
++    demfile = argv[1];
++    root_path = argv[2];
++
++    // load the corresponding dem file so we can interpolate elev values
++    dem.open(demfile);
++    dem.parse();
++    dem.close();
++
++    // process all the *.1.node files in the specified directory
++    process_files(root_path, dem);
++
++    return(0);
++}
++
++
++// $Log$
++// Revision 1.7  1998/09/19 20:43:54  curt
++// C++-ified and STL-ified the code.  Combined triload.* and fixnode.* into
++// a single file.
++//
++// Revision 1.6  1998/09/19 18:01:27  curt
++// Support for changes to libDEM.a
++//
++// Revision 1.5  1998/07/22 21:46:41  curt
++// Fixed a bug that was triggering a seg fault.
++//
++// Revision 1.4  1998/06/27 16:55:24  curt
++// Changed include order for <sys/types.h>
++//
++// Revision 1.3  1998/04/26 05:02:06  curt
++// Added #ifdef HAVE_STDLIB_H
++//
++// Revision 1.2  1998/04/14 02:26:04  curt
++// Code reorganizations.  Added a Lib/ directory for more general libraries.
++//
++// Revision 1.1  1998/04/08 23:05:57  curt
++// Adopted Gnu automake/autoconf system.
++//
++// Revision 1.6  1998/04/06 21:09:44  curt
++// Additional win32 support.
++// Fixed a bad bug in dem file parsing that was causing the output to be
++// flipped about x = y.
++//
++// Revision 1.5  1998/03/19 02:50:20  curt
++// Updated to support -lDEM class.
++//
++// Revision 1.4  1998/03/03 16:00:58  curt
++// More c++ compile tweaks.
++//
++// Revision 1.3  1998/01/09 23:03:08  curt
++// Restructured to split 1deg x 1deg dem's into 64 subsections.
++//
++// Revision 1.2  1997/12/02 13:12:07  curt
++// Updated to fix every node.
++//
++// Revision 1.1  1997/11/27 00:17:34  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7ced91cc9f6ba2470727a49726b810d98a07886e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,69 @@@
++#---------------------------------------------------------------------------
++# Makefile
++#
++# Written by Curtis Olson, started October 1997.
++#
++# Copyright (C) 1997 - 1998  Curtis L. Olson  - curt@me.umn.edu
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++# $Id$
++# (Log is kept at end of this file)
++#---------------------------------------------------------------------------
++
++
++bin_PROGRAMS = fixobj
++
++fixobj_SOURCES = main.cxx obj.cxx obj.hxx
++
++fixobj_LDADD = \
++      $(top_builddir)/Lib/Math/libMath.a \
++      $(top_builddir)/Lib/Debug/libDebug.a \
++      $(top_builddir)/Lib/zlib/libz.a \
++      $(base_LIBS)
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
++
++
++#---------------------------------------------------------------------------
++# $Log$
++# Revision 1.7  1998/11/04 23:01:53  curt
++# Changes to the automake/autoconf system to reduce the number of libraries
++# that are unnecessarily linked into the various executables.
++#
++# Revision 1.6  1998/07/30 23:49:25  curt
++# Removed libtool support.
++#
++# Revision 1.5  1998/06/08 17:11:44  curt
++# Renamed *.[ch] to *.[ch]xx
++#
++# Revision 1.4  1998/04/24 00:44:05  curt
++# Added zlib support.
++#
++# Revision 1.3  1998/04/18 04:01:02  curt
++# Now use libMath rather than having local copies of math routines.
++#
++# Revision 1.2  1998/04/14 02:26:05  curt
++# Code reorganizations.  Added a Lib/ directory for more general libraries.
++#
++# Revision 1.1  1998/04/08 23:19:35  curt
++# Adopted Gnu automake/autoconf system.
++#
++# Revision 1.2  1998/01/21 02:55:53  curt
++# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
++#
++# Revision 1.1  1997/12/08 19:28:54  curt
++# Initial revision.
++#
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bf117a10c1f2bb79b3ac796e4481b5ee3d4182a5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,57 @@@
++// main.cxx -- read and fix the stripping order of a .obj file
++//
++// Written by Curtis Olson, started December 1997.
++//
++// Copyright (C) 1997 - 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include <stdio.h>
++
++#include "obj.hxx"
++
++
++int main(int argc, char **argv) {
++    char infile[256], outfile[256];
++
++    if ( argc != 3 ) {
++      printf("Usage %s: infile outfile\n", argv[0]);
++    }
++
++    strcpy(infile, argv[1]);
++    strcpy(outfile, argv[2]);
++
++    // load the input data files
++    obj_fix(infile, outfile);
++
++    return(0);
++}
++
++
++// $Log$
++// Revision 1.1  1998/06/08 17:11:45  curt
++// Renamed *.[ch] to *.[ch]xx
++//
++// Revision 1.2  1998/01/09 23:03:12  curt
++// Restructured to split 1deg x 1deg dem's into 64 subsections.
++//
++// Revision 1.1  1997/12/08 19:28:54  curt
++// Initial revision.
++//
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4239a189139ea0bf0d818c997f8cf7acefaebf86
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,647 @@@
++// obj.cxx -- routines to handle WaveFront .obj format files.
++//
++// Written by Curtis Olson, started October 1997.
++//
++// Copyright (C) 1997 - 1998  Curtis L. Olson - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include <stdio.h>
++#include <iostream>
++#include <string.h>
++
++#include <vector>
++#include "Include/compiler.h"
++
++#ifdef NEEDNAMESPACESTD
++using namespace std;
++#endif
++
++#include "obj.hxx"
++
++#include <Math/mat3.h>
++#include <Math/point3d.hxx>
++
++
++typedef vector < Point3D > container3;
++typedef container3::iterator iterator3;
++typedef container3::const_iterator const_iterator3;
++
++
++// what do ya' know, here's some global variables
++container3 nodes;
++container3 normals;
++static int faces[MAXNODES][3];
++int vncount, fcount;
++
++static int ccw_list[MAXNODES];
++int ccw_list_ptr;
++
++static int cw_list[MAXNODES];
++int cw_list_ptr;
++
++FILE *in, *out;
++
++Point3D ref;
++
++
++// some simple list routines
++
++// reset the list
++void list_init(int *list_ptr) {
++    *list_ptr = 0;
++}
++
++
++// add to list
++void list_add(int *list, int *list_ptr, int node) {
++    if ( *list_ptr >= MAXNODES ) {
++      printf("ERROR: list overflow in list_add()\n");
++      exit(-1);
++    }
++
++    list[*list_ptr] = node;
++    *list_ptr += 1;
++
++    // printf("list pointer = %d  adding %d\n", *list_ptr, node);
++}
++
++
++// fix the cw list and append to ccw_list
++void fix_cw_list(int *list, int list_ptr) {
++    int i, j, len;
++
++    if ( list_ptr < 3 ) {
++      printf("List is empty ... skipping\n");
++      return;
++    }
++
++    printf("Fixing cw list, size = %d\n", list_ptr);
++
++    i = 0;
++    while ( i < list_ptr ) { 
++      // do next strip
++
++      // find length
++      len = 0;
++      // scan rest of strip (until -1)
++      while ( ((i+len) < list_ptr) && (list[i+len] != -1) ) { 
++          // printf("len = %d item = %d\n", len, list[i+len] );
++          len++;
++      }
++      // printf("          Final length = %d\n", len);
++
++      if ( (len % 2) != 0 ) {
++          // if length is odd, just reverse order of nodes to
++          // reverse winding
++          if ( ccw_list_ptr ) {
++              list_add(ccw_list, &ccw_list_ptr, -1);
++          }
++          for ( j = i + len - 1; j >= i; j-- ) {
++              // printf(" odd -> item = %d\n", list[j] );
++              list_add(ccw_list, &ccw_list_ptr, list[j]);
++          }
++      } else {
++          // if length is even, reverse order of (n-1) nodes to
++          // reverse winding, and create an orphan triangle for the
++          // last "nth" node
++          if ( ccw_list_ptr ) {
++              list_add(ccw_list, &ccw_list_ptr, -1);
++          }
++          for ( j = i + len - 2; j >= i; j-- ) {
++              // printf(" even -> item = %d\n", list[j] );
++              list_add(ccw_list, &ccw_list_ptr, list[j]);
++          }
++
++          // printf(" even bonus -> item = %d\n", list[i + len - 1] );
++          // printf(" even bonus -> item = %d\n", list[i + len - 2] );
++          // printf(" even bonus -> item = %d\n", list[i + len - 3] );
++          list_add(ccw_list, &ccw_list_ptr, -1);
++          list_add(ccw_list, &ccw_list_ptr, list[i + len - 3]);
++          list_add(ccw_list, &ccw_list_ptr, list[i + len - 2]);
++          list_add(ccw_list, &ccw_list_ptr, list[i + len - 1]);
++      }
++
++      i += len + 1;
++    }
++}
++
++
++void dump_global_bounds( void ) {
++    double dist_squared, radius, radius_squared;
++
++    radius = 0.0;
++
++    fprintf(out, "\n");
++
++    
++    iterator3 current = nodes.begin();
++    iterator3 last = nodes.end();
++
++    // skip first dummy node
++    ++current;
++
++    for ( ; current != last; ++current ) {
++      dist_squared = ref.distance3Dsquared(*current);
++      // cout << "node = " << *current << " dist = " << dist_squared << endl;
++
++      if ( dist_squared > radius_squared ) {
++          radius_squared = dist_squared;
++      }
++    }
++
++    radius = sqrt(radius_squared);
++
++    fprintf( out, 
++           "gbs %.5f %.5f %.5f %.2f\n", 
++           ref.x(), ref.y(), ref.z(), radius);
++}
++
++
++// dump nodes
++void dump_nodes( void ) {
++    Point3D p;
++
++    fprintf(out, "\n");
++
++    iterator3 current = nodes.begin();
++    iterator3 last = nodes.end();
++
++    // skip first dummy node
++    ++current;
++
++    for ( ; current != last; ++current ) {
++      p = *current - ref;
++      fprintf( out, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
++    }
++}
++
++
++// dump normals
++void dump_normals( void ) {
++    Point3D p;
++
++    fprintf(out, "\n");
++
++    iterator3 current = normals.begin();
++    iterator3 last = normals.end();
++
++    // skip first dummy normal
++    ++current;
++
++    for ( ; current != last; ++current ) {
++      p = *current;
++      fprintf(out, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
++    }
++}
++
++
++// dump faces
++void dump_faces( void ) {
++    Point3D p;
++    int i, n1, n2, n3;
++    double xmax, xmin, ymax, ymin, zmax, zmin, dist, radius;
++
++    fprintf(out, "\n");
++    for ( i = 1; i < fcount; i++ ) {
++      n1 = faces[i][0];
++      n2 = faces[i][1];
++      n3 = faces[i][2];
++
++      // calc center of face
++      xmin = xmax = nodes[n1].x();
++      ymin = ymax = nodes[n1].y();
++      zmin = zmax = nodes[n1].z();
++
++      if ( nodes[n2].x() < xmin ) { xmin = nodes[n2].x(); }
++      if ( nodes[n2].x() > xmax ) { xmax = nodes[n2].x(); }
++      if ( nodes[n2].y() < ymin ) { ymin = nodes[n2].y(); }
++      if ( nodes[n2].y() > ymax ) { ymax = nodes[n2].y(); }
++      if ( nodes[n2].z() < zmin ) { zmin = nodes[n2].z(); }
++      if ( nodes[n2].z() > zmax ) { zmax = nodes[n2].z(); }
++
++      if ( nodes[n3].x() < xmin ) { xmin = nodes[n3].x(); }
++      if ( nodes[n3].x() > xmax ) { xmax = nodes[n3].x(); }
++      if ( nodes[n3].y() < ymin ) { ymin = nodes[n3].y(); }
++      if ( nodes[n3].y() > ymax ) { ymax = nodes[n3].y(); }
++      if ( nodes[n3].z() < zmin ) { zmin = nodes[n3].z(); }
++      if ( nodes[n3].z() > zmax ) { zmax = nodes[n3].z(); }
++
++      p = Point3D( (xmin + xmax) / 2.0,
++                   (ymin + ymax) / 2.0,
++                   (zmin + zmax) / 2.0 );
++
++      // calc bounding radius
++      radius = p.distance3D(nodes[n1]);
++
++      dist = p.distance3D(nodes[n2]);
++      if ( dist > radius ) { radius = dist; }
++
++      dist = p.distance3D(nodes[n3]);
++      if ( dist > radius ) { radius = dist; }
++      
++      // output data
++      fprintf(out, "bs %.2f %.2f %.2f %.2f\n", p.x(), p.y(), p.z(), radius);
++      fprintf(out, "f %d %d %d\n", n1, n2, n3);
++    }
++}
++
++
++// dump list
++void dump_list(int *list, int list_ptr) {
++    Point3D p;
++    double xmax, xmin, ymax, ymin, zmax, zmin, dist_squared, radius_squared;
++    double radius;
++    int i, j, len, n;
++
++    if ( list_ptr < 3 ) {
++      printf("List is empty ... skipping\n");
++      return;
++    }
++
++    printf("Dumping list, size = %d\n", list_ptr);
++
++    i = 0;
++    while ( i < list_ptr ) { 
++      // do next strip
++
++      if ( (i % 2) == 0 ) {
++          fprintf(out, "\nusemtl desert1\n");
++      } else {
++          fprintf(out, "\nusemtl desert2\n");
++      }
++
++      // find length of next tri strip
++      len = 0;
++      // scan rest of strip (until -1)
++      while ( ((i+len) < list_ptr) && (list[i+len] != -1) ) { 
++          // printf("len = %d item = %d\n", len, list[i+len] );
++          len++;
++      }
++      // printf("strip length = %d\n", len);
++
++      // calc center of face
++      n = list[i];
++      xmin = xmax = nodes[n].x();
++      ymin = ymax = nodes[n].y();
++      zmin = zmax = nodes[n].z();
++      // printf("%.2f %.2f %.2f\n", nodes[n].x(), nodes[n].y(), nodes[n].z());
++
++      for ( j = i + 1; j < i + len; j++ ) {
++          // printf("j = %d\n", j);
++          n = list[j];
++          if ( nodes[n].x() < xmin ) { xmin = nodes[n].x(); }
++          if ( nodes[n].x() > xmax ) { xmax = nodes[n].x(); }
++          if ( nodes[n].y() < ymin ) { ymin = nodes[n].y(); }
++          if ( nodes[n].y() > ymax ) { ymax = nodes[n].y(); }
++          if ( nodes[n].z() < zmin ) { zmin = nodes[n].z(); }
++          if ( nodes[n].z() > zmax ) { zmax = nodes[n].z(); }
++          // printf("%.2f %.2f %.2f\n", nodes[n].x(), nodes[n].y(), nodes[n].z());
++      }
++      p = Point3D( (xmin + xmax) / 2.0,
++                   (ymin + ymax) / 2.0,
++                   (zmin + zmax) / 2.0 );
++      // printf("center = %.2f %.2f %.2f\n", p.x(), p.y(), p.z());
++
++      // calc bounding radius
++      n = list[i];
++      radius_squared = p.distance3Dsquared(nodes[n]);
++
++      for ( j = i + 1; j < i + len; j++ ) {
++          n = list[j];
++          dist_squared = p.distance3Dsquared(nodes[n]);
++          if ( dist_squared > radius_squared ) {
++              radius_squared = dist_squared;
++          }
++      }
++      radius = sqrt(radius_squared);
++
++      // printf("radius = %.2f\n", radius);
++
++      // dump bounding sphere and header
++      fprintf(out, "bs %.2f %.2f %.2f %.2f\n", p.x(), p.y(), p.z(), radius);
++      fprintf(out, "t %d %d %d\n", list[i], list[i+1], list[i+2]);
++      // printf("t %d %d %d\n", list[i], list[i+1], list[i+2]);
++      i += 3;
++
++      // dump rest of strip (until -1)
++      while ( (i < list_ptr) && (list[i] != -1) ) { 
++          fprintf(out, "q %d", list[i]);
++          i++;
++          if ( (i < list_ptr) && (list[i] != -1) ) { 
++              fprintf(out, " %d", list[i]);
++              i++;
++          }
++          fprintf(out, "\n");
++      }
++
++      i++;
++    }
++}
++
++
++// Check the direction the current triangle faces, compared to it's
++// pregenerated normal.  Returns the dot product between the target
++// normal and actual normal.  If the dot product is close to 1.0, they
++// nearly match.  If the are close to -1.0, the are nearly opposite.
++double check_cur_face(int n1, int n2, int n3) {
++    double v1[3], v2[3], approx_normal[3], dot_prod, temp;
++
++    // check for the proper rotation by calculating an approximate
++    // normal and seeing if it is close to the precalculated normal
++    v1[0] = nodes[n2].x() - nodes[n1].x();
++    v1[1] = nodes[n2].y() - nodes[n1].y();
++    v1[2] = nodes[n2].z() - nodes[n1].z();
++    v2[0] = nodes[n3].x() - nodes[n1].x();
++    v2[1] = nodes[n3].y() - nodes[n1].y();
++    v2[2] = nodes[n3].z() - nodes[n1].z();
++
++    MAT3cross_product(approx_normal, v1, v2);
++    MAT3_NORMALIZE_VEC(approx_normal,temp);
++    dot_prod = MAT3_DOT_PRODUCT(normals[n1], approx_normal);
++
++    // not first triangle
++    // if ( ((dot_prod < -0.5) && !is_backwards) ||
++    //     ((dot_prod >  0.5) && is_backwards) ) {
++    //     printf("    Approx normal = %.2f %.2f %.2f\n", approx_normal[0], 
++    //            approx_normal[1], approx_normal[2]);
++    //     printf("    Dot product = %.4f\n", dot_prod);
++    // }
++    // angle = acos(dot_prod);
++    // printf("Normal ANGLE = %.3f rads.\n", angle);
++
++    return(dot_prod);
++}
++
++
++// Load a .obj file
++void obj_fix(char *infile, char *outfile) {
++    Point3D node, normal;
++    char line[256];
++    double dot_prod;
++    int first, n1, n2, n3, n4;
++    double x, y, z, xmax, xmin, ymax, ymin, zmax, zmin;
++    int is_ccw;
++
++    if ( (in = fopen(infile, "r")) == NULL ) {
++      printf("Cannot open file: %s\n", infile);
++      exit(-1);
++    }
++
++    if ( (out = fopen(outfile, "w")) == NULL ) {
++      printf("Cannot open file: %s\n", outfile);
++      exit(-1);
++    }
++
++    // push dummy records onto the lists since we start counting with "1"
++    node = Point3D(0.0, 0.0, 0.0);
++    nodes.push_back(node);
++
++    normal = Point3D(0.0, 0.0, 0.0);
++    normals.push_back(normal);
++
++    // initialize other lists
++    list_init(&ccw_list_ptr);
++    list_init(&cw_list_ptr);
++
++    // I start counting at one because that is how the triangle
++    // program refers to nodes and normals
++    first = 1;
++    vncount = 1;
++    fcount = 1;
++
++    printf("Reading file:  %s\n", infile);
++
++    while ( fgets(line, 250, in) != NULL ) {
++      if ( line[0] == '#' ) {
++          // pass along the comments verbatim
++          fprintf(out, "%s", line);
++      } else if ( strlen(line) <= 1 ) {
++          // don't pass along empty lines
++          // fprintf(out, "%s", line);
++      } else if ( strncmp(line, "v ", 2) == 0 ) {
++          // save vertex to memory and output to file
++          // printf("vertex = %s", line);
++          sscanf(line, "v %lf %lf %lf\n", &x, &y, &z);
++
++          if ( nodes.size() == 1 ) {
++              // first time through set min's and max'es
++              xmin = x;
++              xmax = x;
++              ymin = y;
++              ymax = y;
++              zmin = z;
++              zmax = z;
++          } else {
++              // update min/max vertex values
++              if ( x < xmin ) xmin = x;
++              if ( x > xmax ) xmax = x;
++              if ( y < ymin ) ymin = y;
++              if ( y > ymax ) ymax = y;
++              if ( z < zmin ) zmin = z;
++              if ( z > zmax ) zmax = z;               
++          }
++
++          node = Point3D(x, y, z);
++          nodes.push_back(node);
++          // fprintf(out, "v %.2f %.2f %.2f\n", 
++          //       node.x(), node.y(), node.z());
++      } else if ( strncmp(line, "vn ", 3) == 0 ) {
++          // save vertex normals to memory and output to file
++          // printf("vertex normal = %s", line);
++          sscanf(line, "vn %lf %lf %lf\n", &x, &y, &z);
++          normal = Point3D(x, y, z);
++          normals.push_back(normal);
++      } else if ( line[0] == 't' ) {
++          // starting a new triangle strip
++
++          printf("Starting a new triangle strip\n");
++
++          n1 = n2 = n3 = n4 = 0;
++
++          printf("new tri strip = %s", line);
++          sscanf(line, "t %d %d %d %d\n", &n1, &n2, &n3, &n4);
++
++          // special cases to handle bugs in our beloved tri striper
++          if ( (n1 == 4) && (n2 == 2) && (n3 == 2) && (n4 == 1) ) {
++              n2 = 3;
++          }
++          if ( (n1 == 3) && (n2 == 1) && (n3 == 1) && (n4 == 0) ) {
++              n3 = 4;
++          }
++
++          dot_prod = check_cur_face(n1, n2, n3);
++          if ( dot_prod < 0.0 ) {
++              // this stripe is backwards (CW)
++              is_ccw = 0;
++              printf(" -> Starting a backwards stripe\n");
++          } else {
++              // this stripe is normal (CCW)
++              is_ccw = 1;
++          }
++
++          if ( is_ccw ) {
++              if ( ccw_list_ptr ) {
++                  list_add(ccw_list, &ccw_list_ptr, -1);
++              }
++
++              list_add(ccw_list, &ccw_list_ptr, n1);
++              list_add(ccw_list, &ccw_list_ptr, n2);
++              list_add(ccw_list, &ccw_list_ptr, n3);
++          } else {
++              if ( cw_list_ptr ) {
++                  list_add(cw_list, &cw_list_ptr, -1);
++              }
++
++              list_add(cw_list, &cw_list_ptr, n1);
++              list_add(cw_list, &cw_list_ptr, n2);
++              list_add(cw_list, &cw_list_ptr, n3);
++          }
++
++          if ( n4 > 0 ) {
++              if ( is_ccw ) {
++                  list_add(ccw_list, &ccw_list_ptr, n4);
++              } else {
++                  list_add(cw_list, &cw_list_ptr, n4);
++              }
++          }
++      } else if ( line[0] == 'f' ) {
++          if ( fcount < MAXNODES ) {
++              // pass along the unoptimized faces verbatim
++              sscanf(line, "f %d %d %d\n", &n1, &n2, &n3);
++              faces[fcount][0] = n1;
++              faces[fcount][1] = n2;
++              faces[fcount][2] = n3;
++
++              fcount++;
++          } else {
++              printf("Read too many unoptimized faces ... dying :-(\n");
++                exit(-1);
++          }
++ 
++          // fprintf(out, "%s", line);
++      } else if ( line[0] == 'q' ) {
++          // continue a triangle strip
++          n1 = n2 = 0;
++
++          // printf("continued tri strip = %s ", line);
++          sscanf(line, "q %d %d\n", &n1, &n2);
++
++          if ( is_ccw ) {
++              list_add(ccw_list, &ccw_list_ptr, n1);
++          } else {
++              list_add(cw_list, &cw_list_ptr, n1);
++          }
++
++          if ( n2 > 0 ) {
++              if ( is_ccw ) {
++                  list_add(ccw_list, &ccw_list_ptr, n2);
++              } else {
++                  list_add(cw_list, &cw_list_ptr, n2);
++              }
++          }
++      } else {
++          printf("Unknown line in %s = %s\n", infile, line);
++      }
++    }
++
++    // reference point is the "center"
++    ref = Point3D( (xmin + xmax) / 2.0,
++                 (ymin + ymax) / 2.0,
++                 (zmin + zmax) / 2.0 );
++
++    // convert the cw_list to ccw add append to ccw_list
++    fix_cw_list(cw_list, cw_list_ptr);
++
++    dump_global_bounds();
++    dump_nodes();
++    dump_normals();
++    if ( fcount > 1 ) {
++      dump_faces();
++    }
++
++    dump_list(ccw_list, ccw_list_ptr);
++
++    fclose(in);
++    fclose(out);
++}
++
++
++// $Log$
++// Revision 1.3  1999/02/01 21:09:40  curt
++// Optimizations from Norman Vine.
++//
++// Revision 1.2  1998/10/21 14:55:55  curt
++// Converted to Point3D class.
++//
++// Revision 1.1  1998/06/08 17:11:46  curt
++// Renamed *.[ch] to *.[ch]xx
++//
++// Revision 1.16  1998/05/27 02:27:22  curt
++// Commented out a couple of debugging messages.
++//
++// Revision 1.15  1998/05/24 02:47:47  curt
++// For each strip, specify a default material property and calculate a center
++// and bounding sphere.
++//
++// Revision 1.14  1998/05/23 15:19:49  curt
++// Output more digits after the decimal place.
++//
++// Revision 1.13  1998/05/20 20:55:19  curt
++// Fixed arbitrary polygon winding problem here so all tristrips are passed
++// to runtime simulator with a consistant counter clockwise winding.
++//
++// Revision 1.12  1998/05/16 13:11:26  curt
++// Fixed an off by one error in node, normal, and face counters.
++//
++// Revision 1.11  1998/04/27 15:59:24  curt
++// Fixed an off by one error.
++//
++// Revision 1.10  1998/04/27 03:33:11  curt
++// Code now calculates a center reference points and outputs everything
++// relative to that.  This is useful in the rendering engine to keep everything
++// close to (0, 0, 0) where we can avoid many GLfloat precision problems.
++//
++// Revision 1.9  1998/04/18 04:01:03  curt
++// Now use libMath rather than having local copies of math routines.
++//
++// Revision 1.8  1998/04/08 23:19:37  curt
++// Adopted Gnu automake/autoconf system.
++//
++// Revision 1.7  1998/03/19 02:51:41  curt
++// Added special case handling to compensate for bugs in our beloved tri striper
++//
++// Revision 1.6  1998/03/03 15:36:12  curt
++// Tweaks for compiling with g++
++//
++// Revision 1.5  1998/03/03 03:37:03  curt
++// Cumulative tweaks.
++//
++// Revision 1.4  1998/01/31 00:41:25  curt
++// Made a few changes converting floats to doubles.
++//
++// Revision 1.3  1998/01/19 19:51:07  curt
++// A couple final pre-release tweaks.
++//
++// Revision 1.2  1998/01/09 23:03:12  curt
++// Restructured to split 1deg x 1deg dem's into 64 subsections.
++//
++// Revision 1.1  1997/12/08 19:28:54  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..59a362c8d66dc3083605f9cdd68f9b697d278fcc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,60 @@@
++// obj.hxx -- routines to handle WaveFront .obj format files.
++//
++// Written by Curtis Olson, started October 1997.
++//
++// Copyright (C) 1997 - 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef OBJ_HXX
++#define OBJ_HXX
++
++
++#ifndef __cplusplus                                                          
++# error This library requires C++
++#endif                                   
++
++
++#define MAXNODES 100000
++
++
++// Load a .obj file
++void obj_fix(char *infile, char *outfile);
++
++
++#endif // OBJ_HXX
++
++
++// $Log$
++// Revision 1.1  1998/06/08 17:11:46  curt
++// Renamed *.[ch] to *.[ch]xx
++//
++// Revision 1.4  1998/03/03 15:36:13  curt
++// Tweaks for compiling with g++
++//
++// Revision 1.3  1998/01/31 00:41:25  curt
++// Made a few changes converting floats to doubles.
++//
++// Revision 1.2  1998/01/09 23:03:13  curt
++// Restructured to split 1deg x 1deg dem's into 64 subsections.
++//
++// Revision 1.1  1997/12/08 19:28:55  curt
++// Initial revision.
++//
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..86c8ecb162e909cdd1d5ef1ccf329bd82b6c343a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,86 @@@
++#---------------------------------------------------------------------------
++# Makefile
++#
++# Written by Curtis Olson, started January 1998.
++#
++# Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++# $Id$
++# (Log is kept at end of this file)
++#---------------------------------------------------------------------------
++
++
++bin_PROGRAMS = genapts
++
++genapts_SOURCES = \
++      area.cxx area.hxx \
++      convex_hull.cxx convex_hull.hxx \
++      main.cxx \
++      point2d.cxx point2d.hxx
++
++genapts_LDADD = \
++      $(top_builddir)/Tools/Lib/Polygon/libPolygon.a \
++      $(top_builddir)/Lib/Bucket/libBucket.a \
++      $(top_builddir)/Lib/Debug/libDebug.a \
++      $(top_builddir)/Lib/Misc/libMisc.a \
++      $(top_builddir)/Lib/zlib/libz.a \
++      $(base_LIBS)
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib
++
++
++#---------------------------------------------------------------------------
++# $Log$
++# Revision 1.6  1999/03/08 22:00:47  curt
++# Lots of directory layout reorganization.
++#
++# Revision 1.5  1999/02/25 21:32:47  curt
++# Modified to adhere to new polygon naming convention, and also to read the
++# new Robin Peel aiport format.
++#
++# Revision 1.4  1999/02/11 01:10:50  curt
++# Start of scenery revamp project.
++#
++# Revision 1.3  1998/11/04 23:01:54  curt
++# Changes to the automake/autoconf system to reduce the number of libraries
++# that are unnecessarily linked into the various executables.
++#
++# Revision 1.2  1998/09/04 23:04:47  curt
++# Beginning of convex hull genereration routine.
++#
++# Revision 1.1  1998/09/01 19:34:32  curt
++# Initial revision.
++#
++# Revision 1.2  1998/07/30 23:49:18  curt
++# Removed libtool support.
++#
++# Revision 1.1  1998/07/20 12:54:53  curt
++# Whoops, need to commit Makefile.am, not Makefile.
++#
++# Revision 1.2  1998/04/14 02:25:59  curt
++# Code reorganizations.  Added a Lib/ directory for more general libraries.
++#
++# Revision 1.1  1998/04/08 22:54:57  curt
++# Adopted Gnu automake/autoconf system.
++#
++# Revision 1.2  1998/01/21 02:55:46  curt
++# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
++#
++# Revision 1.1  1998/01/15 02:45:25  curt
++# Initial revision.
++#
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..75d785377be8805c662d9b645fc717e49b2fdf29
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,241 @@@
++// area.c -- routines to assist with inserting "areas" into FG terrain
++//
++// Written by Curtis Olson, started March 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#include <math.h>
++#include <stdio.h>
++
++#include <Include/fg_constants.h>
++
++#include "area.hxx"
++#include "point2d.hxx"
++
++
++// calc new x, y for a rotation
++double rot_x(double x, double y, double theta) {
++    return ( x * cos(theta) + y * sin(theta) );
++}
++
++
++// calc new x, y for a rotation
++double rot_y(double x, double y, double theta) {
++    return ( -x * sin(theta) + y * cos(theta) );
++}
++
++
++// calc new lon/lat given starting lon/lat, and offset radial, and
++// distance.  NOTE: distance is specified in meters (and converted
++// internally to radians)
++point2d calc_lon_lat( point2d orig, point2d offset ) {
++    point2d result;
++
++    // printf("calc_lon_lat()  offset.theta = %.2f offset.dist = %.2f\n",
++    //        offset.theta, offset.dist);
++
++    offset.dist *= METER_TO_NM * NM_TO_RAD;
++
++    result.lat = asin( sin(orig.lat) * cos(offset.dist) + 
++                     cos(orig.lat) * sin(offset.dist) * cos(offset.theta) );
++
++    if ( cos(result.lat) < FG_EPSILON ) {
++        result.lon = orig.lon;      // endpoint a pole
++    } else {
++        result.lon = 
++          fmod(orig.lon - asin( sin(offset.theta) * sin(offset.dist) / 
++                                cos(result.lat) ) + FG_PI, FG_2PI) - FG_PI;
++    }
++
++    return(result);
++}
++
++
++list < point2d >
++batch_cart_to_polar_2d( list < point2d > in_list)
++{
++    list < point2d > out_list;
++    list < point2d > :: iterator current;                          
++    list < point2d > :: iterator last;                    
++    point2d p;
++
++    current = in_list.begin();
++    last = in_list.end();
++    for ( ; current != last ; ++current ) {
++      p = cart_to_polar_2d( *current );
++      out_list.push_back(p);
++    }
++
++    return out_list;
++}
++
++
++// given a set of 2d coordinates relative to a center point, and the
++// lon, lat of that center point (specified in degrees), as well as a
++// potential orientation angle, generate the corresponding lon and lat
++// of the original 2d verticies.
++list < point2d >
++gen_area(point2d origin, double angle, list < point2d > cart_list)
++{
++    list < point2d > rad_list;
++    list < point2d > result_list;
++    list < point2d > :: iterator current;                          
++    list < point2d > :: iterator last;                    
++    point2d origin_rad, p;
++
++    origin_rad.lon = origin.lon * DEG_TO_RAD;
++    origin_rad.lat = origin.lat * DEG_TO_RAD;
++      
++    // convert to polar coordinates
++    rad_list = batch_cart_to_polar_2d(cart_list);
++
++    /*
++    // display points
++    printf("converted to polar\n");
++    current = rad_list.begin();
++    last = rad_list.end();
++    while ( current != last ) {
++      printf("(%.2f, %.2f)\n", current->theta, current->dist);
++      ++current;
++    }
++    printf("\n");
++    */
++
++    // rotate by specified angle
++    // printf("Rotating points by %.2f\n", angle);
++    current = rad_list.begin();
++    last = rad_list.end();
++    for ( ; current != last ; ++current ) {
++        current->theta -= angle;
++        while ( current->theta > FG_2PI ) {
++            current->theta -= FG_2PI;
++      // (*current).theta -= angle;
++      // while ( (*current).theta > FG_2PI ) {
++      //     (*current).theta -= FG_2PI;
++      }
++      // printf("(%.2f, %.2f)\n", current->theta, current->dist);
++    }
++    // printf("\n");
++
++    // find actual lon,lat of coordinates
++    // printf("convert to lon, lat relative to %.2f %.2f\n", 
++    //        origin.lon, origin.lat);
++    current = rad_list.begin();
++    last = rad_list.end();
++    for ( ; current != last ; ++current ) {
++      p = calc_lon_lat(origin_rad, *current);
++      // convert from radians to degress
++      p.lon *= RAD_TO_DEG;
++      p.lat *= RAD_TO_DEG;
++      // printf("(%.8f, %.8f)\n", p.lon, p.lat);
++      result_list.push_back(p);
++    }
++    // printf("\n");
++
++    return result_list;
++}
++
++
++// generate an area for a runway
++list < point2d >
++gen_runway_area( double lon, double lat, double heading, 
++                    double length, double width) 
++{
++    list < point2d > result_list;
++    list < point2d > tmp_list;
++    list < point2d > :: iterator current;                          
++    list < point2d > :: iterator last;                    
++
++    point2d p;
++    point2d origin;
++    double l, w;
++    int i;
++
++    /*
++    printf("runway: lon = %.2f lat = %.2f hdg = %.2f len = %.2f width = %.2f\n",
++         lon, lat, heading, length, width);
++    */
++
++    origin.lon = lon;
++    origin.lat = lat;
++    l = length / 2.0;
++    w = width / 2.0;
++
++    // generate untransformed runway area vertices
++    p.x =  l; p.y =  w; tmp_list.push_back(p);
++    p.x =  l; p.y = -w; tmp_list.push_back(p);
++    p.x = -l; p.y = -w; tmp_list.push_back(p);
++    p.x = -l; p.y =  w; tmp_list.push_back(p);
++
++    /*
++    // display points
++    printf("Untransformed, unrotated runway\n");
++    current = tmp_list.begin();
++    last = tmp_list.end();
++    while ( current != last ) {
++      printf("(%.2f, %.2f)\n", current->x, current->y);
++      ++current;
++    }
++    printf("\n");
++    */
++
++    // rotate, transform, and convert points to lon, lat in degrees
++    result_list = gen_area(origin, heading, tmp_list);
++
++    /*
++    // display points
++    printf("Results in radians.\n");
++    current = result_list.begin();
++    last = result_list.end();
++    while ( current != last ) {
++      printf("(%.8f, %.8f)\n", current->lon, current->lat);
++      ++current;
++    }
++    printf("\n");
++    */
++
++    return result_list;
++}
++
++
++// $Log$
++// Revision 1.5  1998/10/20 15:49:54  curt
++// tweak ...
++//
++// Revision 1.4  1998/09/09 20:59:53  curt
++// Loop construct tweaks for STL usage.
++// Output airport file to be used to generate airport scenery on the fly
++//   by the run time sim.
++//
++// Revision 1.3  1998/09/09 16:26:31  curt
++// Continued progress in implementing the convex hull algorithm.
++//
++// Revision 1.2  1998/09/04 23:04:48  curt
++// Beginning of convex hull genereration routine.
++//
++// Revision 1.1  1998/09/01 19:34:33  curt
++// Initial revision.
++//
++// Revision 1.1  1998/07/20 12:54:05  curt
++// Initial revision.
++//
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a1bbd342e436a8b937e46ccbca5e40097076062b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,54 @@@
++// area.h -- routines to assist with inserting "areas" into FG terrain
++//
++// Written by Curtis Olson, started February 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#ifndef _AREA_H
++#define _AREA_H
++
++
++#include <list>
++
++#include "point2d.hxx"
++
++
++// generate an area for a runway (return result points in degrees)
++list < point2d >
++gen_runway_area( double lon, double lat, double heading, 
++                    double length, double width);
++
++
++#endif // _AREA_H
++
++
++// $Log$
++// Revision 1.2  1998/09/04 23:04:49  curt
++// Beginning of convex hull genereration routine.
++//
++// Revision 1.1  1998/09/01 19:34:33  curt
++// Initial revision.
++//
++// Revision 1.1  1998/07/20 12:54:05  curt
++// Initial revision.
++//
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0cdff1dcb3f5b242a072ebccd7f4e303d20dcc0d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,277 @@@
++// convex_hull.cxx -- calculate the convex hull of a set of points
++//
++// Written by Curtis Olson, started September 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#include <math.h>
++#include <stdio.h>
++
++#include <list>
++#include <map>
++
++#ifdef NEEDNAMESPACESTD
++using namespace std;
++#endif
++
++#include <Include/fg_constants.h>
++
++#include "convex_hull.hxx"
++#include "point2d.hxx"
++
++
++// stl map typedefs
++typedef map < double, double, less<double> > map_container;
++typedef map_container::iterator map_iterator;
++
++
++// Calculate theta of angle (a, b, c)
++double calc_angle(point2d a, point2d b, point2d c) {
++    point2d u, v;
++    double udist, vdist, uv_dot, tmp;
++
++    // u . v = ||u|| * ||v|| * cos(theta)
++
++    u.x = b.x - a.x;
++    u.y = b.y - a.y;
++    udist = sqrt( u.x * u.x + u.y * u.y );
++    // printf("udist = %.6f\n", udist);
++
++    v.x = b.x - c.x;
++    v.y = b.y - c.y;
++    vdist = sqrt( v.x * v.x + v.y * v.y );
++    // printf("vdist = %.6f\n", vdist);
++
++    uv_dot = u.x * v.x + u.y * v.y;
++    // printf("uv_dot = %.6f\n", uv_dot);
++
++    tmp = uv_dot / (udist * vdist);
++    // printf("tmp = %.6f\n", tmp);
++
++    return acos(tmp);
++}
++
++
++// Test to see if angle(Pa, Pb, Pc) < 180 degrees
++bool test_point(point2d Pa, point2d Pb, point2d Pc) {
++    point2d origin, a, b, c;
++    double a1, a2;
++
++    origin.x = origin.y = 0.0;
++
++    a.x = cos(Pa.theta) * Pa.dist;
++    a.y = sin(Pa.theta) * Pa.dist;
++
++    b.x = cos(Pb.theta) * Pb.dist;
++    b.y = sin(Pb.theta) * Pb.dist;
++
++    c.x = cos(Pc.theta) * Pc.dist;
++    c.y = sin(Pc.theta) * Pc.dist;
++
++    // printf("a is %.6f %.6f\n", a.x, a.y);
++    // printf("b is %.6f %.6f\n", b.x, b.y);
++    // printf("c is %.6f %.6f\n", c.x, c.y);
++
++    a1 = calc_angle(a, b, origin);
++    a2 = calc_angle(origin, b, c);
++
++    // printf("a1 = %.2f  a2 = %.2f\n", a1 * RAD_TO_DEG, a2 * RAD_TO_DEG);
++
++    return ( (a1 + a2) < FG_PI );
++}
++
++
++// calculate the convex hull of a set of points, return as a list of
++// point2d.  The algorithm description can be found at:
++// http://riot.ieor.berkeley.edu/riot/Applications/ConvexHull/CHDetails.html
++list_container convex_hull( list_container input_list )
++{
++    list_iterator current, last;
++    map_iterator map_current, map_next, map_next_next, map_last;
++
++    // list of translated points
++    list_container trans_list;
++
++    // points sorted by radian degrees
++    map_container radians_map;
++
++    // will contain the convex hull
++    list_container con_hull;
++
++    point2d p, average, Pa, Pb, Pc, result;
++    double sum_x, sum_y;
++    int in_count, last_size;
++
++    // STEP ONE:  Find an average midpoint of the input set of points
++    current = input_list.begin();
++    last = input_list.end();
++    in_count = input_list.size();
++    sum_x = sum_y = 0.0;
++
++    for ( ; current != last ; ++current ) {
++      sum_x += (*current).x;
++      sum_y += (*current).y;
++    }
++
++    average.x = sum_x / in_count;
++    average.y = sum_y / in_count;
++
++    // printf("Average center point is %.4f %.4f\n", average.x, average.y);
++
++    // STEP TWO:  Translate input points so average is at origin
++    current = input_list.begin();
++    last = input_list.end();
++    trans_list.erase( trans_list.begin(), trans_list.end() );
++
++    for ( ; current != last ; ++current ) {
++      p.x = (*current).x - average.x;
++      p.y = (*current).y - average.y;
++      // printf("%.6f %.6f\n", p.x, p.y);
++      trans_list.push_back(p);
++    }
++
++    // STEP THREE:  convert to radians and sort by theta
++    current = trans_list.begin();
++    last = trans_list.end();
++    radians_map.erase( radians_map.begin(), radians_map.end() );
++
++    for ( ; current != last ; ++current) {
++      p = cart_to_polar_2d(*current);
++      if ( p.dist > radians_map[p.theta] ) {
++          radians_map[p.theta] = p.dist;
++      }
++    }
++
++    // printf("Sorted list\n");
++    map_current = radians_map.begin();
++    map_last = radians_map.end();
++    for ( ; map_current != map_last ; ++map_current ) {
++      p.x = (*map_current).first;
++      p.y = (*map_current).second;
++
++      // printf("p is %.6f %.6f\n", p.x, p.y);
++    }
++
++    // STEP FOUR: traverse the sorted list and eliminate everything
++    // not on the perimeter.
++    // printf("Traversing list\n");
++
++    // double check list size ... this should never fail because a
++    // single runway will always generate four points.
++    if ( radians_map.size() < 3 ) {
++      cout << "convex hull not possible with < 3 points" << endl;
++      exit(-1);
++    }
++
++    // ensure that we run the while loop at least once
++    last_size = radians_map.size() + 1;
++
++    while ( last_size > radians_map.size() ) {
++      // printf("Running an iteration of the graham scan algorithm\n"); 
++      last_size = radians_map.size();
++
++      map_current = radians_map.begin();
++      while ( map_current != radians_map.end() ) {
++          // get first element
++          Pa.theta = (*map_current).first;
++          Pa.dist = (*map_current).second;
++
++          // get second element
++          map_next = map_current;
++          ++map_next;
++          if ( map_next == radians_map.end() ) {
++              map_next = radians_map.begin();
++          }
++          Pb.theta = (*map_next).first;
++          Pb.dist = (*map_next).second;
++
++          // get third element
++          map_next_next = map_next;
++          ++map_next_next;
++          if ( map_next_next == radians_map.end() ) {
++              map_next_next = radians_map.begin();
++          }
++          Pc.theta = (*map_next_next).first;
++          Pc.dist = (*map_next_next).second;
++
++          // printf("Pa is %.6f %.6f\n", Pa.theta, Pa.dist);
++          // printf("Pb is %.6f %.6f\n", Pb.theta, Pb.dist);
++          // printf("Pc is %.6f %.6f\n", Pc.theta, Pc.dist);
++
++          if ( test_point(Pa, Pb, Pc) ) {
++              // printf("Accepted a point\n");
++              // accept point, advance Pa, Pb, and Pc.
++              ++map_current;
++          } else {
++              // printf("REJECTED A POINT\n");
++              // reject point, delete it and advance only Pb and Pc
++              map_next = map_current;
++              ++map_next;
++              if ( map_next == radians_map.end() ) {
++                  map_next = radians_map.begin();
++              }
++              radians_map.erase( map_next );
++          }
++      }
++    }
++
++    // translate back to correct lon/lat
++    // printf("Final sorted convex hull\n");
++    con_hull.erase( con_hull.begin(), con_hull.end() );
++    map_current = radians_map.begin();
++    map_last = radians_map.end();
++    for ( ; map_current != map_last ; ++map_current ) {
++      p.theta = (*map_current).first;
++      p.dist = (*map_current).second;
++
++      result.x = cos(p.theta) * p.dist + average.x;
++      result.y = sin(p.theta) * p.dist + average.y;
++
++      // printf("%.6f %.6f\n", result.x, result.y);
++
++      con_hull.push_back(result);
++    }
++
++    return con_hull;
++}
++
++
++// $Log$
++// Revision 1.5  1999/02/25 21:32:48  curt
++// Modified to adhere to new polygon naming convention, and also to read the
++// new Robin Peel aiport format.
++//
++// Revision 1.4  1998/09/17 18:40:42  curt
++// Debug message tweaks.
++//
++// Revision 1.3  1998/09/09 20:59:55  curt
++// Loop construct tweaks for STL usage.
++// Output airport file to be used to generate airport scenery on the fly
++//   by the run time sim.
++//
++// Revision 1.2  1998/09/09 16:26:32  curt
++// Continued progress in implementing the convex hull algorithm.
++//
++// Revision 1.1  1998/09/04 23:04:51  curt
++// Beginning of convex hull genereration routine.
++//
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..42bf0db8315a16066d45f1a91e034f3cda92041b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,60 @@@
++// convex_hull.hxx -- calculate the convex hull of a set of points
++//
++// Written by Curtis Olson, started September 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#ifndef _CONVEX_HULL_HXX
++#define _CONVEX_HULL_HXX
++
++
++#include <list>
++
++#ifdef NEEDNAMESPACESTD
++using namespace std;
++#endif
++
++#include "point2d.hxx"
++
++
++// stl list typedefs
++typedef list < point2d > list_container;
++typedef list_container::iterator list_iterator;
++
++
++// calculate the convex hull of a set of points, return as a list of
++// point2d.  The algorithm description can be found at:
++// http://riot.ieor.berkeley.edu/riot/Applications/ConvexHull/CHDetails.html
++list_container convex_hull( list_container input_list );
++
++
++#endif // _CONVEX_HULL_HXX
++
++
++// $Log$
++// Revision 1.2  1998/09/09 16:26:33  curt
++// Continued progress in implementing the convex hull algorithm.
++//
++// Revision 1.1  1998/09/04 23:04:51  curt
++// Beginning of convex hull genereration routine.
++//
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7ad07f6db0b57a750c5152438dd8c450b9dc7393
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,374 @@@
++// main.cxx -- main loop
++//
++// Written by Curtis Olson, started March 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <Include/compiler.h>
++
++#ifdef HAVE_STDLIB_H
++#include <stdlib.h>
++#endif
++
++#include <list>
++#include <stdio.h>
++#include <string.h>
++#include STL_STRING
++
++#include <Bucket/newbucket.hxx>
++#include <Debug/logstream.hxx>
++#include <Include/fg_constants.h>
++#include <Misc/fgstream.hxx>
++#include <Polygon/index.hxx>
++
++#include "area.hxx"
++#include "convex_hull.hxx"
++
++
++// write out airport data
++void write_airport( long int p_index, list_container hull_list, FGBucket b, 
++                  const string& root, const bool cut_and_keep ) {
++    char tile_name[256], poly_index[256];
++
++    string base = b.gen_base_path();
++    string path = root + "/Scenery/" + base;
++    string command = "mkdir -p " + path;
++    system( command.c_str() );
++
++    long int b_index = b.gen_index();
++    sprintf(tile_name, "%ld", b_index);
++    string aptfile = path + "/" + tile_name;
++
++    sprintf( poly_index, "%ld", p_index );
++    aptfile += ".";
++    aptfile += poly_index;
++    cout << "apt file = " << aptfile << endl;
++
++    FILE *fd;
++    if ( (fd = fopen(aptfile.c_str(), "a")) == NULL ) {
++        cout << "Cannot open file: " << aptfile << endl;
++        exit(-1);
++    }
++
++    // polygon type
++    if ( cut_and_keep ) {
++      fprintf( fd, "AirportKeep\n" );
++    } else {
++      fprintf( fd, "AirportIgnore\n" );
++    }
++
++    // number of contours
++    fprintf( fd, "1\n" );
++
++    // size of first contour
++    fprintf( fd, "%d\n", hull_list.size() );
++
++    // write contour (polygon) points
++    list_iterator current = hull_list.begin();
++    list_iterator last = hull_list.end();
++    for ( ; current != last ; ++current ) {
++      fprintf( fd, "%.7f %.7f\n", (*current).lon, (*current).lat );
++    }
++
++    fclose(fd);
++}
++
++
++// process and airport + runway list
++void process_airport( string airport, list < string > & runway_list,
++                    const string& root ) {
++    list_container rwy_list, apt_list, hull_list;
++    list_iterator current, last;
++
++    // parse main airport information
++    int elev;
++
++    cout << airport << endl;
++    string apt_type = airport.substr(0, 1);
++    string apt_code = airport.substr(2, 4);
++    string apt_lat = airport.substr(7, 10);
++    string apt_lon = airport.substr(18, 11);
++    string apt_elev = airport.substr(30, 5);
++    sscanf( apt_elev.c_str(), "%d", &elev );
++    string apt_use = airport.substr(36, 1);
++    string apt_twr = airport.substr(37, 1);
++    string apt_bldg = airport.substr(38, 1);
++    string apt_name = airport.substr(40);
++
++    /*
++    cout << "  type = " << apt_type << endl;
++    cout << "  code = " << apt_code << endl;
++    cout << "  lat  = " << apt_lat << endl;
++    cout << "  lon  = " << apt_lon << endl;
++    cout << "  elev = " << apt_elev << " " << elev << endl;
++    cout << "  use  = " << apt_use << endl;
++    cout << "  twr  = " << apt_twr << endl;
++    cout << "  bldg = " << apt_bldg << endl;
++    cout << "  name = " << apt_name << endl;
++    */
++
++    // parse runways and generate the vertex list
++    string rwy_str;
++    double lon, lat, hdg;
++    int len, width;
++
++    list < string >::iterator last_runway = runway_list.end();
++    for ( list < string >::iterator current_runway = runway_list.begin();
++        current_runway != last_runway ; ++current_runway ) {
++      rwy_str = (*current_runway);
++
++      cout << rwy_str << endl;
++      string rwy_no = rwy_str.substr(2, 4);
++      string rwy_lat = rwy_str.substr(6, 10);
++      sscanf( rwy_lat.c_str(), "%lf", &lat);
++      string rwy_lon = rwy_str.substr(17, 11);
++      sscanf( rwy_lon.c_str(), "%lf", &lon);
++      string rwy_hdg = rwy_str.substr(29, 7);
++      sscanf( rwy_hdg.c_str(), "%lf", &hdg);
++      string rwy_len = rwy_str.substr(36, 7);
++      sscanf( rwy_len.c_str(), "%d", &len);
++      string rwy_width = rwy_str.substr(43, 4);
++      sscanf( rwy_width.c_str(), "%d", &width);
++      string rwy_sfc = rwy_str.substr(47, 4);
++      string rwy_end1 = rwy_str.substr(52, 8);
++      string rwy_end2 = rwy_str.substr(61, 8);
++
++      /*
++      cout << "  no    = " << rwy_no << endl;
++      cout << "  lat   = " << rwy_lat << " " << lat << endl;
++      cout << "  lon   = " << rwy_lon << " " << lon << endl;
++      cout << "  hdg   = " << rwy_hdg << " " << hdg << endl;
++      cout << "  len   = " << rwy_len << " " << len << endl;
++      cout << "  width = " << rwy_width << " " << width << endl;
++      cout << "  sfc   = " << rwy_sfc << endl;
++      cout << "  end1  = " << rwy_end1 << endl;
++      cout << "  end2  = " << rwy_end2 << endl;
++      */
++
++      rwy_list = gen_runway_area( lon, lat, hdg * DEG_TO_RAD, 
++                                  (double)len * FEET_TO_METER,
++                                  (double)width * FEET_TO_METER );
++
++      // add rwy_list to apt_list
++      current = rwy_list.begin();
++      last = rwy_list.end();
++      for ( ; current != last ; ++current ) {
++          apt_list.push_back(*current);
++      }
++    }
++
++    if ( apt_list.size() == 0 ) {
++      cout << "no runway points generated" << endl;
++      return;
++    }
++
++    // printf("Runway points in degrees\n");
++    // current = apt_list.begin();
++    // last = apt_list.end();
++    // for ( ; current != last; ++current ) {
++    //   printf( "%.5f %.5f\n", current->lon, current->lat );
++    // }
++    // printf("\n");
++
++    // generate convex hull
++    hull_list = convex_hull(apt_list);
++
++    // get next polygon index
++    long int index = poly_index_next();
++
++    // find average center, min, and max point of convex hull
++    point2d average, min, max;
++    double sum_x, sum_y;
++    int count = hull_list.size();
++    current = hull_list.begin();
++    last = hull_list.end();
++    sum_x = sum_y = 0.0;
++    min.x = min.y = 200.0;
++    max.x = max.y = -200.0;
++    for ( ; current != last; ++current ) {
++      // printf("return = %.6f %.6f\n", (*current).x, (*current).y);
++      sum_x += (*current).x;
++      sum_y += (*current).y;
++
++      if ( (*current).x < min.x ) { min.x = (*current).x; }
++      if ( (*current).y < min.y ) { min.y = (*current).y; }
++      if ( (*current).x > max.x ) { max.x = (*current).x; }
++      if ( (*current).y > max.y ) { max.y = (*current).y; }
++    }
++    average.x = sum_x / count;
++    average.y = sum_y / count;
++
++    // find buckets for center, min, and max points of convex hull.
++    // note to self: self, you should think about checking for runways
++    // that span the data line
++    FGBucket b(average.lon, average.lat);
++    FGBucket b_min(min.x, min.y);
++    FGBucket b_max(max.x, max.y);
++    cout << "Bucket center = " << b << endl;
++    cout << "Bucket min = " << b_min << endl;
++    cout << "Bucket max = " << b_max << endl;
++    
++    if ( b_min == b_max ) {
++      write_airport( index, hull_list, b, root, true );
++    } else {
++      FGBucket b_cur;
++      int dx, dy, i, j;
++
++      fgBucketDiff(b_min, b_max, &dx, &dy);
++      cout << "airport spans tile boundaries" << endl;
++      cout << "  dx = " << dx << "  dy = " << dy << endl;
++
++      if ( (dx > 2) || (dy > 2) ) {
++          cout << "somethings really wrong!!!!" << endl;
++          exit(-1);
++      }
++
++      for ( j = 0; j <= dy; j++ ) {
++          for ( i = 0; i <= dx; i++ ) {
++              b_cur = fgBucketOffset(min.x, min.y, i, j);
++              if ( b_cur == b ) {
++                  write_airport( index, hull_list, b_cur, root, true );
++              } else {
++                  write_airport( index, hull_list, b_cur, root, false );
++              }
++          }
++      }
++      // string answer; cin >> answer;
++    }
++}
++
++
++// reads the apt_full file and extracts and processes the individual
++// airport records
++int main( int argc, char **argv ) {
++    list < string > runway_list;
++    string airport, last_airport;
++    string line;
++    char tmp[256];
++
++    fglog().setLogLevels( FG_ALL, FG_DEBUG );
++
++    if ( argc != 3 ) {
++      FG_LOG( FG_GENERAL, FG_ALERT, 
++              "Usage " << argv[0] << " <apt_file> <work_dir>" );
++      exit(-1);
++    }
++
++    // make work directory
++    string work_dir = argv[2];
++    string command = "mkdir -p " + work_dir;
++    system( command.c_str() );
++
++    // initialize persistant polygon counter
++    string counter_file = work_dir + "/../work.counter";
++    poly_index_init( counter_file );
++
++    fg_gzifstream in( argv[1] );
++    if ( !in ) {
++        FG_LOG( FG_GENERAL, FG_ALERT, "Cannot open file: " << argv[1] );
++        exit(-1);
++    }
++
++    // throw away the first 3 lines
++    in.getline(tmp, 256);
++    in.getline(tmp, 256);
++    in.getline(tmp, 256);
++
++    last_airport = "";
++
++    while ( ! in.eof() ) {
++      in.getline(tmp, 256);
++      line = tmp;
++      // cout << line << endl;
++
++      if ( line.length() == 0 ) {
++          // empty, skip
++      } else if ( line[0] == '#' ) {
++          // comment, skip
++      } else if ( (line[0] == 'A') || (line[0] == 'S') ) {
++          // start of airport record
++          airport = line;
++
++          if ( last_airport.length() ) {
++              // process previous record
++              process_airport(last_airport, runway_list, argv[2]);
++          }
++
++          // clear runway list for start of next airport
++          runway_list.erase(runway_list.begin(), runway_list.end());
++
++          last_airport = airport;
++      } else if ( line[0] == 'R' ) {
++          // runway entry
++          runway_list.push_back(line);
++      } else if ( line == "[End]" ) {
++          // end of file
++          break;
++      } else {
++          FG_LOG( FG_GENERAL, FG_ALERT, 
++                  "Unknown line in file" << endl << line );
++          exit(-1);
++      }
++    }
++
++    if ( last_airport.length() ) {
++      // process previous record
++      process_airport(last_airport, runway_list, argv[2]);
++    }
++
++    return 0;
++}
++
++
++// $Log$
++// Revision 1.11  1999/03/19 00:27:38  curt
++// Use long int for index instead of just int.
++//
++// Revision 1.10  1999/03/17 23:51:25  curt
++// Changed polygon index counter file.
++//
++// Revision 1.9  1999/03/12 22:54:19  curt
++// Rearrange a bit of code ...
++//
++// Revision 1.8  1999/03/01 15:35:26  curt
++// Fixed bug in output format generated.
++//
++// Revision 1.7  1999/02/25 21:32:49  curt
++// Modified to adhere to new polygon naming convention, and also to read the
++// new Robin Peel aiport format.
++//
++// Revision 1.6  1999/02/11 01:10:51  curt
++// Start of scenery revamp project.
++//
++// Revision 1.5  1998/09/17 18:40:43  curt
++// Debug message tweaks.
++//
++// Revision 1.4  1998/09/09 20:59:56  curt
++// Loop construct tweaks for STL usage.
++// Output airport file to be used to generate airport scenery on the fly
++//   by the run time sim.
++//
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..755224477fa06ba2adbfaeeb1e1ecad6d3f906ad
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,45 @@@
++// point2d.cxx -- 2d coordinate routines
++//
++// Written by Curtis Olson, started September 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#include <math.h>
++
++#include "point2d.hxx"
++
++
++// convert a point from cartesian to polar coordinates
++point2d cart_to_polar_2d(point2d in) {
++    point2d result;
++    result.dist = sqrt( in.x * in.x + in.y * in.y );
++    result.theta = atan2(in.y, in.x);    
++
++    return(result);
++}
++
++
++// $Log$
++// Revision 1.1  1998/09/04 23:04:53  curt
++// Beginning of convex hull genereration routine.
++//
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..199524047a1b62addc4b97aa7fcfd29cff143757
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,59 @@@
++// point2d.hxx -- define a 2d point class
++//
++// Written by Curtis Olson, started February 1998.
++//
++// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++//
++
++
++#ifndef _POINT2D_HXX
++#define _POINT2D_HXX
++
++
++#include <list>
++
++
++class point2d {
++public:
++    union {
++      double x;
++      double dist;
++      double lon;
++    };
++    union {
++      double y;
++      double theta;
++      double lat;
++    };
++};
++
++
++// convert a point from cartesian to polar coordinates
++point2d cart_to_polar_2d(point2d in);
++
++
++#endif // _POINT2D_HXX
++
++
++// $Log$
++// Revision 1.1  1998/09/04 23:04:53  curt
++// Beginning of convex hull genereration routine.
++//
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..28ad535a2b9f5f847b3b52bb934f1d24b3775558
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,9 @@@
++noinst_LIBRARIES = libGenOutput.a
++
++libGenOutput_a_SOURCES = genobj.cxx genobj.hxx
++
++INCLUDES += \
++      -I$(top_builddir) \
++      -I$(top_builddir)/Lib \
++      -I$(top_builddir)/Tools/Lib \
++      -I$(top_builddir)/Tools/Construct
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fc3cc3b688de45a2dfe86ebc36ab60b80898e473
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,469 @@@
++// genobj.hxx -- Generate the flight gear "obj" file format from the
++//               triangle output
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include <time.h>
++
++#include <Math/mat3.h>
++#include <Polygon/names.hxx>
++#include <Tools/scenery_version.hxx>
++
++#include "genobj.hxx"
++
++
++// build the wgs-84 point list
++void FGGenOutput::gen_wgs84_points( const FGArray& array ) {
++    cout << "calculating wgs84 point" << endl;
++    Point3D geod, radians, cart;
++
++    const_point_list_iterator current = geod_nodes.begin();
++    const_point_list_iterator last = geod_nodes.end();
++
++    double real_z;
++
++    for ( ; current != last; ++current ) {
++      geod = *current;
++
++      real_z = array.interpolate_altitude( geod.x() * 3600.0, 
++                                            geod.y() * 3600.0 );
++
++      // convert to radians
++      radians = Point3D( geod.x() * DEG_TO_RAD,
++                         geod.y() * DEG_TO_RAD,
++                         real_z );
++
++        cart = fgGeodToCart(radians);
++      // cout << cart << endl;
++        wgs84_nodes.push_back(cart);
++    }
++}
++
++
++// build the node -> element (triangle) reverse lookup table.  there
++// is an entry for each point containing a list of all the triangles
++// that share that point.
++void FGGenOutput::gen_node_ele_lookup_table() {
++    int_list ele_list;
++    ele_list.erase( ele_list.begin(), ele_list.end() );
++
++    // initialize reverse_ele_lookup structure by creating an empty
++    // list for each point
++    const_point_list_iterator w_current = wgs84_nodes.begin();
++    const_point_list_iterator w_last = wgs84_nodes.end();
++    for ( ; w_current != w_last; ++w_current ) {
++      reverse_ele_lookup.push_back( ele_list );
++    }
++
++    // traverse triangle structure building reverse lookup table
++    const_triele_list_iterator current = tri_elements.begin();
++    const_triele_list_iterator last = tri_elements.end();
++    int counter = 0;
++    for ( ; current != last; ++current ) {
++      reverse_ele_lookup[ current->get_n1() ].push_back( counter );
++      reverse_ele_lookup[ current->get_n2() ].push_back( counter );
++      reverse_ele_lookup[ current->get_n3() ].push_back( counter );
++      ++counter;
++    }
++}
++
++
++// caclulate the normal for the specified triangle face
++Point3D FGGenOutput::calc_normal( int i ) {
++    double v1[3], v2[3], normal[3];
++    double temp;
++
++    Point3D p1 = wgs84_nodes[ tri_elements[i].get_n1() ];
++    Point3D p2 = wgs84_nodes[ tri_elements[i].get_n2() ];
++    Point3D p3 = wgs84_nodes[ tri_elements[i].get_n3() ];
++
++    v1[0] = p2.x() - p1.x(); v1[1] = p2.y() - p1.y(); v1[2] = p2.z() - p1.z();
++    v2[0] = p3.x() - p1.x(); v2[1] = p3.y() - p1.y(); v2[2] = p3.z() - p1.z();
++
++    MAT3cross_product(normal, v1, v2);
++    MAT3_NORMALIZE_VEC(normal,temp);
++
++    return Point3D( normal[0], normal[1], normal[2] );
++}
++
++
++// build the face normal list
++void FGGenOutput::gen_face_normals() {
++    // traverse triangle structure building the face normal table
++
++    cout << "calculating face normals" << endl;
++
++    for ( int i = 0; i < (int)tri_elements.size(); i++ ) {
++      // cout << calc_normal( i ) << endl;
++      face_normals.push_back( calc_normal( i ) );
++    }
++
++}
++
++
++// calculate the normals for each point in wgs84_nodes
++void FGGenOutput::gen_normals() {
++    Point3D normal;
++    cout << "caculating node normals" << endl;
++
++    // for each node
++    for ( int i = 0; i < (int)wgs84_nodes.size(); ++i ) {
++      int_list tri_list = reverse_ele_lookup[i];
++
++      int_list_iterator current = tri_list.begin();
++      int_list_iterator last = tri_list.end();
++
++      Point3D average( 0.0 );
++
++      // for each triangle that shares this node
++      for ( ; current != last; ++current ) {
++          normal = face_normals[ *current ];
++          average += normal;
++          // cout << normal << endl;
++      }
++
++      average /= tri_list.size();
++      // cout << "average = " << average << endl;
++
++      point_normals.push_back( average );
++    }
++}
++
++
++// calculate the global bounding sphere.  Center is the average of the
++// points.
++void FGGenOutput::calc_gbs() {
++    double dist_squared;
++    double radius_squared = 0;
++    
++    gbs_center = Point3D( 0.0 );
++
++    const_point_list_iterator current = wgs84_nodes.begin();
++    const_point_list_iterator last = wgs84_nodes.end();
++
++    for ( ; current != last; ++current ) {
++      gbs_center += *current;
++    }
++
++    gbs_center /= wgs84_nodes.size();
++
++    current =  wgs84_nodes.begin();
++    for ( ; current != last; ++current ) {
++        dist_squared = gbs_center.distance3Dsquared(*current);
++      if ( dist_squared > radius_squared ) {
++            radius_squared = dist_squared;
++        }
++    }
++
++    gbs_radius = sqrt(radius_squared);
++}
++
++
++// build the necessary output structures based on the triangulation
++// data
++int FGGenOutput::build( const FGArray& array, const FGTriangle& t ) {
++    FGTriNodes trinodes = t.get_out_nodes();
++
++    // copy the geodetic node list into this class
++    geod_nodes = trinodes.get_node_list();
++
++    // copy the triangle list into this class
++    tri_elements = t.get_elelist();
++
++    // build the trifan list
++    cout << "total triangles = " << tri_elements.size() << endl;
++    FGGenFans f;
++    for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
++      triele_list area_tris;
++      area_tris.erase( area_tris.begin(), area_tris.end() );
++
++      const_triele_list_iterator t_current = tri_elements.begin();
++      const_triele_list_iterator t_last = tri_elements.end();
++      for ( ; t_current != t_last; ++t_current ) {
++          if ( (int)t_current->get_attribute() == i ) {
++              area_tris.push_back( *t_current );
++          }
++      }
++
++      if ( (int)area_tris.size() > 0 ) {
++          cout << "generating fans for area = " << i << endl;
++          fans[i] = f.greedy_build( area_tris );
++      }
++    }
++
++    // generate the point list in wgs-84 coordinates
++    gen_wgs84_points( array );
++
++    // calculate the global bounding sphere
++    calc_gbs();
++    cout << "center = " << gbs_center << " radius = " << gbs_radius << endl;
++
++    // build the node -> element (triangle) reverse lookup table
++    gen_node_ele_lookup_table();
++
++    // build the face normal list
++    gen_face_normals();
++
++    // calculate the normals for each point in wgs84_nodes
++    gen_normals();
++
++    return 1;
++}
++
++
++// caclulate the bounding sphere for a list of triangle faces
++void FGGenOutput::calc_group_bounding_sphere( const fan_list& fans, 
++                                            Point3D *center, double *radius )
++{
++    cout << "calculate group bounding sphere for " << fans.size() << " fans." 
++       << endl;
++
++    // generate a list of unique points from the triangle list
++    FGTriNodes nodes;
++
++    const_fan_list_iterator f_current = fans.begin();
++    const_fan_list_iterator f_last = fans.end();
++    for ( ; f_current != f_last; ++f_current ) {
++      const_int_list_iterator i_current = f_current->begin();
++      const_int_list_iterator i_last = f_current->end();
++      for ( ; i_current != i_last; ++i_current ) {
++          Point3D p1 = wgs84_nodes[ *i_current ];
++          nodes.unique_add(p1);
++      }
++    }
++
++    // find average of point list
++    Point3D c( 0.0 );
++    point_list points = nodes.get_node_list();
++    // cout << "found " << points.size() << " unique nodes" << endl;
++    point_list_iterator p_current = points.begin();
++    point_list_iterator p_last = points.end();
++    for ( ; p_current != p_last; ++p_current ) {
++      c += *p_current;
++    }
++    c /= points.size();
++
++    // find max radius
++    double dist_squared;
++    double max_squared = 0;
++
++    p_current = points.begin();
++    p_last = points.end();
++    for ( ; p_current != p_last; ++p_current ) {
++      dist_squared = c.distance3Dsquared(*p_current);
++      if ( dist_squared > max_squared ) {
++          max_squared = dist_squared;
++      }
++    }
++
++    *center = c;
++    *radius = sqrt(max_squared);
++}
++
++
++// caclulate the bounding sphere for the specified triangle face
++void FGGenOutput::calc_bounding_sphere( const FGTriEle& t, 
++                                      Point3D *center, double *radius )
++{
++    Point3D c( 0.0 );
++
++    Point3D p1 = wgs84_nodes[ t.get_n1() ];
++    Point3D p2 = wgs84_nodes[ t.get_n2() ];
++    Point3D p3 = wgs84_nodes[ t.get_n3() ];
++
++    c = p1 + p2 + p3;
++    c /= 3;
++
++    double dist_squared;
++    double max_squared = 0;
++
++    dist_squared = c.distance3Dsquared(p1);
++    if ( dist_squared > max_squared ) {
++      max_squared = dist_squared;
++    }
++
++    dist_squared = c.distance3Dsquared(p2);
++    if ( dist_squared > max_squared ) {
++      max_squared = dist_squared;
++    }
++
++    dist_squared = c.distance3Dsquared(p3);
++    if ( dist_squared > max_squared ) {
++      max_squared = dist_squared;
++    }
++
++    *center = c;
++    *radius = sqrt(max_squared);
++}
++
++
++// write out the fgfs scenery file
++int FGGenOutput::write( const string& base, const FGBucket& b ) {
++    Point3D p;
++
++    string dir = base + "/Scenery/" + b.gen_base_path();
++    string command = "mkdir -p " + dir;
++    system(command.c_str());
++
++    string file = dir + "/" + b.gen_index_str();
++    cout << "Output file = " << file << endl;
++
++    FILE *fp;
++    if ( (fp = fopen( file.c_str(), "w" )) == NULL ) {
++      cout << "ERROR: opening " << file << " for writing!" << endl;
++      exit(-1);
++    }
++
++    // write headers
++    fprintf(fp, "# FGFS Scenery Version %s\n", FG_SCENERY_FILE_FORMAT);
++
++    time_t calendar_time = time(NULL);
++    struct tm *local_tm;
++    local_tm = localtime( &calendar_time );
++    char time_str[256];
++    strftime( time_str, 256, "%a %b %d %H:%M:%S %Z %Y", local_tm);
++    fprintf(fp, "# Created %s\n", time_str );
++    fprintf(fp, "\n");
++
++    // write global bounding sphere
++    fprintf(fp, "# gbs %.5f %.5f %.5f %.2f\n",
++          gbs_center.x(), gbs_center.y(), gbs_center.z(), gbs_radius);
++    fprintf(fp, "\n");
++
++    // write nodes
++    fprintf(fp, "# vertex list\n");
++    const_point_list_iterator w_current = wgs84_nodes.begin();
++    const_point_list_iterator w_last = wgs84_nodes.end();
++    for ( ; w_current != w_last; ++w_current ) {
++      p = *w_current - gbs_center;
++      fprintf(fp, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z());
++    }
++    fprintf(fp, "\n");
++    
++    // write vertex normals
++    fprintf(fp, "# vertex normal list\n");
++    const_point_list_iterator n_current = point_normals.begin();
++    const_point_list_iterator n_last = point_normals.end();
++    for ( ; n_current != n_last; ++n_current ) {
++      p = *n_current;
++      fprintf(fp, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z());
++    }
++    fprintf(fp, "\n");
++
++    // write triangles (grouped by type for now)
++    Point3D center;
++    double radius;
++    fprintf(fp, "# triangle groups\n");
++    fprintf(fp, "\n");
++
++    int total_tris = 0;
++    for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
++      if ( (int)fans[i].size() > 0 ) {
++          string attr_name = get_area_name( (AreaType)i );
++          calc_group_bounding_sphere( fans[i], &center, &radius );
++          cout << "writing " << (int)fans[i].size() << " fans for " 
++               << attr_name << endl;
++
++          fprintf(fp, "# usemtl %s\n", attr_name.c_str() );
++          fprintf(fp, "# bs %.4f %.4f %.4f %.2f\n", 
++                  center.x(), center.y(), center.z(), radius);
++
++          fan_list_iterator f_current = fans[i].begin();
++          fan_list_iterator f_last = fans[i].end();
++          for ( ; f_current != f_last; ++f_current ) {
++              fprintf( fp, "tf" );
++              total_tris += f_current->size() - 2;
++              int_list_iterator i_current = f_current->begin();
++              int_list_iterator i_last = f_current->end();
++              for ( ; i_current != i_last; ++i_current ) {
++                  fprintf( fp, " %d", *i_current );
++              }
++              fprintf( fp, "\n" );
++
++#if 0
++              {
++                  int_list_iterator i_current = f_current->begin();
++                  int_list_iterator i_last = f_current->end();
++                  int center = *i_current;
++                  ++i_current;
++                  int n2 = *i_current;
++                  ++i_current;
++                  for ( ; i_current != i_last; ++i_current ) {
++                      int n3 = *i_current;
++                      fprintf( fp, "f %d %d %d\n", center, n2, n3 );
++                      n2 = n3;
++                  }
++              }
++#endif
++          }
++
++          fprintf( fp, "\n" );
++      }
++    }
++    cout << "wrote " << total_tris << " tris to output file" << endl;
++
++    fclose(fp);
++
++    command = "gzip --force --best " + file;
++    system(command.c_str());
++
++    return 1;
++}
++
++
++// $Log$
++// Revision 1.10  1999/03/31 23:46:57  curt
++// Debugging output tweaks.
++//
++// Revision 1.9  1999/03/31 13:26:40  curt
++// Debugging output tweeaks.
++//
++// Revision 1.8  1999/03/31 05:35:05  curt
++// Fixed bug in genfans (deleting the wrong triangles from the available pool.)
++//
++// Revision 1.7  1999/03/30 23:50:43  curt
++// Modifications to fanify by attribute.
++//
++// Revision 1.6  1999/03/29 13:11:03  curt
++// Shuffled stl type names a bit.
++// Began adding support for tri-fanning (or maybe other arrangments too.)
++//
++// Revision 1.5  1999/03/27 14:06:42  curt
++// Tweaks to bounding sphere calculation routines.
++// Group like triangles together for output to be in a single display list,
++// even though they are individual, non-fanified, triangles.
++//
++// Revision 1.4  1999/03/27 05:23:22  curt
++// Interpolate real z value of all nodes from dem data.
++// Write scenery file to correct location.
++// Pass along correct triangle attributes and write to output file.
++//
++// Revision 1.3  1999/03/25 19:04:21  curt
++// Preparations for outputing scenery file to correct location.
++//
++// Revision 1.2  1999/03/23 22:02:03  curt
++// Worked on creating data to output ... normals, bounding spheres, etc.
++//
++// Revision 1.1  1999/03/22 23:51:51  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..55f9844527f70ee6ed5e302c389890219c2f9797
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,165 @@@
++// genobj.hxx -- Generate the flight gear "obj" file format from the
++//               triangle output
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef _GENOBJ_HXX
++#define _GENOBJ_HXX
++
++
++#ifndef __cplusplus                                                          
++# error This library requires C++
++#endif                                   
++
++
++#include <Include/compiler.h>
++
++#include STL_STRING
++
++#include <Bucket/newbucket.hxx>
++#include <Math/fg_geodesy.hxx>
++#include <Math/point3d.hxx>
++
++#include <Combine/genfans.hxx>
++#include <Main/construct_types.hxx>
++#include <Triangulate/triangle.hxx>
++
++FG_USING_STD(string);
++FG_USING_STD(vector);
++
++
++typedef vector < int_list > belongs_to_list;
++typedef belongs_to_list::iterator belongs_to_list_iterator;
++typedef belongs_to_list::const_iterator belongs_to_list_tripoly_iterator;
++
++
++class FGGenOutput {
++
++private:
++
++    // node list in geodetic coordinats
++    point_list geod_nodes;
++
++    // node list in cartesian coords (wgs84 model)
++    point_list wgs84_nodes;
++
++    // face normal list (for flat shading)
++    point_list face_normals;
++
++    // normal list (for each point) in cart coords (for smooth
++    // shading)
++    point_list point_normals;
++
++    // triangles (by index into point list)
++    triele_list tri_elements;
++
++    // fan list
++    fan_list fans[FG_MAX_AREA_TYPES];
++
++    // for each node, a list of triangle indices that contain this node
++    belongs_to_list reverse_ele_lookup;
++
++    // global bounding sphere
++    Point3D gbs_center;
++    double gbs_radius;
++
++    // build the wgs-84 point list
++    void gen_wgs84_points( const FGArray& array );
++
++    // build the node -> element (triangle) reverse lookup table.
++    // there is an entry for each point containing a list of all the
++    // triangles that share that point.
++    void gen_node_ele_lookup_table();
++
++    // calculate the normals for each point in wgs84_nodes
++    void gen_normals();
++
++    // build the face normal list
++    void gen_face_normals();
++
++    // caclulate the normal for the specified triangle face
++    Point3D calc_normal( int i );
++
++    // calculate the global bounding sphere.  Center is the average of
++    // the points.
++    void calc_gbs();
++
++    // caclulate the bounding sphere for a list of triangle faces
++    void calc_group_bounding_sphere( const fan_list& fans, 
++                                   Point3D *center, double *radius );
++
++    // caclulate the bounding sphere for the specified triangle face
++    void calc_bounding_sphere( const FGTriEle& t, 
++                             Point3D *center, double *radius );
++
++public:
++
++    // Constructor && Destructor
++    inline FGGenOutput() { }
++    inline ~FGGenOutput() { }
++
++    // build the necessary output structures based on the
++    // triangulation data
++    int build( const FGArray& array, const FGTriangle& t );
++
++    // write out the fgfs scenery file
++    int write( const string& base, const FGBucket& b );
++};
++
++
++#endif // _GENOBJ_HXX
++
++
++// $Log$
++// Revision 1.9  1999/03/31 23:46:58  curt
++// Debugging output tweaks.
++//
++// Revision 1.8  1999/03/30 23:50:44  curt
++// Modifications to fanify by attribute.
++//
++// Revision 1.7  1999/03/29 13:11:04  curt
++// Shuffled stl type names a bit.
++// Began adding support for tri-fanning (or maybe other arrangments too.)
++//
++// Revision 1.6  1999/03/27 14:06:43  curt
++// Tweaks to bounding sphere calculation routines.
++// Group like triangles together for output to be in a single display list,
++// even though they are individual, non-fanified, triangles.
++//
++// Revision 1.5  1999/03/27 05:23:23  curt
++// Interpolate real z value of all nodes from dem data.
++// Write scenery file to correct location.
++// Pass along correct triangle attributes and write to output file.
++//
++// Revision 1.4  1999/03/25 19:04:22  curt
++// Preparations for outputing scenery file to correct location.
++//
++// Revision 1.3  1999/03/23 22:02:04  curt
++// Worked on creating data to output ... normals, bounding spheres, etc.
++//
++// Revision 1.2  1999/03/23 17:44:49  curt
++// Beginning work on generating output scenery.
++//
++// Revision 1.1  1999/03/22 23:51:51  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6c6ad9d3eea3531213b6ff23b698ab6b7a4c9899
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++SUBDIRS = \
++      DEM \
++      Polygon \
++      Triangle
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..95e1e4f147c719b89ba27a60e824a34c3da92b1a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,24 @@@
++bin_PROGRAMS = construct
++
++construct_SOURCES = construct.cxx construct_types.hxx
++
++construct_LDADD = \
++      $(top_builddir)/Tools/Construct/Array/libArray.a \
++      $(top_builddir)/Tools/Construct/Clipper/libClipper.a \
++      $(top_builddir)/Tools/Construct/GenOutput/libGenOutput.a \
++      $(top_builddir)/Tools/Construct/Combine/libCombine.a \
++      $(top_builddir)/Tools/Construct/Triangulate/libTriangulate.a \
++      $(top_builddir)/Tools/Lib/Polygon/libPolygon.a \
++      $(top_builddir)/Tools/Lib/Triangle/libTriangle.a \
++      $(top_builddir)/Lib/Bucket/libBucket.a \
++      $(top_builddir)/Lib/Math/libMath.a \
++      $(top_builddir)/Lib/Misc/libMisc.a \
++      $(top_builddir)/Lib/Debug/libDebug.a \
++      $(top_builddir)/Lib/zlib/libz.a \
++      -lgpc -lgfc
++
++INCLUDES += \
++      -I$(top_builddir) \
++      -I$(top_builddir)/Lib \
++      -I$(top_builddir)/Tools/Lib \
++      -I$(top_builddir)/Tools/Construct
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1c5c117a99e53b8a1df7d0241557816c50716ec0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,373 @@@
++// main.cxx -- top level construction routines
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include <sys/types.h>  // for directory reading
++#include <dirent.h>     // for directory reading
++
++#include <Bucket/newbucket.hxx>
++#include <Include/fg_constants.h>
++
++#include <Debug/logstream.hxx>
++#include <Array/array.hxx>
++#include <Clipper/clipper.hxx>
++#include <GenOutput/genobj.hxx>
++#include <Triangulate/triangle.hxx>
++
++
++// load regular grid of elevation data (dem based), return list of
++// fitted nodes
++int load_dem(const string& work_base, FGBucket& b, FGArray& array) {
++    point_list result;
++    string base = b.gen_base_path();
++
++    string dem_path = work_base + ".dem" + "/Scenery/" + base 
++      + "/" + b.gen_index_str() + ".dem";
++    cout << "dem_path = " << dem_path << endl;
++
++    if ( ! array.open(dem_path) ) {
++      cout << "ERROR: cannot open " << dem_path << endl;
++    }
++
++    array.parse( b );
++
++    return 1;
++}
++
++// fit dem nodes, return number of fitted nodes
++int fit_dem(FGArray& array, int error) {
++    return array.fit( error );
++}
++
++
++// do actual scan of directory and loading of files
++int actual_load_polys( const string& dir, FGBucket& b, FGClipper& clipper ) {
++    int counter = 0;
++    string base = b.gen_base_path();
++    string tile_str = b.gen_index_str();
++    string ext;
++
++    DIR *d;
++    struct dirent *de;
++
++    if ( (d = opendir( dir.c_str() )) == NULL ) {
++        cout << "cannot open directory " << dir << "\n";
++      return 0;
++    }
++
++    // load all matching polygon files
++    string file, f_index, full_path;
++    int pos;
++    while ( (de = readdir(d)) != NULL ) {
++      file = de->d_name;
++      pos = file.find(".");
++      f_index = file.substr(0, pos);
++
++      if ( tile_str == f_index ) {
++          ext = file.substr(pos + 1);
++          cout << file << "  " << f_index << "  '" << ext << "'" << endl;
++          full_path = dir + "/" + file;
++          if ( (ext == "dem") || (ext == "dem.gz") ) {
++              // skip
++          } else {
++              cout << "ext = '" << ext << "'" << endl;
++              clipper.load_polys( full_path );
++              ++counter;
++          }
++      }
++    }
++
++    return counter;
++}
++
++
++// load all 2d polygons matching the specified base path and clip
++// against each other to resolve any overlaps
++int load_polys( const string& work_base, FGBucket& b, FGClipper& clipper) {
++    string base = b.gen_base_path();
++    int result;
++
++    // initialize clipper
++    clipper.init();
++
++    // load airports
++    string poly_path = work_base + ".apt" + "/Scenery/" + base;
++    cout << "poly_path = " << poly_path << endl;
++    result = actual_load_polys( poly_path, b, clipper );
++    cout << "  loaded " << result << " polys" << endl;
++
++    // load hydro
++    poly_path = work_base + ".hydro" + "/Scenery/" + base;
++    cout << "poly_path = " << poly_path << endl;
++    result = actual_load_polys( poly_path, b, clipper );
++    cout << "  loaded " << result << " polys" << endl;
++
++    point2d min, max;
++    min.x = b.get_center_lon() - 0.5 * b.get_width();
++    min.y = b.get_center_lat() - 0.5 * b.get_height();
++    max.x = b.get_center_lon() + 0.5 * b.get_width();
++    max.y = b.get_center_lat() + 0.5 * b.get_height();
++
++    // do clipping
++    cout << "clipping polygons" << endl;
++    clipper.clip_all(min, max);
++
++    return 1;
++}
++
++
++// triangulate the data for each polygon
++void do_triangulate( const FGArray& array, const FGClipper& clipper,
++                FGTriangle& t ) {
++    // first we need to consolidate the points of the DEM fit list and
++    // all the polygons into a more "Triangle" friendly format
++
++    point_list corner_list = array.get_corner_node_list();
++    point_list fit_list = array.get_fit_node_list();
++    FGgpcPolyList gpc_polys = clipper.get_polys_clipped();
++
++    cout << "ready to build node list and polygons" << endl;
++    t.build( corner_list, fit_list, gpc_polys );
++    cout << "done building node list and polygons" << endl;
++
++    cout << "ready to do triangulation" << endl;
++    t.run_triangulate();
++    cout << "finished triangulation" << endl;
++}
++
++
++// generate the flight gear scenery file
++void do_output( const string& base, const FGBucket &b, const FGTriangle& t, 
++              const FGArray& array, FGGenOutput& output ) {
++    output.build( array, t );
++    output.write( base, b );
++}
++
++
++void construct_tile( const string& work_base, const string& output_base,
++                   FGBucket& b )
++{
++    cout << "Construct tile, bucket = " << b << endl;
++
++    // fit with ever increasing error tolerance until we produce <=
++    // 80% of max nodes.  We should really have the sim end handle
++    // arbitrarily complex tiles.
++
++    const int min_nodes = 50;
++    const int max_nodes = (int)(MAX_NODES * 0.8);
++
++    bool acceptable = false;
++    double error = 200.0;
++    int count = 0;
++
++    // load and fit grid of elevation data
++    FGArray array;
++    load_dem( work_base, b, array );
++
++    FGTriangle t;
++
++    while ( ! acceptable ) {
++      // fit the data
++      array.fit( error );
++
++      // load and clip 2d polygon data
++      FGClipper clipper;
++      load_polys( work_base, b, clipper );
++
++      // triangulate the data for each polygon
++      do_triangulate( array, clipper, t );
++
++      acceptable = true;
++
++      count = t.get_out_nodes_size();
++
++      if ( (count < min_nodes) && (error >= 25.0) ) {
++          // reduce error tolerance until number of points exceeds the
++          // minimum threshold
++          cout << "produced too few nodes ..." << endl;
++
++          acceptable = false;
++
++          error /= 1.5;
++          cout << "Setting error to " << error << " and retrying fit." 
++               << endl;
++      }
++
++      if ( (count > max_nodes) && (error <= 1000.0) ) {
++          // increase error tolerance until number of points drops below
++          // the maximum threshold
++          cout << "produced too many nodes ..." << endl;
++          
++          acceptable = false;
++
++          error *= 1.5;
++          cout << "Setting error to " << error << " and retrying fit." 
++               << endl;
++      }
++    }
++
++    cout << "finished fit with error = " << error << " node count = " 
++       << count << endl;
++
++    // generate the output
++    FGGenOutput output;
++    do_output( output_base, b, t, array, output );
++}
++
++
++main(int argc, char **argv) {
++    double lon, lat;
++
++    fglog().setLogLevels( FG_ALL, FG_DEBUG );
++
++    if ( argc != 3 ) {
++      cout << "Usage: " << argv[0] << " <work_base> <output_base>" << endl;
++      exit(-1);
++    }
++
++    string work_base = argv[1];
++    string output_base = argv[2];
++   
++    // lon = -146.248360; lat = 61.133950;     // PAVD (Valdez, AK)
++    // lon = -110.664244; lat = 33.352890;     // P13
++    // lon = -93.211389; lat = 45.145000;      // KANE
++    // lon = -92.486188; lat = 44.590190;      // KRGK
++    // lon = -89.744682312011719; lat= 29.314495086669922;
++    // lon = -122.488090; lat = 42.743183;     // 64S
++    // lon = -114.861097; lat = 35.947480;     // 61B
++    // lon = -112.012175; lat = 41.195944;     // KOGD
++    // lon = -90.757128; lat = 46.790212;      // WI32
++    // lon = -122.220717; lat = 37.721291;     // KOAK
++    // lon = -111.721477; lat = 40.215641;     // KPVU
++    // lon = -122.309313; lat = 47.448982;     // KSEA
++    lon = -148.798131; lat = 63.645099;     // AK06 (Danali, AK)
++
++    double min_x = lon - 3;
++    double min_y = lat - 1;
++    FGBucket b_min( min_x, min_y );
++    FGBucket b_max( lon + 3, lat + 1 );
++
++    FGBucket b_omit(550314L);
++    // FGBucket b(517745L);
++    // FGBucket b(-146.248360, 61.133950);
++    // construct_tile( work_base, output_base, b );
++    // exit(0);
++
++    if ( b_min == b_max ) {
++      construct_tile( work_base, output_base, b_min );
++    } else {
++      FGBucket b_cur;
++      int dx, dy, i, j;
++          
++      fgBucketDiff(b_min, b_max, &dx, &dy);
++      cout << "  construction area spans tile boundaries" << endl;
++      cout << "  dx = " << dx << "  dy = " << dy << endl;
++
++      for ( j = 0; j <= dy; j++ ) {
++          for ( i = 0; i <= dx; i++ ) {
++              b_cur = fgBucketOffset(min_x, min_y, i, j);
++
++              if ( b_cur != b_omit ) {
++                  construct_tile( work_base, output_base, b_cur );
++              }
++          }
++      }
++      // string answer; cin >> answer;
++    }
++}
++
++
++// $Log$
++// Revision 1.18  1999/04/05 02:16:51  curt
++// Dynamically update "error" until the resulting tile data scales within
++// a lower and upper bounds.
++//
++// Revision 1.17  1999/04/03 05:22:57  curt
++// Found a bug in dividing and adding unique verticle segments which could
++// cause the triangulator to end up in an infinite loop.  Basically the code
++// was correct, but the verticle line test was a bit to selective.
++//
++// Revision 1.16  1999/04/01 13:52:12  curt
++// Version 0.6.0
++// Shape name tweak.
++// Removing tool: FixNode
++//
++// Revision 1.15  1999/03/31 23:47:02  curt
++// Debugging output tweaks.
++//
++// Revision 1.14  1999/03/31 13:26:41  curt
++// Debugging output tweeaks.
++//
++// Revision 1.13  1999/03/31 05:35:06  curt
++// Fixed bug in genfans (deleting the wrong triangles from the available pool.)
++//
++// Revision 1.12  1999/03/30 23:51:14  curt
++// fiddling ...
++//
++// Revision 1.11  1999/03/29 13:11:06  curt
++// Shuffled stl type names a bit.
++// Began adding support for tri-fanning (or maybe other arrangments too.)
++//
++// Revision 1.10  1999/03/27 05:25:02  curt
++// Fit with a value of 200 rather than 100.
++// Handle corner nodes separately from the rest of the fitted nodes.
++// Write scenery file to correct location.
++// First hack at generating scenery for multiple tiles in one invocation.
++//
++// Revision 1.9  1999/03/25 19:04:31  curt
++// Preparations for outputing scenery file to correct location.
++// Minor tweaks related to FGBucket usage.
++//
++// Revision 1.8  1999/03/23 22:02:17  curt
++// Worked on creating data to output ... normals, bounding spheres, etc.
++//
++// Revision 1.7  1999/03/22 23:48:29  curt
++// Added GenOutput/
++//
++// Revision 1.6  1999/03/21 15:48:01  curt
++// Removed Dem2node from the Tools fold.
++// Tweaked the triangulator options to add quality mesh refinement.
++//
++// Revision 1.5  1999/03/21 14:02:05  curt
++// Added a mechanism to dump out the triangle structures for viewing.
++// Fixed a couple bugs in first pass at triangulation.
++// - needed to explicitely initialize the polygon accumulator in triangle.cxx
++//   before each polygon rather than depending on the default behavior.
++// - Fixed a problem with region attribute propagation where I wasn't generating
++//   the hole points correctly.
++//
++// Revision 1.4  1999/03/20 20:32:54  curt
++// First mostly successful tile triangulation works.  There's plenty of tweaking
++// to do, but we are marching in the right direction.
++//
++// Revision 1.3  1999/03/19 00:26:52  curt
++// Minor tweaks ...
++//
++// Revision 1.2  1999/03/17 23:49:52  curt
++// Started work on Triangulate/ section.
++//
++// Revision 1.1  1999/03/14 00:03:24  curt
++// Initial revision.
++//
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..095e48c56dfae3dffe4895c4d53da4c337e624a0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,58 @@@
++// construct_types.hxx -- commonly used types in the construction business.
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef _CONSTRUCT_TYPES_HXX
++#define _CONSTRUCT_TYPES_HXX
++
++
++#ifndef __cplusplus                                                          
++# error This library requires C++
++#endif                                   
++
++
++#include <Include/compiler.h>
++
++#include <vector>
++
++#include <Math/point3d.hxx>
++
++FG_USING_STD(vector);
++
++
++typedef vector < int > int_list;
++typedef int_list::iterator int_list_iterator;
++typedef int_list::const_iterator const_int_list_iterator;
++
++typedef vector < Point3D > point_list;
++typedef point_list::iterator point_list_iterator;
++typedef point_list::const_iterator const_point_list_iterator;
++
++
++#endif // _CONSTRUCT_TYPES_HXX
++
++
++// $Log$
++// Revision 1.1  1999/03/29 13:19:44  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e93857cc0527dd94a1230ca188b36b2cb4af498a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,9 @@@
++bin_PROGRAMS = makedir
++
++makedir_SOURCES = makedir.cxx
++
++makedir_LDADD = \
++      $(top_builddir)/Lib/Bucket/libBucket.a \
++      $(base_LIBS)
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1bc7734cb70006addd0446a0be46dd71cf6a76d7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,119 @@@
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#ifdef HAVE_STDLIB_H
++#include <stdlib.h>
++#endif
++
++#include <stdio.h>
++#include <sys/stat.h> // stat()
++#include <unistd.h>   // stat()
++
++#include <string>
++
++#include <Bucket/bucketutils.h>
++
++
++
++#ifdef WIN32
++#ifndef TRUE
++ #define FALSE 0
++ #define TRUE 1
++#endif
++
++char* PathDivider()
++{
++      return "\\";
++} // PathDivider
++
++void ReplaceDivider( char* path )
++{
++      char    div = PathDivider()[0];
++      int             i;
++
++      if ( ! path )
++              return;
++      if ( div == '/' )
++              return;
++
++      for ( i = 0; path[i]; i++ )
++              if ( path[i] == '/' )
++                      path[i] = div;
++
++} // ReplaceDivider
++
++int   Exists( char* path )
++{
++    struct stat statbuff;
++
++      ReplaceDivider( path );
++      if ( path[strlen( path ) - 1] == ':' )
++              return TRUE;
++      if ( _stat( path, &statbuff ) != 0 )
++              return FALSE;
++      return TRUE;
++} // Exists
++
++
++void CreateDir( char* path )
++{
++      if ( ! path  ||  ! strlen( path ) )
++              return;
++      ReplaceDivider( path );
++                                                              // see if the parent exists yet
++      int             i;      // looping index
++      string  parent; // path to parent
++
++      parent =  path;
++      for ( i = strlen( parent.c_str() )-1; i >= 0; i-- )
++              if ( parent[i] == PathDivider()[0] )
++              {
++                      parent[i] = '\0';
++                      break;
++              }
++      
++      if ( ! Exists( parent.c_str() ) )
++      {
++              CreateDir( parent.c_str() );
++      }
++
++      if ( ! Exists( path ) )
++      {
++              if (mkdir(path, S_IRWXU) != 0 )
++              {
++                      cout << "Could not create directory " << path << endl;
++              }else{
++                      cout << "CreateDir: " << path << endl;
++              }
++      }
++      
++} // CreateDir
++
++
++int main(int argc, char **argv)
++{
++      string root;
++
++      if(argc != 2)
++      {
++              cout << "Makedir failed needs one argument\n";
++              return(10);
++      }
++      root = argv[1];
++      
++      CreateDir(root.c_str());
++      
++      return(0);
++}
++#else
++
++int main(int argc, char **argv)
++{
++      cout << "This program is intended to work with windoze\n";
++      cout << "Other platforms can use mkdir\n";
++}
++
++#endif // WIN32
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..caa4c59be2d6b9f886c185743a22322840845adb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++noinst_LIBRARIES = libPolygon.a
++
++libPolygon_a_SOURCES = \
++      index.cxx index.hxx \
++      names.cxx names.hxx
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..34352aacd187cf8e8fd3a389474895581f8b1175
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,79 @@@
++// index.cxx -- routines to handle a unique/persistant integer polygon index
++//
++// Written by Curtis Olson, started February 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++ 
++#include <Include/compiler.h>
++
++#include STL_STRING
++
++#include <stdio.h>
++
++#include "index.hxx"
++
++
++static long int poly_index;
++static string poly_path;
++
++
++// initialize the unique polygon index counter stored in path
++bool poly_index_init( string path ) {
++    poly_path = path;
++
++    FILE *fp = fopen( poly_path.c_str(), "r" );
++
++    if ( fp == NULL ) {
++      cout << "Error cannot open " << poly_path << endl;
++      poly_index = 0;
++      return false;
++    }
++
++    fscanf( fp, "%ld", &poly_index );
++
++    fclose( fp );
++}
++
++
++// increment the persistant counter and return the next poly_index
++long int poly_index_next() {
++    ++poly_index;
++
++    FILE *fp = fopen( poly_path.c_str(), "w" );
++
++    if ( fp == NULL ) {
++      cout << "Error cannot open " << poly_path << " for writing" << endl;
++    }
++
++    fprintf( fp, "%ld\n", poly_index );
++
++    fclose( fp );
++
++    return poly_index;
++}
++
++
++// $Log$
++// Revision 1.2  1999/03/19 00:27:30  curt
++// Use long int for index instead of just int.
++//
++// Revision 1.1  1999/02/25 21:30:24  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0ea6b5c06b3c03c06baed3e434b1576a3553b9bd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,51 @@@
++// index.cxx -- routines to handle a unique/persistant integer polygon index
++//
++// Written by Curtis Olson, started February 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef _INDEX_HXX
++#define _INDEX_HXX
++
++
++#include <Include/compiler.h>
++
++#include STL_STRING
++
++
++// initialize the unique polygon index counter stored in path
++bool poly_index_init( string path );
++
++// increment the persistant counter and return the next poly_index
++long int poly_index_next();
++
++
++
++#endif // _INDEX_HXX
++
++
++// $Log$
++// Revision 1.2  1999/03/19 00:27:31  curt
++// Use long int for index instead of just int.
++//
++// Revision 1.1  1999/02/25 21:30:24  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2633d19a6b39dd66a9d88d4afef136316058b28c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,146 @@@
++// names.cxx -- process shapefiles names
++//
++// Written by Curtis Olson, started February 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++ 
++#include <Include/compiler.h>
++
++#include STL_STRING
++
++#include "names.hxx"
++
++
++// return area type from text name
++AreaType get_area_type( string area ) {
++    if ( area == "Default" ) {
++      return DefaultArea;
++    } else if ( area == "AirportKeep" ) {
++      return AirportKeepArea;
++    } else if ( area == "AirportIgnore" ) {
++      return AirportIgnoreArea;
++    } else if ( (area == "Swamp or Marsh")
++              || (area == "Marsh") ) {
++      return MarshArea;
++    } else if ( (area == "Bay  Estuary or Ocean")
++                || (area == "Ocean") ) {
++      return OceanArea;
++    } else if ( area == "Lake" ) {
++      return LakeArea;
++    } else if ( (area == "Lake   Dry")
++              || (area == "DryLake") ) {
++      return DryLakeArea;
++    } else if ( (area == "Lake   Intermittent")
++              || (area == "IntermittentLake") ) {
++      return IntLakeArea;
++    } else if ( area == "Reservoir" ) {
++      return ReservoirArea;
++    } else if ( (area == "Reservoir   Intermittent")
++              || (area == "IntermittentReservoir") ) {
++      return IntReservoirArea;
++    } else if ( area == "Stream" ) {
++      return StreamArea;
++    } else if ( area == "Canal" ) {
++      return CanalArea;
++    } else if ( area == "Glacier" ) {
++      return GlacierArea;
++    } else if ( area == "Void Area" ) {
++      return VoidArea;
++    } else if ( area == "Null" ) {
++      return NullArea;
++    } else {
++      cout << "unknown area = '" << area << "'" << endl;
++      // cout << "area = " << area << endl;
++      // for ( int i = 0; i < area.length(); i++ ) {
++      //  cout << i << ") " << (int)area[i] << endl;
++      // }
++      return UnknownArea;
++    }
++}
++
++
++// return text from of area name
++string get_area_name( AreaType area ) {
++    if ( area == DefaultArea ) {
++      return "Default";
++    } else if ( area == AirportKeepArea ) {
++      return "AirportKeep";
++    } else if ( area == AirportIgnoreArea ) {
++      return "AirportIgnore";
++    } else if ( area == MarshArea ) {
++      return "Marsh";
++    } else if ( area == OceanArea ) {
++      return "Ocean";
++    } else if ( area == LakeArea ) {
++      return "Lake";
++    } else if ( area == DryLakeArea ) {
++      return "DryLake";
++    } else if ( area == IntLakeArea ) {
++      return "IntermittentLake";
++    } else if ( area == ReservoirArea ) {
++      return "Reservoir";
++    } else if ( area == IntReservoirArea ) {
++      return "IntermittentReservoir";
++    } else if ( area == StreamArea ) {
++      return "Stream";
++    } else if ( area == CanalArea ) {
++      return "Canal";
++    } else if ( area == GlacierArea ) {
++      return "Glacier";
++    } else if ( area == VoidArea ) {
++      return "VoidArea";
++    } else if ( area == NullArea ) {
++      return "Null";
++    } else {
++      cout << "unknown area code = " << (int)area << endl;
++      return "Unknown";
++    }
++}
++
++
++// $Log$
++// Revision 1.7  1999/04/01 13:52:13  curt
++// Version 0.6.0
++// Shape name tweak.
++// Removing tool: FixNode
++//
++// Revision 1.6  1999/03/27 05:31:24  curt
++// Make 0 the default area type since this corresponds well with the conventions
++//   used by the triangulator.
++//
++// Revision 1.5  1999/03/22 23:49:29  curt
++// Moved AreaType get_shapefile_type(GDBFile *dbf, int rec) to where it
++// belongs in ShapeFile/
++//
++// Revision 1.4  1999/03/13 18:47:04  curt
++// Removed an unused variable.
++//
++// Revision 1.3  1999/03/02 01:03:58  curt
++// Added more reverse lookup support.
++//
++// Revision 1.2  1999/03/01 15:35:52  curt
++// Generalized the routines a bit to make them more useful.
++//
++// Revision 1.1  1999/02/25 21:30:24  curt
++// Initial revision.
++//
++// Revision 1.1  1999/02/23 01:29:05  curt
++// Additional progress.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0a919a5ed8bbaa90393c8a82ace07aaf42efb999
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,89 @@@
++// names.hxx -- process shapefiles names
++//
++// Written by Curtis Olson, started February 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++ 
++
++#ifndef _NAMES_HXX
++#define _NAMES_HXX
++
++
++#include <Include/compiler.h>
++
++#include STL_STRING
++
++FG_USING_STD(string);
++
++
++// Posible shape file types.  Note the order of these is important and
++// defines the priority of these shapes if they should intersect.  The
++// smaller the number, the higher the priority.
++enum AreaType {
++    DefaultArea       = 0,
++    AirportKeepArea   = 1,
++    AirportIgnoreArea = 2,
++    OceanArea         = 3,
++    LakeArea          = 4,
++    DryLakeArea       = 5,
++    IntLakeArea       = 6,
++    ReservoirArea     = 7,
++    IntReservoirArea  = 8,
++    StreamArea        = 9,
++    CanalArea         = 10,
++    GlacierArea       = 11,
++    MarshArea         = 12,
++    VoidArea          = 9997,
++    NullArea          = 9998,
++    UnknownArea       = 9999
++};
++
++
++// return area type from text name
++AreaType get_area_type( string area );
++
++// return text form of area name
++string get_area_name( AreaType area );
++
++
++#endif // _NAMES_HXX
++
++
++// $Log$
++// Revision 1.5  1999/03/27 05:31:25  curt
++// Make 0 the default area type since this corresponds well with the conventions
++//   used by the triangulator.
++//
++// Revision 1.4  1999/03/22 23:49:30  curt
++// Moved AreaType get_shapefile_type(GDBFile *dbf, int rec) to where it
++// belongs in ShapeFile/
++//
++// Revision 1.3  1999/03/01 15:35:53  curt
++// Generalized the routines a bit to make them more useful.
++//
++// Revision 1.2  1999/02/26 22:10:42  curt
++// Updated names and priorities of area types.
++//
++// Revision 1.1  1999/02/25 21:30:24  curt
++// Initial revision.
++//
++// Revision 1.1  1999/02/23 01:29:05  curt
++// Additional progress.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..96c87b41232877923d07691e5564ef3890ecfac6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++SUBDIRS = \
++      DemChop \
++      DemInfo \
++      DemRaw2ascii \
++      GenAirports \
++      ShapeFile
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b3c41b82bc978e0a92f686034b1a32e8cdd017f2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,14 @@@
++bin_PROGRAMS = shape-decode
++
++shape_decode_SOURCES = main.cxx shape.cxx shape.hxx
++
++shape_decode_LDADD = \
++      $(top_builddir)/Tools/Lib/Polygon/libPolygon.a \
++      $(top_builddir)/Lib/Debug/libDebug.a \
++      $(top_builddir)/Lib/Bucket/libBucket.a \
++      $(top_builddir)/Lib/Misc/libMisc.a \
++      $(top_builddir)/Lib/zlib/libz.a \
++      -lgfc -lgpc
++
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b0e629575be0c9fc86ce57c7cfef2bd748c0fddd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,333 @@@
++// main.cxx -- process shapefiles and extract polygon outlines,
++//             clipping against and sorting them into the revelant
++//             tiles.
++//
++// Written by Curtis Olson, started February 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++ 
++
++// Include Geographic Foundation Classes library
++
++// libgfc.a includes need this bit o' strangeness
++#if defined ( linux )
++#  define _LINUX_
++#endif
++#include <gfc/gadt_polygon.h>
++#include <gfc/gdbf.h>
++#include <gfc/gshapefile.h>
++#undef E
++#undef DEG_TO_RAD
++#undef RAD_TO_DEG
++
++// include Generic Polygon Clipping Library
++extern "C" {
++#include <gpc.h>
++}
++
++#include <Include/compiler.h>
++
++#include STL_STRING
++
++#include <Debug/logstream.hxx>
++
++#include <Polygon/index.hxx>
++#include <Polygon/names.hxx>
++#include "shape.hxx"
++
++
++// return the type of the shapefile record
++AreaType get_shapefile_type(GDBFile *dbf, int rec) {
++    // GDBFieldDesc *fdesc[128];      // 128 is an arbitrary number here
++    GDBFValue *fields;                //an array of field values
++    char* dbf_rec;            //a record containing all the fields
++
++    // grab the meta-information for all the fields
++    // this applies to all the records in the DBF file.
++    // for ( int i = 0; i < dbf->numFields(); i++ ) {
++    //   fdesc[i] = dbf->getFieldDesc(i);
++    //   cout << i << ") " << fdesc[i]->name << endl;
++    // }
++
++    // this is the whole name record
++    dbf_rec = dbf->getRecord( rec );
++
++    // parse it into individual fields
++    if ( dbf_rec ) {
++      fields = dbf->recordDeform( dbf_rec );
++    } else {
++      return UnknownArea;
++    }
++
++    string area = fields[4].str_v;
++    // strip leading spaces
++    while ( area[0] == ' ' ) {
++      area = area.substr(1, area.length() - 1);
++    }
++    // strip trailing spaces
++    while ( area[area.length() - 1] == ' ' ) {
++      area = area.substr(0, area.length() - 1);
++    }
++    // strip other junk encountered
++    while ( (int)area[area.length() - 1] == 9 ) {
++      area = area.substr(0, area.length() - 1);
++    }
++
++    return get_area_type( area );
++}
++
++
++int main( int argc, char **argv ) {
++    gpc_polygon gpc_shape;
++    int i, j;
++
++    fglog().setLogLevels( FG_ALL, FG_DEBUG );
++
++    if ( argc != 3 ) {
++      FG_LOG( FG_GENERAL, FG_ALERT, "Usage: " << argv[0] 
++              << " <shape_file> <work_dir>" );
++      exit(-1);
++    }
++
++    FG_LOG( FG_GENERAL, FG_DEBUG, "Opening " << argv[1] << " for reading." );
++
++    // make work directory
++    string work_dir = argv[2];
++    string command = "mkdir -p " + work_dir;
++    system( command.c_str() );
++
++    // initialize persistant polygon counter
++    string counter_file = work_dir + "/../work.counter";
++    poly_index_init( counter_file );
++
++    // initialize structure for building gpc polygons
++    shape_utils_init();
++
++    GShapeFile * sf = new GShapeFile( argv[1] );
++    GDBFile *dbf = new GDBFile( argv[1] );
++    string path = argv[2];
++
++    GPolygon shape;
++    double  *coords; // in decimal degrees
++    int       n_vertices;
++
++    FG_LOG( FG_GENERAL, FG_INFO, "shape file records = " << sf->numRecords() );
++
++    GShapeFile::ShapeType t = sf->shapeType();
++    if ( t != GShapeFile::av_Polygon ) {
++      FG_LOG( FG_GENERAL, FG_ALERT, "Can't handle non-polygon shape files" );
++      exit(-1);
++    }
++
++    for ( i = 0; i < sf->numRecords(); i++ ) {
++      //fetch i-th record (shape)
++      sf->getShapeRec(i, &shape); 
++      FG_LOG( FG_GENERAL, FG_DEBUG, "Record = " << i << "  rings = " 
++              << shape.numRings() );
++
++      AreaType area = get_shapefile_type(dbf, i);
++      FG_LOG( FG_GENERAL, FG_DEBUG, "area type = " << get_area_name(area) 
++              << " (" << (int)area << ")" );
++
++      FG_LOG( FG_GENERAL, FG_INFO, "  record = " << i 
++              << " ring = " << 0 );
++
++      if ( area == MarshArea ) {
++          // interior of polygon is marsh, holes are water
++
++          // do main outline first
++          init_shape(&gpc_shape);
++          n_vertices = shape.getRing(0, coords);
++          add_to_shape(n_vertices, coords, &gpc_shape);
++          process_shape(path, area, &gpc_shape);
++          free_shape(&gpc_shape);
++
++          // do lakes (individually) next
++          for (  j = 1; j < shape.numRings(); j++ ) {
++              FG_LOG( FG_GENERAL, FG_INFO, "  record = " << i 
++                      << " ring = " << j );
++              init_shape(&gpc_shape);
++              n_vertices = shape.getRing(j, coords);
++              add_to_shape(n_vertices, coords, &gpc_shape);
++              process_shape(path, LakeArea, &gpc_shape);
++              free_shape(&gpc_shape);
++          }
++      } else if ( area == OceanArea ) {
++          // interior of polygon is ocean, holes are islands
++
++          init_shape(&gpc_shape);
++          for (  j = 0; j < shape.numRings(); j++ ) {
++              n_vertices = shape.getRing(j, coords);
++              add_to_shape(n_vertices, coords, &gpc_shape);
++          }
++          process_shape(path, area, &gpc_shape);
++          free_shape(&gpc_shape);
++      } else if ( area == LakeArea ) {
++          // interior of polygon is lake, holes are islands
++
++          init_shape(&gpc_shape);
++          for (  j = 0; j < shape.numRings(); j++ ) {
++              n_vertices = shape.getRing(j, coords);
++              add_to_shape(n_vertices, coords, &gpc_shape);
++          }
++          process_shape(path, area, &gpc_shape);
++          free_shape(&gpc_shape);
++      } else if ( area == DryLakeArea ) {
++          // interior of polygon is dry lake, holes are islands
++
++          init_shape(&gpc_shape);
++          for (  j = 0; j < shape.numRings(); j++ ) {
++              n_vertices = shape.getRing(j, coords);
++              add_to_shape(n_vertices, coords, &gpc_shape);
++          }
++          process_shape(path, area, &gpc_shape);
++          free_shape(&gpc_shape);
++      } else if ( area == IntLakeArea ) {
++          // interior of polygon is intermittent lake, holes are islands
++
++          init_shape(&gpc_shape);
++          for (  j = 0; j < shape.numRings(); j++ ) {
++              n_vertices = shape.getRing(j, coords);
++              add_to_shape(n_vertices, coords, &gpc_shape);
++          }
++          process_shape(path, area, &gpc_shape);
++          free_shape(&gpc_shape);
++      } else if ( area == ReservoirArea ) {
++          // interior of polygon is reservoir, holes are islands
++
++          init_shape(&gpc_shape);
++          for (  j = 0; j < shape.numRings(); j++ ) {
++              n_vertices = shape.getRing(j, coords);
++              add_to_shape(n_vertices, coords, &gpc_shape);
++          }
++          process_shape(path, area, &gpc_shape);
++          free_shape(&gpc_shape);
++      } else if ( area == IntReservoirArea ) {
++          // interior of polygon is intermittent reservoir, holes are islands
++
++          init_shape(&gpc_shape);
++          for (  j = 0; j < shape.numRings(); j++ ) {
++              n_vertices = shape.getRing(j, coords);
++              add_to_shape(n_vertices, coords, &gpc_shape);
++          }
++          process_shape(path, area, &gpc_shape);
++          free_shape(&gpc_shape);
++      } else if ( area == StreamArea ) {
++          // interior of polygon is stream, holes are islands
++
++          init_shape(&gpc_shape);
++          for (  j = 0; j < shape.numRings(); j++ ) {
++              n_vertices = shape.getRing(j, coords);
++              add_to_shape(n_vertices, coords, &gpc_shape);
++          }
++          process_shape(path, area, &gpc_shape);
++          free_shape(&gpc_shape);
++      } else if ( area == CanalArea ) {
++          // interior of polygon is canal, holes are islands
++
++          init_shape(&gpc_shape);
++          for (  j = 0; j < shape.numRings(); j++ ) {
++              n_vertices = shape.getRing(j, coords);
++              add_to_shape(n_vertices, coords, &gpc_shape);
++          }
++          process_shape(path, area, &gpc_shape);
++          free_shape(&gpc_shape);
++      } else if ( area == GlacierArea ) {
++          // interior of polygon is glacier, holes are dry land
++
++          init_shape(&gpc_shape);
++          for (  j = 0; j < shape.numRings(); j++ ) {
++              n_vertices = shape.getRing(j, coords);
++              add_to_shape(n_vertices, coords, &gpc_shape);
++          }
++          process_shape(path, area, &gpc_shape);
++          free_shape(&gpc_shape);
++      } else if ( area == VoidArea ) {
++          // interior is ????
++
++          // skip for now
++          FG_LOG(  FG_GENERAL, FG_ALERT, "Void area ... SKIPPING!" );
++
++          if ( shape.numRings() > 1 ) {
++              FG_LOG(  FG_GENERAL, FG_ALERT, "  Void area with holes!" );
++              // exit(-1);
++          }
++
++          init_shape(&gpc_shape);
++          for (  j = 0; j < shape.numRings(); j++ ) {
++              n_vertices = shape.getRing(j, coords);
++              add_to_shape(n_vertices, coords, &gpc_shape);
++          }
++          // process_shape(path, area, &gpc_shape);
++          free_shape(&gpc_shape);
++      } else if ( area == NullArea ) {
++          // interior is ????
++
++          // skip for now
++          FG_LOG(  FG_GENERAL, FG_ALERT, "Null area ... SKIPPING!" );
++
++          if ( shape.numRings() > 1 ) {
++              FG_LOG(  FG_GENERAL, FG_ALERT, "  Null area with holes!" );
++              // exit(-1);
++          }
++
++          init_shape(&gpc_shape);
++          for (  j = 0; j < shape.numRings(); j++ ) {
++              n_vertices = shape.getRing(j, coords);
++              add_to_shape(n_vertices, coords, &gpc_shape);
++          }
++          // process_shape(path, area, &gpc_shape);
++          free_shape(&gpc_shape);
++      } else {
++          FG_LOG(  FG_GENERAL, FG_ALERT, "Uknown area!" );
++          exit(-1);
++      }
++    }
++
++    return 0;
++}
++
++
++// $Log$
++// Revision 1.8  1999/03/22 23:49:36  curt
++// Moved AreaType get_shapefile_type(GDBFile *dbf, int rec) to where it
++// belongs in ShapeFile/
++//
++// Revision 1.7  1999/03/17 23:51:29  curt
++// Changed polygon index counter file.
++//
++// Revision 1.6  1999/03/02 01:04:28  curt
++// Don't crash when work directory doesn't exist ... create it.
++//
++// Revision 1.5  1999/03/01 15:36:28  curt
++// Tweaked a function call name in "names.hxx".
++//
++// Revision 1.4  1999/02/25 21:31:05  curt
++// First working version???
++//
++// Revision 1.3  1999/02/23 01:29:04  curt
++// Additional progress.
++//
++// Revision 1.2  1999/02/19 19:05:18  curt
++// Working on clipping shapes and distributing into buckets.
++//
++// Revision 1.1  1999/02/15 19:10:23  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..badef88238fc820edac252215a2b3890befc50a3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,255 @@@
++// shape.cxx -- shape/gpc utils
++//
++// Written by Curtis Olson, started February 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include <Include/compiler.h>
++
++#include STL_STRING
++
++#include <Bucket/newbucket.hxx>
++#include <Debug/logstream.hxx>
++
++#include <Polygon/index.hxx>
++#include <Polygon/names.hxx>
++#include "shape.hxx"
++
++
++#define FG_MAX_VERTICES 100000
++static gpc_vertex_list v_list;
++
++
++class point2d {
++public:
++    double x, y;
++};
++
++
++static void clip_and_write_poly( string root, long int p_index, AreaType area, 
++                               FGBucket b, gpc_polygon *shape ) {
++    point2d c, min, max;
++    c.x = b.get_center_lon();
++    c.y = b.get_center_lat();
++    double span = bucket_span(c.y);
++    gpc_polygon base, result;
++    char tile_name[256], poly_index[256];
++
++    // calculate bucket dimensions
++    if ( (c.y >= -89.0) && (c.y < 89.0) ) {
++      min.x = c.x - span / 2.0;
++      max.x = c.x + span / 2.0;
++      min.y = c.y - FG_HALF_BUCKET_SPAN;
++      max.y = c.y + FG_HALF_BUCKET_SPAN;
++    } else if ( c.y < -89.0) {
++      min.x = -90.0;
++      max.x = -89.0;
++      min.y = -180.0;
++      max.y = 180.0;
++    } else if ( c.y >= 89.0) {
++      min.x = 89.0;
++      max.x = 90.0;
++      min.y = -180.0;
++      max.y = 180.0;
++    } else {
++      FG_LOG ( FG_GENERAL, FG_ALERT, 
++               "Out of range latitude in clip_and_write_poly() = " << c.y );
++    }
++
++    FG_LOG( FG_GENERAL, FG_INFO, "  (" << min.x << "," << min.y << ") ("
++          << max.x << "," << max.y << ")" );
++
++    // set up clipping tile
++    v_list.vertex[0].x = min.x;
++    v_list.vertex[0].y = min.y;
++
++    v_list.vertex[1].x = max.x;
++    v_list.vertex[1].y = min.y;
++
++    v_list.vertex[2].x = max.x;
++    v_list.vertex[2].y = max.y;
++
++    v_list.vertex[3].x = min.x;
++    v_list.vertex[3].y = max.y;
++
++    v_list.num_vertices = 4;
++
++    base.num_contours = 0;
++    base.contour = NULL;
++    gpc_add_contour( &base, &v_list );
++
++    // FG_LOG( FG_GENERAL, FG_DEBUG, "base = 4 vertices" );
++
++    /*
++    FILE *bfp= fopen("base", "w");
++    gpc_write_polygon(bfp, &base);
++    fclose(bfp);
++    */
++
++    gpc_polygon_clip(GPC_INT, &base, shape, &result);
++
++    if ( result.num_contours > 0 ) {
++      long int t_index = b.gen_index();
++      string path = root + "/Scenery/" + b.gen_base_path();
++      string command = "mkdir -p " + path;
++      system( command.c_str() );
++
++      sprintf( tile_name, "%ld", t_index );
++      string polyfile = path + "/" + tile_name;
++
++      sprintf( poly_index, "%ld", p_index );
++      polyfile += ".";
++      polyfile += poly_index;
++
++      string poly_type = get_area_name( area );
++      if ( poly_type == "Unknown" ) {
++          cout << "unknown area type in clip_and_write_poly()!" << endl;
++          exit(-1);
++      }
++      
++      FILE *rfp= fopen( polyfile.c_str(), "w" );
++      fprintf( rfp, "%s\n", poly_type.c_str() );
++      gpc_write_polygon( rfp, &result );
++      fclose( rfp );
++    }
++
++    gpc_free_polygon(&base);
++    gpc_free_polygon(&result);
++}
++
++
++// Initialize structure we use to create polygons for the gpc library
++bool shape_utils_init() {
++    v_list.num_vertices = 0;
++    v_list.vertex = new gpc_vertex[FG_MAX_VERTICES];;
++
++    return true;
++}
++
++
++// initialize a gpc_polygon
++void init_shape(gpc_polygon *shape) {
++    shape->num_contours = 0;
++    shape->contour = NULL;
++}
++
++
++// make a gpc_polygon
++void add_to_shape(int count, double *coords, gpc_polygon *shape) {
++    
++    for ( int i = 0; i < count; i++ ) {
++      v_list.vertex[i].x = coords[i*2+0];
++      v_list.vertex[i].y = coords[i*2+1];
++    }
++
++    v_list.num_vertices = count;
++    gpc_add_contour( shape, &v_list );
++}
++
++
++// process shape (write polygon to all intersecting tiles)
++void process_shape(string path, AreaType area, gpc_polygon *gpc_shape) {
++    point2d min, max;
++    long int index;
++    int i, j;
++
++    min.x = min.y = 200.0;
++    max.x = max.y = -200.0;
++
++    // find min/max of polygon
++    for ( i = 0; i < gpc_shape->num_contours; i++ ) {
++      for ( j = 0; j < gpc_shape->contour[i].num_vertices; j++ ) {
++          double x = gpc_shape->contour[i].vertex[j].x;
++          double y = gpc_shape->contour[i].vertex[j].y;
++
++          if ( x < min.x ) { min.x = x; }
++          if ( y < min.y ) { min.y = y; }
++          if ( x > max.x ) { max.x = x; }
++          if ( y > max.y ) { max.y = y; }
++      }
++    }
++
++    /*
++    FILE *sfp= fopen("shape", "w");
++    gpc_write_polygon(sfp, gpc_shape);
++    fclose(sfp);
++    exit(-1);
++    */
++      
++    // get next polygon index
++    index = poly_index_next();
++
++    FG_LOG( FG_GENERAL, FG_INFO, "  min = " << min.x << "," << min.y
++          << " max = " << max.x << "," << max.y );
++
++    // find buckets for min, and max points of convex hull.
++    // note to self: self, you should think about checking for
++    // polygons that span the date line
++    FGBucket b_min(min.x, min.y);
++    FGBucket b_max(max.x, max.y);
++    FG_LOG( FG_GENERAL, FG_INFO, "  Bucket min = " << b_min );
++    FG_LOG( FG_GENERAL, FG_INFO, "  Bucket max = " << b_max );
++          
++    if ( b_min == b_max ) {
++      clip_and_write_poly( path, index, area, b_min, gpc_shape );
++    } else {
++      FGBucket b_cur;
++      int dx, dy, i, j;
++          
++      fgBucketDiff(b_min, b_max, &dx, &dy);
++      FG_LOG( FG_GENERAL, FG_INFO, 
++              "  polygon spans tile boundaries" );
++      FG_LOG( FG_GENERAL, FG_INFO, "  dx = " << dx 
++              << "  dy = " << dy );
++
++      if ( (dx > 100) || (dy > 100) ) {
++          FG_LOG( FG_GENERAL, FG_ALERT, 
++                  "somethings really wrong!!!!" );
++          exit(-1);
++      }
++
++      for ( j = 0; j <= dy; j++ ) {
++          for ( i = 0; i <= dx; i++ ) {
++              b_cur = fgBucketOffset(min.x, min.y, i, j);
++              clip_and_write_poly( path, index, area, b_cur, gpc_shape );
++          }
++      }
++      // string answer; cin >> answer;
++    }
++}
++
++
++// free a gpc_polygon
++void free_shape(gpc_polygon *shape) {
++    gpc_free_polygon(shape);
++}
++
++
++// $Log$
++// Revision 1.3  1999/03/19 00:27:41  curt
++// Use long int for index instead of just int.
++//
++// Revision 1.2  1999/02/25 21:31:08  curt
++// First working version???
++//
++// Revision 1.1  1999/02/23 01:29:06  curt
++// Additional progress.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6a59b77e33e866131a1c8ec6ef951a1ec91f5614
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,64 @@@
++// shape.hxx -- shape/gpc utils
++//
++// Written by Curtis Olson, started February 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef _SHAPE_HXX
++#define _SHAPE_HXX
++
++
++// include Generic Polygon Clipping Library
++extern "C" {
++#include <gpc.h>
++}
++
++#include <Polygon/names.hxx>
++
++
++// Initialize structure we use to create polygons for the gpc library
++// this must be called once from main for any program that uses this library
++bool shape_utils_init();
++
++
++// initialize a gpc_polygon
++void init_shape(gpc_polygon *shape);
++
++// make a gpc_polygon
++void add_to_shape(int count, double *coords, gpc_polygon *shape);
++
++// process shape (write polygon to all intersecting tiles)
++void process_shape(string path, AreaType area, gpc_polygon *gpc_shape);
++
++// free a gpc_polygon
++void free_shape(gpc_polygon *shape);
++
++
++#endif // _SHAPE_HXX
++
++
++// $Log$
++// Revision 1.2  1999/02/25 21:31:09  curt
++// First working version???
++//
++// Revision 1.1  1999/02/23 01:29:06  curt
++// Additional progress.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e8f64e5b92b7648eae4ec5ecec3fc05cd2e5bfb0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,77 @@@
++#---------------------------------------------------------------------------
++# Makefile
++#
++# Written by Curtis Olson, started January 1998.
++#
++# Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++# $Id$
++# (Log is kept at end of this file)
++#---------------------------------------------------------------------------
++
++
++bin_PROGRAMS = splittris
++
++splittris_SOURCES = splittris.cxx splittris.hxx
++
++splittris_LDADD = \
++      $(top_builddir)/Lib/Bucket/libBucket.a \
++      $(top_builddir)/Lib/Math/libMath.a \
++        $(top_builddir)/Lib/Debug/libDebug.a \
++      $(top_builddir)/Lib/Misc/libMisc.a \
++        $(top_builddir)/Lib/zlib/libz.a \
++      $(base_LIBS)
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
++
++
++#---------------------------------------------------------------------------
++# $Log$
++# Revision 1.8  1998/11/04 23:01:57  curt
++# Changes to the automake/autoconf system to reduce the number of libraries
++# that are unnecessarily linked into the various executables.
++#
++# Revision 1.7  1998/10/18 01:17:25  curt
++# Point3D tweaks.
++#
++# Revision 1.6  1998/07/30 23:49:26  curt
++# Removed libtool support.
++#
++# Revision 1.5  1998/07/08 14:49:13  curt
++# tweaks.
++#
++# Revision 1.4  1998/04/24 00:44:06  curt
++# Added zlib support.
++#
++# Revision 1.3  1998/04/18 04:01:17  curt
++# Now use libMath rather than having local copies of math routines.
++#
++# Revision 1.2  1998/04/14 02:26:06  curt
++# Code reorganizations.  Added a Lib/ directory for more general libraries.
++#
++# Revision 1.1  1998/04/08 23:21:10  curt
++# Adopted Gnu automake/autoconf system.
++#
++# Revision 1.3  1998/01/21 02:55:55  curt
++# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
++#
++# Revision 1.2  1998/01/14 15:54:42  curt
++# Initial revision completed.
++#
++# Revision 1.1  1998/01/14 02:11:30  curt
++# Initial revision.
++#
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..20e26e7a9dcf3a0dfa6d04d0f7da5c97f1bab3fb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,673 @@@
++// splittris.cxx -- read in a .ele/.node file pair generated by the
++//                  triangle program and output a simple Wavefront .obj
++//                  file for the north, south, east, and west edge
++//                  verticies ... including the normals.
++//
++// Written by Curtis Olson, started January 1998.
++//
++// Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include <math.h>
++#include <stdio.h>
++#include <stdlib.h>   // for atoi()
++#include <string.h>
++#include <sys/stat.h> // for stat()
++#include <unistd.h>   // for stat()
++
++#include "splittris.hxx"
++
++#include <Include/fg_constants.h>
++#include <Bucket/bucketutils.h>
++#include <Math/fg_geodesy.hxx>
++#include <Math/mat3.h>
++#include <Math/point3d.hxx>
++#include <Math/polar3d.hxx>
++#include <Misc/fgstream.hxx>
++
++// int nodecount, tricount;
++double xmin, xmax, ymin, ymax;
++
++// static double nodes_orig[MAX_NODES][3];
++// static Point3D nodes_cart[MAX_NODES];
++// static int tris[MAX_TRIS][3];
++
++container_3d nodes_orig;
++container_3d nodes_cart;
++container_tri tri_list;
++
++fgBUCKET ne_index, nw_index, sw_index, se_index;
++fgBUCKET north_index, south_index, east_index, west_index;
++
++
++// given three points defining a triangle, calculate the normal
++void calc_normal(const Point3D& p1, const Point3D& p2, 
++               const Point3D& p3, double normal[3])
++{
++    double v1[3], v2[3];
++    double temp;
++
++    v1[0] = p2.x() - p1.x(); v1[1] = p2.y() - p1.y(); v1[2] = p2.z() - p1.z();
++    v2[0] = p3.x() - p1.x(); v2[1] = p3.y() - p1.y(); v2[2] = p3.z() - p1.z();
++
++    MAT3cross_product(normal, v1, v2);
++    MAT3_NORMALIZE_VEC(normal,temp);
++
++    // printf("  Normal = %.2f %.2f %.2f\n", normal[0], normal[1], normal[2]);
++}
++
++
++// return the file base name ( foo/bar/file.ext = file.ext )
++string extract_file(const string& input) {
++    int pos;
++
++    pos = input.rfind("/");
++    ++pos;
++
++    return input.substr(pos);
++}
++
++
++// return the file path name ( foo/bar/file.ext = foo/bar )
++string extract_path(const string& input) {
++    int pos;
++
++    pos = input.rfind("/");
++
++    return input.substr(0, pos);
++}
++
++
++// return the index of all triangles containing the specified node
++void find_tris(int n, int *t1, int *t2, int *t3, int *t4, int *t5) {
++    int i;
++
++    *t1 = *t2 = *t3 = *t4 = *t5 = 0;
++
++    i = 1;
++    iterator_tri last = tri_list.end();
++    iterator_tri current = tri_list.begin();
++
++    // skip first null record
++    ++current;
++
++    for ( ; current != last; ++current )
++    {
++        if ( (n == (*current).n1) || (n == (*current).n2) || 
++           (n == (*current).n3) )
++      {
++            if ( *t1 == 0 ) {
++              *t1 = i;
++            } else if ( *t2 == 0 ) {
++              *t2 = i;
++            } else if ( *t3 == 0 ) {
++              *t3 = i;
++            } else if ( *t4 == 0 ) {
++              *t4 = i;
++          } else {
++              *t5 = i;
++          }
++        }
++        ++i;
++    }
++}
++
++
++// Initialize a new mesh structure
++void triload(const string& basename) {
++    string nodename, elename;
++    Point3D node1, node2, p;
++    triangle tri;
++    int nodecount, tricount, dim, junk1, junk2;
++    int i;
++
++    nodename = basename + ".node";
++    elename  = basename + ".ele";
++
++    cout << "Loading node file:  " + nodename + " ...\n";
++
++    fg_gzifstream node_in( nodename );
++    if ( !node_in ) {
++      cout << "Cannot open file " + nodename + "\n";
++      exit(-1);
++    }
++
++    // the triangle program starts counting at 1 by default which is
++    // pretty obnoxious.  Let's just push null record zero's onto our
++    // list to compensate
++    nodes_orig.push_back(node1);
++    nodes_cart.push_back(node1);
++    tri_list.push_back(tri);
++
++    node_in >> nodecount >> dim >> junk1 >> junk2;
++    cout << "    Expecting " << nodecount << " nodes\n";
++
++    for ( i = 1; i <= nodecount; i++ ) {
++      node_in >> junk1 >> node1 >> junk2;
++      nodes_orig.push_back(node1);
++      // printf("%d %.2f %.2f %.2f\n", junk1, node1.x, node1.y, node1.z);
++      
++      // convert to radians (before we can convert to cartesian)
++      p = Point3D( node1.x() * ARCSEC_TO_RAD,
++                   node1.y() * ARCSEC_TO_RAD,
++                   node1.z() );
++
++      node2 = fgGeodToCart(p);
++      nodes_cart.push_back(node2);
++      // printf("%d %.2f %.2f %.2f\n", junk1, node2.x, node2.y, node2.z);
++
++      if ( i == 1 ) {
++          xmin = xmax = node1.x();
++          ymin = ymax = node1.y();
++      } else {
++          if ( node1.x() < xmin ) {
++              xmin = node1.x();
++          }
++          if ( node1.x() > xmax ) {
++              xmax = node1.x();
++          }
++          if ( node1.y() < ymin ) {
++              ymin = node1.y();
++          }
++          if ( node1.y() > ymax ) {
++              ymax = node1.y();
++          }
++      }
++    }
++
++    cout << "Loading element file:  " + elename + " ...\n";
++    fg_gzifstream ele_in( elename );
++    if ( !ele_in ) {
++      cout << "Cannot open file " + elename + "\n";
++      exit(-1);
++    }
++
++    ele_in >> tricount >> junk1 >> junk2;
++    cout << "    Expecting " << tricount << " elements\n";
++
++    for ( i = 1; i <= tricount; i++ ) {
++      // fscanf(ele_file, "%d %d %d %d\n", &junk1, 
++      //        &(tri.n1), &(tri.n2), &(tri.n3));
++      ele_in >> junk1 >> tri.n1 >> tri.n2 >> tri.n3;
++      // printf("%d %d %d %d\n", junk1, tri.n1, tri.n2, tri.n3);
++      tri_list.push_back(tri);
++    }
++}
++
++
++// check if a file exists
++int file_exists(char *file) {
++    struct stat stat_buf;
++    int result;
++
++    cout << "checking " << file << " ... ";
++
++    result = stat(file, &stat_buf);
++
++    if ( result != 0 ) {
++      // stat failed, no file
++      cout << "not found.\n";
++      return 0;
++    } else {
++      // stat succeeded, file exists
++      cout << "exists.\n";
++      return 1;
++    }
++}
++
++
++// check to see if a shared object exists
++int shared_object_exists(const char *basepath, const string& ext) {
++    char file[256], scene_path[256];
++    long int index;
++
++    if ( ext == ".sw" ) {
++      fgBucketGenBasePath(&west_index, scene_path);
++      index = fgBucketGenIndex(&west_index);
++      sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&sw_index, scene_path);
++      index = fgBucketGenIndex(&sw_index);
++      sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&south_index, scene_path);
++      index = fgBucketGenIndex(&south_index);
++      sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( ext == ".se" ) {
++      fgBucketGenBasePath(&east_index, scene_path);
++      index = fgBucketGenIndex(&east_index);
++      sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&se_index, scene_path);
++      index = fgBucketGenIndex(&se_index);
++      sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&south_index, scene_path);
++      index = fgBucketGenIndex(&south_index);
++      sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( ext == ".ne" ) {
++      fgBucketGenBasePath(&east_index, scene_path);
++      index = fgBucketGenIndex(&east_index);
++      sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&ne_index, scene_path);
++      index = fgBucketGenIndex(&ne_index);
++      sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&north_index, scene_path);
++      index = fgBucketGenIndex(&north_index);
++      sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( ext == ".nw" ) {
++      fgBucketGenBasePath(&west_index, scene_path);
++      index = fgBucketGenIndex(&west_index);
++      sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&nw_index, scene_path);
++      index = fgBucketGenIndex(&nw_index);
++      sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&north_index, scene_path);
++      index = fgBucketGenIndex(&north_index);
++      sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( ext == ".south" ) {
++      fgBucketGenBasePath(&south_index, scene_path);
++      index = fgBucketGenIndex(&south_index);
++      sprintf(file, "%s/%s/%ld.1.north", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( ext == ".north" ) {
++      fgBucketGenBasePath(&north_index, scene_path);
++      index = fgBucketGenIndex(&north_index);
++      sprintf(file, "%s/%s/%ld.1.south", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( ext == ".west" ) {
++      fgBucketGenBasePath(&west_index, scene_path);
++      index = fgBucketGenIndex(&west_index);
++      sprintf(file, "%s/%s/%ld.1.east", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( ext == ".east" ) {
++      fgBucketGenBasePath(&east_index, scene_path);
++      index = fgBucketGenIndex(&east_index);
++      sprintf(file, "%s/%s/%ld.1.west", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    return(0);
++}
++
++
++// my custom file opening routine ... don't open if a shared edge or
++// vertex alread exists
++FILE *my_open(const string& basename, const string& basepath, 
++            const string& ext)
++{
++    FILE *fp;
++    string filename;
++
++    // create the output file name
++    filename = basename + ext;
++
++    // check if a shared object already exist from a different tile
++
++    if ( shared_object_exists(basepath.c_str(), ext) ) {
++      // not an actual file open error, but we've already got the
++        // shared edge, so we don't want to create another one
++      cout << "not opening\n";
++      return(NULL);
++    } else {
++      // open the file
++      fp = fopen(filename.c_str(), "w");
++      cout << "Opening " + filename + "\n";
++      return(fp);
++    }
++}
++
++
++// dump in WaveFront .obj format
++void dump_obj(const string& basename, const string& basepath) {
++    Point3D node;
++    double n1[3], n2[3], n3[3], n4[3], n5[3], norm[3], temp;
++    FILE *fp, *sw, *se, *ne, *nw, *north, *south, *east, *west, *body;
++    int i, t1, t2, t3, t4, t5, count, size;
++    double x, y, z;
++
++    sw = my_open(basename, basepath, ".sw");
++    se = my_open(basename, basepath, ".se");
++    ne = my_open(basename, basepath, ".ne");
++    nw = my_open(basename, basepath, ".nw");
++
++    north = my_open(basename, basepath, ".north");
++    south = my_open(basename, basepath, ".south");
++    east = my_open(basename, basepath, ".east");
++    west = my_open(basename, basepath, ".west");
++
++    body = my_open(basename, basepath, ".body");
++
++    cout << "Dumping edges file basename:  " + basename + " ...\n";
++
++    // dump vertices
++    cout << "  writing vertices\n";
++
++    iterator_3d last = nodes_orig.end();
++    iterator_3d current = nodes_orig.begin();
++    ++current;
++    for ( ; current != last; ++current) {
++      node = *current;
++
++      if ( (fabs(node.y() - ymin) < FG_EPSILON) && 
++           (fabs(node.x() - xmin) < FG_EPSILON) ) {
++          fp = sw;
++      } else if ( (fabs(node.y() - ymin) < FG_EPSILON) &&
++                  (fabs(node.x() - xmax) < FG_EPSILON) ) {
++          fp = se;
++      } else if ( (fabs(node.y() - ymax) < FG_EPSILON) &&
++                  (fabs(node.x() - xmax) < FG_EPSILON)) {
++          fp = ne;
++      } else if ( (fabs(node.y() - ymax) < FG_EPSILON) &&
++                  (fabs(node.x() - xmin) < FG_EPSILON) ) {
++          fp = nw;
++      } else if ( fabs(node.x() - xmin) < FG_EPSILON ) {
++          fp = west;
++      } else if ( fabs(node.x() - xmax) < FG_EPSILON ) {
++          fp = east;
++      } else if ( fabs(node.y() - ymin) < FG_EPSILON ) {
++          fp = south;
++      } else if ( fabs(node.y() - ymax) < FG_EPSILON ) {
++          fp = north;
++      } else {
++          fp = body;
++      }
++
++      x = node.x();
++      y = node.y();
++      z = node.z();
++
++      if ( fp != NULL ) {
++          fprintf(fp, "gdn %.2f %.2f %.2f\n", x, y, z);
++      }
++    }
++
++    cout << "  calculating and writing normals\n";
++
++    // calculate and generate normals
++    size = nodes_orig.size();
++    for ( i = 1; i < size; i++ ) {
++      // printf("Finding normal\n");
++
++      find_tris(i, &t1, &t2, &t3, &t4, &t5);
++
++      n1[0] = n1[1] = n1[2] = 0.0;
++      n2[0] = n2[1] = n2[2] = 0.0;
++      n3[0] = n3[1] = n3[2] = 0.0;
++      n4[0] = n4[1] = n4[2] = 0.0;
++      n5[0] = n5[1] = n5[2] = 0.0;
++
++      count = 1;
++      calc_normal(nodes_cart[tri_list[t1].n1],
++                  nodes_cart[tri_list[t1].n2], 
++                  nodes_cart[tri_list[t1].n3],
++                  n1);
++
++      if ( t2 > 0 ) {
++          calc_normal(nodes_cart[tri_list[t2].n1], 
++                      nodes_cart[tri_list[t2].n2], 
++                      nodes_cart[tri_list[t2].n3],
++                      n2);
++          count = 2;
++      }
++
++      if ( t3 > 0 ) {
++          calc_normal(nodes_cart[tri_list[t3].n1],
++                      nodes_cart[tri_list[t3].n2],
++                      nodes_cart[tri_list[t3].n3],
++                      n3);
++          count = 3;
++      }
++
++      if ( t4 > 0 ) {
++          calc_normal(nodes_cart[tri_list[t4].n1],
++                      nodes_cart[tri_list[t4].n2],
++                      nodes_cart[tri_list[t4].n3],
++                      n4);
++          count = 4;
++      }
++
++      if ( t5 > 0 ) {
++          calc_normal(nodes_cart[tri_list[t5].n1],
++                      nodes_cart[tri_list[t5].n2],
++                      nodes_cart[tri_list[t5].n3],
++                      n5);
++          count = 5;
++      }
++
++      // printf("  norm[2] = %.2f %.2f %.2f\n", n1[2], n2[2], n3[2]);
++
++      norm[0] = ( n1[0] + n2[0] + n3[0] + n4[0] + n5[0] ) / (double)count;
++      norm[1] = ( n1[1] + n2[1] + n3[1] + n4[1] + n5[1] ) / (double)count;
++      norm[2] = ( n1[2] + n2[2] + n3[2] + n4[2] + n5[2] ) / (double)count;
++      
++      // printf("  count = %d\n", count);
++      // printf("  Ave. normal = %.4f %.4f %.4f\n", norm[0], norm[1], 
++      //        norm[2]);
++      MAT3_NORMALIZE_VEC(norm, temp);
++      // printf("  Normalized ave. normal = %.4f %.4f %.4f\n", 
++      //        norm[0], norm[1], norm[2]);
++      
++      fp = NULL;
++
++      if ( (fabs(nodes_orig[i].y() - ymin) < FG_EPSILON) && 
++           (fabs(nodes_orig[i].x() - xmin) < FG_EPSILON) ) {
++          fp = sw;
++      } else if ( (fabs(nodes_orig[i].y() - ymin) < FG_EPSILON) &&
++                  (fabs(nodes_orig[i].x() - xmax) < FG_EPSILON) ) {
++          fp = se;
++      } else if ( (fabs(nodes_orig[i].y() - ymax) < FG_EPSILON) &&
++                  (fabs(nodes_orig[i].x() - xmax) < FG_EPSILON)) {
++          fp = ne;
++      } else if ( (fabs(nodes_orig[i].y() - ymax) < FG_EPSILON) &&
++                  (fabs(nodes_orig[i].x() - xmin) < FG_EPSILON) ) {
++          fp = nw;
++      } else if ( fabs(nodes_orig[i].x() - xmin) < FG_EPSILON ) {
++          fp = west;
++      } else if ( fabs(nodes_orig[i].x() - xmax) < FG_EPSILON ) {
++          fp = east;
++      } else if ( fabs(nodes_orig[i].y() - ymin) < FG_EPSILON ) {
++          fp = south;
++      } else if ( fabs(nodes_orig[i].y() - ymax) < FG_EPSILON ) {
++          fp = north;
++      }
++      if ( fp != NULL ) {
++          fprintf(fp, "vn %.4f %.4f %.4f\n", norm[0], norm[1], norm[2]);
++      }
++    }
++
++    if ( sw ) { fclose(sw); }
++    if ( se ) { fclose(se); }
++    if ( ne ) { fclose(ne); }
++    if ( nw ) { fclose(nw); }
++
++    if ( north ) { fclose(north); }
++    if ( south ) { fclose(south); }
++    if ( east ) { fclose(east); }
++    if ( west ) { fclose(west); }
++
++    if ( body ) { fclose(body); }
++}
++
++
++int main(int argc, char **argv) {
++    string basename, basepath, temp;
++    fgBUCKET p;
++    long int index;
++    int len;
++
++    basename = argv[1];
++
++    // find the base path of the file
++    basepath = extract_path(basename);
++    basepath = extract_path(basepath);
++    basepath = extract_path(basepath);
++    cout << "basepath = " + basepath + "\n";
++
++    // find the index of the current file
++    temp = extract_file(basename);
++    len = temp.length();
++    if ( len >= 2 ) {
++      temp = temp.substr(0, len-2);
++    }
++    index = atoi( temp.c_str() );
++    cout << "index = " << index << "\n";
++    fgBucketParseIndex(index, &p);
++
++    cout << "bucket = " << p.lon << " " << p.lat << " " << 
++      p.x << " " << p.y << "\n";
++
++    // generate the indexes of the neighbors
++    fgBucketOffset(&p, &ne_index,  1,  1);
++    fgBucketOffset(&p, &nw_index, -1,  1);
++    fgBucketOffset(&p, &se_index,  1, -1);
++    fgBucketOffset(&p, &sw_index, -1, -1);
++
++    fgBucketOffset(&p, &north_index,  0,  1);
++    fgBucketOffset(&p, &south_index,  0, -1);
++    fgBucketOffset(&p, &east_index,  1,  0);
++    fgBucketOffset(&p, &west_index, -1,  0);
++
++    // printf("Corner indexes = %ld %ld %ld %ld\n", 
++    //        ne_index, nw_index, sw_index, se_index);
++    // printf("Edge indexes = %ld %ld %ld %ld\n",
++    //        north_index, south_index, east_index, west_index);
++        
++
++    // load the input data files
++    triload(basename);
++
++    // dump in WaveFront .obj format
++    dump_obj(basename, basepath);
++
++    return(0);
++}
++
++
++// $Log$
++// Revision 1.7  1998/11/06 21:33:57  curt
++// Updates to go along with changes in fgstream.
++//
++// Revision 1.6  1998/10/21 14:56:20  curt
++// Fixed a units conversion bug.
++//
++// Revision 1.5  1998/10/20 15:50:33  curt
++// whitespace tweak.
++//
++// Revision 1.4  1998/10/18 01:17:27  curt
++// Point3D tweaks.
++//
++// Revision 1.3  1998/09/22 23:49:56  curt
++// C++-ified, STL-ified, and string-ified.
++//
++// Revision 1.2  1998/09/21 23:16:23  curt
++// Converted to c++ style comments.
++//
++// Revision 1.1  1998/07/08 14:59:13  curt
++// *.[ch] renamed to *.[ch]xx
++//
++// Revision 1.11  1998/07/04 00:56:40  curt
++// typedef'd struct fgBUCKET.
++//
++// Revision 1.10  1998/05/02 01:54:37  curt
++// Converting to polar3d.h routines.
++//
++// Revision 1.9  1998/04/18 04:01:20  curt
++// Now use libMath rather than having local copies of math routines.
++//
++// Revision 1.8  1998/04/14 02:26:08  curt
++// Code reorganizations.  Added a Lib/ directory for more general libraries.
++//
++// Revision 1.7  1998/04/08 23:21:13  curt
++// Adopted Gnu automake/autoconf system.
++//
++// Revision 1.6  1998/03/03 15:36:13  curt
++// Tweaks for compiling with g++
++//
++// Revision 1.5  1998/03/03 03:37:04  curt
++// Cumulative tweaks.
++//
++// Revision 1.4  1998/01/31 00:41:26  curt
++// Made a few changes converting floats to doubles.
++//
++// Revision 1.3  1998/01/27 18:37:04  curt
++// Lots of updates to get back in sync with changes made over in .../Src/
++//
++// Revision 1.2  1998/01/14 15:54:43  curt
++// Initial revision completed.
++//
++// Revision 1.1  1998/01/14 02:11:31  curt
++// Initial revision.
++//
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..12787872d92c3f4206eff6e2017cb5273f0e1c2b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,89 @@@
++// splittris.hxx -- read in a .ele/.node file pair generated by the triangle 
++//                  program and output edge vertices w/ normals.
++//
++// Written by Curtis Olson, started January 1998.
++//
++// Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++
++#ifndef SPLITTRIS_HXX
++#define SPLITTRIS_HXX
++
++
++#include <stdio.h>
++#include <string.h>
++#include <string>
++
++#include <vector>
++#include "Include/fg_stl_config.h"
++
++#ifdef NEEDNAMESPACESTD
++using namespace std;
++#endif
++
++#include <Math/point3d.hxx>
++
++
++// A triangle (indices of the three nodes)
++typedef struct {
++    int n1, n2, n3;
++} triangle;
++
++
++typedef vector < Point3D > container_3d;
++typedef container_3d::iterator iterator_3d;
++typedef container_3d::const_iterator const_iterator_3d;
++
++typedef vector < triangle > container_tri;
++typedef container_tri::iterator iterator_tri;
++typedef container_tri::const_iterator const_iterator_tri;
++
++
++// Initialize a new mesh structure
++void triload(const string& basename);
++
++
++#endif // SPLITTRIS_HXX
++
++
++// $Log$
++// Revision 1.4  1998/10/18 01:17:28  curt
++// Point3D tweaks.
++//
++// Revision 1.3  1998/09/22 23:49:58  curt
++// C++-ified, STL-ified, and string-ified.
++//
++// Revision 1.2  1998/09/21 23:16:24  curt
++// Converted to c++ style comments.
++//
++// Revision 1.1  1998/07/08 14:59:14  curt
++// *.[ch] renamed to *.[ch]xx
++//
++// Revision 1.3  1998/03/03 15:36:13  curt
++// Tweaks for compiling with g++
++//
++// Revision 1.2  1998/01/15 02:49:25  curt
++// Misc. housekeeping.
++//
++// Revision 1.1  1998/01/14 02:11:32  curt
++// Initial revision.
++//
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8373ea88bd6d4ce910813d9f3b96d0483c1c8224
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,30 @@@
++bin_PROGRAMS = strips
++
++strips_SOURCES = \
++      add.c add.h \
++      bands.c \
++      common.c common.h \
++      define.h \
++      extend.h \
++      free.c free.h \
++      global.h \
++      glove.h \
++      init.c init.h \
++      local.c local.h \
++      my_global.h \
++      newpolve.c \
++      options.c options.h \
++      output.c output.h \
++      outputex.c outputex.h \
++      partial.c partial.h \
++      polverts.h polvertsex.h \
++      queue.c queue.h \
++      sgi_triang.c sgi_triangex.c \
++      struct.c struct.h \
++      structex.c \
++      sturcts.h sturctsex.h \
++      ties.c ties.h \
++      triangulate.h triangulatex.h \
++      util.c util.h
++
++strips_LDADD = $(base_LIBS)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7d90357fd3981184eea17e5b88fc60d042a09fe5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,386 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: add.c
++     This file contains the procedure code that will add information
++     to our data structures.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++#include <string.h>
++#include "global.h"
++#include "queue.h"
++#include "polverts.h"
++#include "triangulate.h"
++#include "ties.h"
++#include "outputex.h"
++#include "options.h"
++#include "local.h"
++
++BOOL new_vertex(double difference, int id1,int id2,
++                struct vert_struct *n)
++{
++     /*   Is the difference between id1 and id2 (2 normal vertices that
++          mapped to the same vertex) greater than the
++          threshold that was specified?
++     */
++     struct vert_struct *pn1,*pn2;
++     double dot_product;
++     double distance1, distance2,distance;
++     double rad;
++     char arg1[100];
++     char arg2[100];
++
++     pn1 = n + id1;
++     pn2 = n + id2;
++ 
++     dot_product = ((pn1->x) * (pn2->x)) +
++                   ((pn1->y) * (pn2->y)) +
++                   ((pn1->z) * (pn2->z));
++     /*   Get the absolute value */
++     if (dot_product < 0)
++          dot_product = dot_product * -1;
++
++     distance1 = sqrt( (pn1->x * pn1->x) +
++                       (pn1->y * pn1->y) +
++                       (pn1->z * pn1->z) );
++     distance2 = sqrt( (pn2->x * pn2->x) +
++                       (pn2->y * pn2->y) +
++                       (pn2->z * pn2->z) );
++     distance = distance1 * distance2;
++
++     rad = acos((double)dot_product/(double)distance);
++     /*   convert to degrees */
++     rad = (180 * rad)/PI;
++    
++     if ( rad <= difference)
++         return FALSE;
++     
++     /*   double checking because of imprecision with floating
++          point acos function
++     */
++     sprintf( arg1,"%.5f", rad );
++     sprintf( arg2,"%.5f", difference );
++     if ( strcmp( arg1, arg2 ) <=0 )
++          return( FALSE );
++     if ( rad <= difference)
++         return FALSE;
++     else 
++          return TRUE;
++}
++
++BOOL Check_VN(int vertex,int normal, struct vert_added *added)
++{
++     /*   Check to see if we already added this vertex and normal */
++     register int x,n;
++
++     n = (added+vertex)->num;
++     for (x = 0; x < n; x++)
++     {
++          if (*((added+vertex)->normal+x) == normal)
++               return TRUE;
++     }
++     return FALSE;
++}
++
++BOOL norm_array(int id, int vertex, double normal_difference,
++                struct vert_struct *n, int num_vert)
++{
++     static int last;
++     static struct vert_added *added;
++     register int x;
++     static BOOL first = TRUE;
++
++     if (first)
++     {
++          /*   This is the first time that we are in here, so we will allocate
++               a structure that will save the vertices that we added, so that we
++               do not add the same thing twice
++          */
++          first = FALSE;
++          added = (struct vert_added *) malloc (sizeof (struct vert_added ) * num_vert);
++          /*   The number of vertices added for each vertex must be initialized to
++               zero
++          */
++          for (x = 0; x < num_vert; x++)
++               (added+x)->num = 0;
++     }
++     
++     if (vertex)
++          /*   Set the pointer to the vertex, we will be calling again with the
++               normal to fill it with
++          */
++          last = id;
++     else
++     {    
++          /*   Fill the pointer with the id of the normal */
++          if (*(vert_norms + last) == 0)
++               *(vert_norms + last) = id;
++          else if ((*(vert_norms + last) != id) && ((int)normal_difference != 360))
++          {
++               /*   difference is big enough, we need to create a new vertex */
++               if (new_vertex(normal_difference,id,*(vert_norms + last),n))
++               {
++                    /*   First check to see if we added this vertex and normal already */
++                    if (Check_VN(last,id,added))
++                         return FALSE;
++                    /*   OK, create the new vertex, and have its id = the number of vertices
++                         and its normal what we have here
++                    */
++                    vert_norms = realloc(vert_norms, sizeof(int) * (num_vert + 1));
++                    if (!vert_norms)
++                    {
++                         printf("Allocation error - aborting\n");
++                         exit(1);
++                    }
++                    *(vert_norms + num_vert) = id;
++                    /*   We created a new vertex, now put it in our added structure so
++                         we do not add the same thing twice
++                    */
++                    (added+last)->num = (added+last)->num + 1;
++                    if ((added+last)->num == 1)
++                    {
++                         /*   First time */
++                         (added+last)->normal =  (int *) malloc (sizeof (int ) * 1);
++                         *((added+last)->normal) =  id;
++                    }
++                    else
++                    {
++                         /*   Not the first time, reallocate space */
++                         (added+last)->normal = realloc((added+last)->normal,sizeof(int) * (added+last)->num);
++                         *((added+last)->normal+((added+last)->num-1)) = id;
++                    }
++                    return TRUE;
++               }
++          }
++     }
++     return FALSE;
++}
++
++void add_texture(int id,BOOL vertex)
++{
++     /*   Save the texture with its vertex for future use when outputting */
++     static int last;
++
++     if (vertex)
++          last = id;
++     else
++          *(vert_texture+last) = id;
++}
++
++int   add_vert_id(int id, int index_count)
++{
++      register int x;
++     
++     /*   Test if degenerate, if so do not add degenerate vertex */
++     for (x = 1; x < index_count ; x++)
++     {
++          if (ids[x] == id)
++               return 0;
++     }
++     ids[index_count] = id;
++     return 1;
++}
++
++void  add_norm_id(int id, int index_count)
++{
++      norms[index_count] = id;
++}
++
++void AddNewFace(int ids[MAX1], int vert_count, int face_id, int norms[MAX1])
++{
++PF_FACES pfNode;
++int   *pTempInt;
++int *pnorms;
++F_EDGES **pTempVertptr;
++int   *pTempmarked, *pTempwalked;
++register int  y,count = 0,sum = 0;
++      
++      /*   Add a new face into our face data structure */
++
++     pfNode = (PF_FACES) malloc(sizeof(F_FACES) );
++     if ( pfNode )
++     {
++          pfNode->pPolygon = (int*) malloc(sizeof(int) * (vert_count) );
++      pfNode->pNorms = (int*) malloc(sizeof(int) * (vert_count) );
++          pfNode->VertandId = (F_EDGES**)malloc(sizeof(F_EDGES*) * (vert_count)); 
++              pfNode->marked  = (int*)malloc(sizeof(int) * (vert_count));
++              pfNode->walked = (int*)malloc(sizeof(int) * (vert_count));
++      }
++      pTempInt =pfNode->pPolygon;
++      pnorms = pfNode->pNorms;
++     pTempmarked = pfNode->marked;
++      pTempwalked = pfNode->walked;
++      pTempVertptr = pfNode->VertandId;
++      pfNode->nPolSize = vert_count;
++      pfNode->seen = -1;
++     pfNode->seen2 = -1;
++      for (y=1;y<=vert_count;y++)
++      {
++              *(pTempInt + count) = ids[y];
++              *(pnorms + count) = norms[y];
++          *(pTempmarked + count) = FALSE;
++              *(pTempwalked + count) =  -1;
++              *(pTempVertptr+count) = NULL;
++              count++;
++      }
++        AddHead(PolFaces[face_id-1],(PLISTINFO) pfNode);
++}     
++
++      
++void CopyFace(int ids[MAX1], int vert_count, int face_id, int norms[MAX1])
++{
++PF_FACES pfNode;
++int   *pTempInt;
++int *pnorms;
++F_EDGES **pTempVertptr;
++int   *pTempmarked, *pTempwalked;
++register int  y,count = 0,sum = 0;
++      
++      /*   Copy a face node into a new node, used after the global algorithm
++          is run, so that we can save whatever is left into a new structure
++     */
++     
++     pfNode = (PF_FACES) malloc(sizeof(F_FACES) );
++     if ( pfNode )
++     {
++          pfNode->pPolygon = (int*) malloc(sizeof(int) * (vert_count) );
++      pfNode->pNorms = (int*) malloc(sizeof(int) * (vert_count) );
++          pfNode->VertandId = (F_EDGES**)malloc(sizeof(F_EDGES*) * (vert_count)); 
++              pfNode->marked  = (int*)malloc(sizeof(int) * (vert_count));
++              pfNode->walked = (int*)malloc(sizeof(int) * (vert_count));
++      }
++      pTempInt =pfNode->pPolygon;
++      pnorms = pfNode->pNorms;
++     pTempmarked = pfNode->marked;
++      pTempwalked = pfNode->walked;
++      pTempVertptr = pfNode->VertandId;
++      pfNode->nPolSize = vert_count;
++      pfNode->seen = -1;
++     pfNode->seen2 = -1;
++      for (y=0;y<vert_count;y++)
++      {
++              *(pTempInt + count) = ids[y];
++              *(pnorms + count) = norms[y];
++          *(pTempmarked + count) = FALSE;
++              *(pTempwalked + count) =  -1;
++              *(pTempVertptr+count) = NULL;
++              count++;
++      }
++      AddHead(PolFaces[face_id-1],(PLISTINFO) pfNode);
++}     
++      
++void Add_Edge(int v1,int v2)
++{
++PF_EDGES temp  = NULL;
++ListHead *pListHead;
++BOOL flag = TRUE;
++register int t,count = 0;
++      
++      /*   Add a new edge into the edge data structure */
++     if (v1 > v2)
++      {
++              t  = v1;
++              v1 = v2;
++              v2 = t;
++      }
++      
++     pListHead = PolEdges[v1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++      if (temp == NULL)
++     {
++          printf("Have the wrong edge \n:");
++          exit(1);
++     }
++      
++      while (flag)
++      {
++              if (v2 == temp->edge[0])
++               return;
++          else
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,++count);
++
++      }                       
++}
++
++void Add_AdjEdge(int v1,int v2,int fnum,int index1 )
++{
++     PF_EDGES temp  = NULL;
++     PF_FACES temp2 = NULL;
++     PF_EDGES pfNode;
++     ListHead *pListHead;
++     ListHead *pListFace;
++     BOOL     flag = TRUE;
++     register int     count = 0;
++     register int     t,v3 = -1;
++      
++      if (v1 > v2)
++      {
++              t  = v1;
++              v1 = v2;
++              v2 = t;
++      }
++      pListFace  = PolFaces[fnum];
++      temp2 = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
++      pListHead = PolEdges[v1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++      if (temp == NULL)
++              flag = FALSE;
++      count++;
++      while (flag)
++      {
++              if (v2 == temp->edge[0])
++              {
++               /*   If greater than 2 polygons adjacent to an edge, then we will
++                    only save the first 2 that we found. We will have a small performance
++                    hit, but this does not happen often.
++               */
++               if (temp->edge[2] == -1)
++                    temp->edge[2] = fnum;
++               else
++                    v3 = temp->edge[2];
++                      flag = FALSE;
++              }
++              else
++              {
++                      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++                      count++;
++                      if (temp == NULL)
++                              flag = FALSE;
++              }
++      }
++                
++      /*   Did not find it */
++     if (temp == NULL)
++      {
++              pfNode = (PF_EDGES) malloc(sizeof(F_EDGES) );
++          if ( pfNode )
++          {
++               pfNode->edge[0] = v2;
++                      pfNode->edge[1] = fnum;
++                pfNode->edge[2] =  v3;
++                      AddTail( PolEdges[v1], (PLISTINFO) pfNode );
++          }
++              else
++          {
++               printf("Out of memory!\n");
++               exit(1);
++          }
++              
++          *(temp2->VertandId+index1) = pfNode;
++      }
++      else
++              *(temp2->VertandId+index1) =  temp;
++              
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..607363e5e531465c7a9b6414c87ef46181f594de
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,25 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: add.h
++-----------------------------------------------------------------------*/
++
++BOOL new_vertex();
++BOOL Check_VN();
++BOOL norm_array();
++void add_texture();
++int   add_vert_id();
++void  add_norm_id();
++void AddNewFace();
++void CopyFace();
++void Add_Edge();
++void Add_AdjEdge();
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..14a9fe4c0a07760570e07b46129ea5d4db4f3040
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,549 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: bands.c
++     This file contains the main procedure code that will read in the
++     object and then call the routines that produce the triangle strips.
++*/
++/*---------------------------------------------------------------------*/
++
++  
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++#include <string.h>
++#include "global.h"
++#include "polverts.h"
++#include "triangulate.h"
++#include "ties.h"
++#include "outputex.h"
++#include "options.h"
++#include "local.h"
++#include "init.h"
++#include "free.h"
++#include "add.h"
++
++#define MAX1 60
++/*   TIMING for Windows */
++#ifdef WIN32
++#include <sys/timeb.h>
++#include <time.h>
++/*   TIMING for UNIX */
++#else
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/times.h>
++#include        <sys/time.h>
++struct timeval   tm;
++struct timezone  tz;
++double           et;
++#define START gettimeofday(&tm,&tz);\
++                et = (tm.tv_sec)+ (0.000001* (tm.tv_usec));
++
++#define STOP gettimeofday(&tm,&tz);\
++                et = (tm.tv_sec)+(0.000001*(tm.tv_usec)) - et;
++#endif
++
++
++void get_time()
++{
++     /*   For timing */
++     #ifdef WIN32
++          struct _timeb timebuffer;
++          char *timeline;
++     #else
++          long timer;
++     #endif
++
++
++     #ifdef WIN32
++          _ftime( &timebuffer );
++          timeline = ctime( & ( timebuffer.time ) );
++          printf( "The time is %.19s.%hu %s", timeline, timebuffer.millitm, &timeline[20] );
++     #else
++            printf("Time for last frame  = %lf seconds\n", et);
++     #endif
++}
++
++/*
++** 
++     Here the main program begins. It will start by loading in a .obj file
++     then it will convert the polygonal model into triangle strips.
++**  
++*/
++
++void main (int argc,char *argv[])
++{
++      char    *fname,*all,buff[255], *ptr, *ptr2;
++      FILE    *file, *bands;
++      int face_id=0, vert_count, loop, num=0,num2;
++      float center[3];
++     int temp[MAX1],vertex,strips, swaps,tempi,cost,triangles;
++     int f,t,tr,g;
++     char *file_open;
++      int     num_vert        = 0,
++              num_faces       = 0,
++              num_nvert       = 0,
++              num_edges       = 0,
++          num_texture = 0,
++          num_tris = 0;
++     double fra = 0.0;
++     BOOL texture, normal, normal_and_texture,quads = FALSE;
++
++     /*   Options variables */
++     float norm_difference;
++
++      /*   Structures for the object */
++     struct vert_struct       *vertices       = NULL,
++                              *nvertices      = NULL,
++                              *pvertices      = NULL,
++                              *pnvertices     = NULL;
++
++     get_time();
++     START
++
++     /*   File that will contain the triangle strip data */
++     bands = fopen("bands.d","w");
++
++     /*
++           Scan the file once to find out the number of vertices,
++           vertice normals, and faces so we can set up some memory
++           structures 
++      */
++      /* Interpret the options specified */
++      norm_difference = get_options(argc,argv,&f,&t,&tr,&g);
++     if (f == BINARY)
++          file_open = "rb";
++     else
++          file_open = "r";
++
++      fname = argv[argc-1];
++     printf ("File: %s\n",fname);
++      /*printf ("Scanning...%s ",file_open);*/
++
++          
++     /*   File can be in binary for faster reading */
++     if (file = fopen (fname,file_open))
++      {
++              while (!feof (file))
++              {
++                      /*   Read a line */
++               if (f == BINARY)
++                    fread (buff,sizeof(char) * 255,1, file);
++                      else
++                    fgets (buff, sizeof(char) * 255, file);
++              num++;
++               /*   At a vertex */
++               if (*buff == 'v')
++                      {
++                              /*   At a normal */
++                    if (*(buff+1)=='n')
++                                      num_nvert++;
++                              else if (*(buff+1)=='t')
++                         num_texture++;
++                    /*   At a regular vertex */
++                    else
++                                      num_vert++;
++                      }
++                      /*   At a face */
++               else if (*buff == 'f')
++                      {  
++                    num_faces++;
++                           strtok(buff, " ");
++                           tempi = 0;
++                           while (strtok(NULL, " ") != NULL) tempi++;
++                           num_tris += tempi - 2;
++               }
++              }
++              fclose (file);
++      }
++
++      else
++     {
++              printf("Error in the file name\n");
++          exit(1);
++     }
++      
++      
++      /* Allocate structures for the information */
++      Start_Face_Struct(num_faces);
++      vertices = (struct vert_struct *)
++                      malloc (sizeof (struct vert_struct) * num_vert);
++
++      if (num_nvert > 0) 
++     {
++          nvertices = (struct vert_struct *)
++                      malloc (sizeof (struct vert_struct) * num_nvert);
++          vert_norms = (int *) 
++               malloc (sizeof (int) * num_vert);
++          /*   Initialize entries to zero, in case there are 2 hits
++               to the same vertex we will know it - used for determining
++               the normal difference
++          */
++          init_vert_norms(num_vert);
++     }
++      else 
++              nvertices = NULL;
++
++     if (num_texture > 0)
++     {
++          vert_texture = (int *) malloc (sizeof(int) * num_vert);
++          init_vert_texture(num_vert);
++     }
++     
++      /*   Set up the temporary 'p' pointers 
++     */
++      pvertices = vertices;
++      pnvertices = nvertices;
++
++      /* Load the object into memory */
++      /*printf (" Loading...");*/
++ 
++     fprintf(bands,"#%s: a triangle strip representation created by STRIPE.\n#This is a .objf file\n#by Francine Evans\n",fname);
++ 
++     /*  File will be put in a list for faster execution if file is in binary */   
++     if (file = fopen(fname,file_open))
++     {
++          if (f == BINARY)
++          {
++               all = (char *) malloc (sizeof(char) * 255 * num);
++               fread(all,sizeof(char) * 255 * num, 1, file);
++              ptr = all;
++          }
++          else
++               ptr = (char *) malloc (sizeof(char) * 255 * num);
++     }
++
++   
++     while (num > 0)
++      {
++          num--;
++              if (f == ASCII)
++               fgets (ptr, sizeof(char) * 255, file);
++          else
++               ptr = ptr + 255;
++
++          /* Load in vertices/normals */
++              if (*ptr == 'v')
++              {
++                      if (*(ptr+1)=='n')
++                      {
++                              sscanf (ptr+3,"%lf%lf%lf",
++                                      &(pnvertices->x),
++                                      &(pnvertices->y),
++                                      &(pnvertices->z));
++                              fprintf(bands,"vn %lf %lf %lf\n",
++                                      pnvertices->x,pnvertices->y,pnvertices->z); 
++                      ++pnvertices;
++                      }
++                      else if (*(ptr+1)=='t')
++               {
++                              sscanf (ptr+3,"%f%f%f",&center[0],&center[1],&center[2]);
++                              fprintf(bands,"vt %f %f %f\n",center[0],center[1],center[2]); 
++               }
++               else
++                      {
++                              sscanf (ptr+2,"%lf%lf%lf",
++                                      &(pvertices->x), 
++                                      &(pvertices->y), 
++                                      &(pvertices->z));
++                      fprintf(bands,"v %lf %lf %lf\n",
++                                      pvertices->x,pvertices->y,pvertices->z); 
++                              ++pvertices;
++               }
++              }
++              
++          else if (*ptr == 'f')
++              {
++                      /* Read in faces */
++                      num2 = 0;
++                      face_id++;
++               ptr2 = ptr+1;
++               normal = FALSE; texture = FALSE, normal_and_texture = FALSE;
++               while (*ptr2)
++               {
++                         if (*ptr2 >='0' && *ptr2 <='9')
++                         {
++                              num2++;
++                              ++ptr2;
++                              while (*ptr2 && (*ptr2!=' ' && *ptr2!='/'))
++                                      ptr2++;
++                    /*   There are normals in this line */
++                    if (*ptr2 == '/')
++                    {
++                         if (*(ptr2+1) == '/')
++                              normal = TRUE;
++                         else
++                              texture = TRUE;
++                           }
++                    else if (*ptr2 == ' ')
++                    {
++                         if ((num2 == 3) && (texture))
++                              normal_and_texture = TRUE;
++                    }
++                  }
++                         else
++                                 ++ptr2;
++                      }
++
++               ptr2 = ptr+1;
++                      
++               /* loop on the number of numbers in this line of face data 
++               */
++                      vert_count = 0;
++                                                              
++                      for (loop=0;loop<num2;loop++)
++                      {
++                              /* skip the whitespace */
++                              while (*ptr2<'0' || *ptr2>'9')
++                    {
++                         if (*ptr2 == '-')
++                              break;
++                         ptr2++;
++                    }
++                              vertex = atoi(ptr2)-1;
++                    if (vertex < 0)
++                    {
++                         vertex = num_vert + vertex;
++                         *ptr2 = ' ';
++                         ptr2++;
++                    }
++                    /*   If there are either normals or textures with the vertices
++                         in this file, the data alternates so we must read it this way 
++                    */
++                              if ( (normal) && (!normal_and_texture))
++                              {
++                                      if (loop%2)
++                         {
++                              add_norm_id(vertex,vert_count);
++                              /*   Test here to see if we added a new vertex, since the
++                                   vertex has more than one normal and the 2 normals are greater
++                                   than the threshold specified
++                              */
++                              if (norm_array(vertex,0,norm_difference,nvertices,num_vert))
++                              {
++                                   /*   Add a new vertex and change the
++                                        id of the vertex that we just read to the id of the new
++                                        vertex that we just added
++                                   */
++                                   /*   Put it in the output file, note the added vertices will
++                                        be after the normals and separated from the rest of the 
++                                        vertices. Will not affect our viewer
++                                   */
++                                   fprintf(bands,"v %lf %lf %lf\n",
++                                          (vertices + temp[vert_count - 1])->x,
++                                          (vertices + temp[vert_count - 1])->y,
++                                          (vertices + temp[vert_count - 1])->z); 
++                                   num_vert++;
++                                   temp[vert_count - 1] = num_vert - 1;
++                                   if (!(add_vert_id(num_vert - 1,vert_count)))
++                                        vert_count--;
++                              }
++                         }
++                                      /*   the vertex */
++                         else 
++                                      {
++                                              temp[vert_count] = vertex ;
++                                              vert_count++;
++                              if (!(add_vert_id(vertex,vert_count)))
++                                   vert_count--;
++                              norm_array(vertex,1,norm_difference,nvertices,num_vert);
++                                      }
++                    }
++                         
++                    /*   Else there are vertices and textures with the data */
++                    else if (normal_and_texture)
++                    {
++                         if( !((loop+1)%3))
++                         {
++                              add_norm_id(vertex,vert_count);
++                              /*   Test here to see if we added a new vertex, since the
++                                   vertex has more than one normal and the 2 normals are greater
++                                   than the threshold specified
++                              */
++                              if (norm_array(vertex,0,norm_difference,nvertices,num_vert))
++                              {
++                                   /*   Add a new vertex and change the
++                                        id of the vertex that we just read to the id of the new
++                                        vertex that we just added
++                                   */
++                                   /*   Put it in the output file, note the added vertices will
++                                        be after the normals and separated from the rest of the 
++                                        vertices. Will not affect our viewer
++                                   */
++                                   fprintf(bands,"v %lf %lf %lf\n",
++                                          (vertices + temp[vert_count - 1])->x,
++                                          (vertices + temp[vert_count - 1])->y,
++                                          (vertices + temp[vert_count - 1])->z); 
++                                   num_vert++;
++                                   temp[vert_count - 1] = num_vert - 1;
++                                   if (!(add_vert_id(num_vert - 1,vert_count)))
++                                        vert_count--;
++                              }
++                         }
++                         /*   the vertex */
++                         else if ((loop == 0) || (*(ptr2-1) == ' '))
++                                      {
++                                              temp[vert_count] = vertex ;
++                                              vert_count++;
++                              if (vert_count == 4)
++                                   quads = TRUE;
++                              if (!(add_vert_id(vertex,vert_count)))
++                                   vert_count--;
++                              add_texture(vertex,TRUE);
++                              norm_array(vertex,1,norm_difference,nvertices,num_vert);
++                                      }
++                         else /*   The texture */
++                              add_texture(vertex,FALSE);
++                    }
++                              
++                              else if ( texture )
++                              {
++                                      /*   the vertex */
++                         if (!(loop%2))
++                                      {
++                                              temp[vert_count] = vertex ;
++                                              vert_count++;
++                              if (vert_count == 4)
++                                   quads = TRUE;
++                              add_texture(vertex,TRUE);
++                              if (!(add_vert_id(vertex,vert_count)))
++                                   vert_count--;
++                              norm_array(vertex,1,norm_difference,nvertices,num_vert);
++                                      }
++                         else /*   texture */
++                              add_texture(vertex,FALSE);
++                    }
++ 
++                    else
++                              {
++                                  /*** no nvertices ***/
++                                      temp[vert_count] = vertex ;
++                                      vert_count++;
++                         if (vert_count == 4)
++                              quads = TRUE;
++                         if (!(add_vert_id(vertex,vert_count)))
++                              vert_count--;
++                              }
++                              while (*ptr2>='0' && *ptr2<='9')
++                                      ptr2++;
++               }
++                      /* Done with the polygon */
++                      num_edges += vert_count;
++                      /* add it to face structure */
++                      if (vert_count >= 3)
++                    AddNewFace(ids,vert_count,face_id,norms);
++               else
++                    face_id--;
++               if (vert_count == 4)
++                    quads = TRUE;
++          }
++          else if ((g == TRUE) && (face_id > 0)
++                      && ((*ptr == 'g') || (*ptr  == 's') || (*ptr == 'm') || (*ptr == 'o')))
++          {
++               /*   The user specified that the strips will be contained in each group
++                    from the data file, so we just finished a group and will find the
++                    triangle strips in it.
++               */
++               Start_Edge_Struct(num_vert);
++                Find_Adjacencies(face_id);
++                if (quads)
++               {
++                Init_Table_SGI();
++                     Build_SGI_Table(num_vert,face_id);
++                    /* Code for lengths of walks in each direction */
++                     Save_Walks(face_id,TRUE);
++      
++                    /* Code for finding the bands */
++                     Find_Bands(face_id,bands,&swaps,&strips,&cost,&triangles,num_nvert,vert_norms,num_texture,vert_texture);
++
++                    /*  Remove the faces that we did  so that we can
++                         run the strip code on the rest of the faces that are left
++                    */
++                    if (cost != 0)
++                    {
++                         printf("Total %d triangles with %d cost\n",triangles,cost);
++                         Save_Rest(&face_id);
++                         printf("We saved %d .... now doing the local algorithm\n",face_id);
++                         fprintf(bands,"\n#local\n");
++                          End_Edge_Struct(num_vert);
++                         Start_Edge_Struct(num_vert);
++                          Find_Adjacencies(face_id);
++                    }
++              }
++           
++              SGI_Strip(num_vert,face_id,bands,t,tr);
++
++               /*   Get the total cost */
++               Output_TriEx(-1,-2,-3,NULL,-1,-20,cost);
++
++               End_Face_Struct(num_faces);
++               End_Edge_Struct(num_vert);
++               cost = 0;
++               face_id = 0;
++               quads = FALSE;
++                      Start_Face_Struct(num_faces-face_id);
++               num_faces = num_faces - face_id;
++               Free_Strips();
++          }
++}
++               
++     /*   Done reading in all the information into data structures */
++     num_faces = face_id;
++     fclose (file);
++      /*printf(" Done.\n\n");*/
++     free(vertices);
++     free(nvertices);
++
++      /*printf ("Vertices:    %d\nNormals:    %d\nFaces:              %d\n",num_vert,num_nvert,num_faces);*/
++      Start_Edge_Struct(num_vert);
++      Find_Adjacencies(num_faces);
++
++     /*       Initialize it */
++      Init_Table_SGI();
++      /*      Build it */
++      Build_SGI_Table(num_vert,num_faces);
++
++     InitStripTable();
++
++      
++      if (quads)
++     {
++          /* Code for lengths of walks in each direction */
++           Save_Walks(num_faces,TRUE);
++      
++          /* Code for finding the bands */
++           Find_Bands(num_faces,bands,&swaps,&strips,&cost,&triangles,num_nvert,vert_norms,num_texture,vert_texture);
++          /*printf("Total %d triangles with %d cost\n",triangles,cost);*/
++
++          /*  Remove the faces that we did  so that we can
++               run the strip code on the rest of the faces that are left
++          */
++          Save_Rest(&num_faces);
++          /*printf("We saved %d .... now doing the local algorithm\n",num_faces);*/
++          fprintf(bands,"\n#local\n");
++           End_Edge_Struct(num_vert);
++          Start_Edge_Struct(num_vert);
++           Find_Adjacencies(num_faces);
++     }
++           
++      SGI_Strip(num_vert,num_faces,bands,t,tr);
++
++     /*   Get the total cost */
++     Output_TriEx(-1,-2,-3,NULL,-1,-20,cost);
++
++     End_Face_Struct(num_faces);
++     End_Edge_Struct(num_vert);
++     fclose(bands);
++     STOP
++
++     get_time();
++
++}
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6e553f14924a1ec6db7e77e53e35554bcc3420bf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,811 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: common.c
++     This file contains common code used in both the local and global algorithm
++*/
++/*---------------------------------------------------------------------*/
++
++
++#include <stdlib.h>
++#include "polverts.h"
++#include "extend.h"
++#include "output.h"
++#include "triangulate.h"
++#include "util.h"
++#include "add.h"
++
++int  Old_Adj(int face_id)
++{
++      /*      Find the bucket that the face_id is currently in,
++              because maybe we will be deleting it. 
++      */
++      PF_FACES temp = NULL;
++      ListHead *pListHead;
++      int size,y;
++      
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      if ( temp == NULL )
++      {
++              printf("The face was already deleted, there is an error\n");
++              exit(0);
++      }
++      
++      size = temp->nPolSize;
++      if (Done(face_id,size,&y) == NULL)
++      {
++              printf("There is an error in finding the face\n");
++              exit(0);
++      }
++      return y;
++}
++
++int Number_Adj(int id1, int id2, int curr_id)
++{
++      /*      Given edge whose endpoints are specified by id1 and id2,
++              determine how many polygons share this edge and return that
++              number minus one (since we do not want to include the polygon
++              that the caller has already).
++      */
++
++      int size,y,count=0;
++      PF_EDGES temp = NULL;
++      PF_FACES temp2 = NULL;
++      ListHead *pListHead;
++      BOOL there= FALSE;
++
++      /*      Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++     /*       new edge that was created might not be here */
++              return 0;
++      while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          if (temp == NULL)
++                      /*      This edge was not there in the original, which
++                              mean that we created it in the partial triangulation.
++                              So it is adjacent to nothing.
++                      */
++                      return 0;
++      }
++      /*      Was not adjacent to anything else except itself */
++      if (temp->edge[2] == -1)
++              return 0;
++      else
++      {
++              /*      It was adjacent to another polygon, but maybe we did this
++                      polygon already, and it was done partially so that this edge
++                      could have been done
++              */
++              if (curr_id != temp->edge[1])
++              {
++                      /*      Did we use this polygon already?and it was deleted
++                              completely from the structure
++                      */
++                      pListHead = PolFaces[temp->edge[1]];
++                      temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++                      if (Done(temp->edge[1],temp2->nPolSize,&size) == NULL)
++                              return 0;
++              }
++              else
++              {
++                      pListHead = PolFaces[temp->edge[2]];
++                      temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++                      if (Done(temp->edge[2],temp2->nPolSize,&size)== NULL)
++                              return 0;
++              }
++
++              /*      Now we have to check whether it was partially done, before
++                      we can say definitely if it is adjacent.
++                      Check each edge of the face and tally the number of adjacent
++                      polygons to this face. 
++              */                      
++              if ( temp2 != NULL )
++              {
++                      /*      Size of the polygon */
++                      size = temp2->nPolSize;
++                      for (y = 0; y< size; y++)
++                      {
++                              /*      If we are doing partial triangulation, we must check
++                                      to see whether the edge is still there in the polygon,
++                                      since we might have done a portion of the polygon
++                                      and saved the rest for later.
++                              */
++                              if (y != (size-1))
++                              {
++                                      if( ((id1 == *(temp2->pPolygon+y)) && (id2 ==*(temp2->pPolygon+y+1)))
++                                              || ((id2 == *(temp2->pPolygon+y)) && (id1 ==*(temp2->pPolygon+y+1))))
++                                              /*      edge is still there we are ok */
++                                              there = TRUE;
++                              }
++                              else
++                              {
++                                      if( ((id1 == *(temp2->pPolygon)) && (id2 == *(temp2->pPolygon+size-1)))
++                                      || ((id2 == *(temp2->pPolygon)) && (id1 ==*(temp2->pPolygon+size-1))))
++                                      /*      edge is still there we are ok */
++                                              there = TRUE;
++                              }
++                      }
++              }
++              
++              if (there )
++                      return 1;
++              return 0;
++      }
++}
++
++int Min_Adj(int id)
++{
++      /*      Used for the lookahead to break ties. It will
++              return the minimum adjacency found at this face.
++      */
++      int y,numverts,t,x=60;
++      PF_FACES temp=NULL;
++      ListHead *pListHead;
++
++      /*      If polygon was used then we can't use this face */
++      if (Done(id,59,&y) == NULL)
++              return 60;
++              
++      /*      It was not used already */
++      pListHead = PolFaces[id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++     if ( temp != NULL )
++      {
++              numverts = temp->nPolSize;
++              for (y = 0; y< numverts; y++)
++              {
++                      if (y != (numverts-1))
++                              t = Number_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),id);
++                      else
++                              t = Number_Adj(*(temp->pPolygon),*(temp->pPolygon+(numverts-1)),id);
++                      if (t < x)
++                              x = t;
++              }
++      }
++      if (x == -1)
++      {
++              printf("Error in the look\n");
++              exit(0);
++      }
++      return x;
++}
++
++
++
++void Edge_Least(int *index,int *new1,int *new2,int face_id,int size)
++{
++    /*   We had a polygon without an input edge and now we re going to pick one
++         of the edges with the least number of adjacencies to be the input
++         edge
++    */
++    register int x,value,smallest=60;
++
++    for (x = 0; x<size; x++)
++    {
++        if (x != (size -1) )
++            value = Number_Adj(*(index+x),*(index+x+1),face_id);
++        else 
++            value = Number_Adj(*(index),*(index+size-1),face_id);
++        if (value < smallest)
++        {
++            smallest = value;
++            if (x != (size -1))
++            {
++                *new1 = *(index+x);
++                *new2 = *(index+x+1);
++            }
++            else
++            {
++                *new1 = *(index);
++                *new2 = *(index+size-1);
++            }
++        }
++    }
++    if ((smallest == 60) || (smallest < 0))
++    {
++        printf("There is an error in getting the least edge\n");
++        exit(0);
++    }
++}
++
++
++void Check_In_Polygon(int face_id, int *min, int size)
++{
++    /*  Check to see the adjacencies by going into a polygon that has
++        greater than 4 sides.
++    */
++    
++    ListHead *pListHead;
++    PF_FACES temp;
++    int y,id1,id2,id3,x=0,z=0;
++    int saved[2];
++    int big_saved[60];
++
++    pListHead = PolFaces[face_id];
++    temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++
++    /*   Get the input edge that we came in on */
++    Last_Edge(&id1,&id2,&id3,0);
++
++    /*  Find the number of adjacencies to the edges that are adjacent
++        to the input edge.
++    */
++    for (y=0; y< size; y++)
++    {
++        if (y != (size-1))
++        {
++            if (((*(temp->pPolygon+y) == id2) && (*(temp->pPolygon+y+1) != id3))
++                || ((*(temp->pPolygon+y) == id3) && (*(temp->pPolygon+y+1) != id2)))
++            {
++                saved[x++] = Number_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),face_id);
++                big_saved[z++] = saved[x-1];
++            }
++            else
++                big_saved[z++] = Number_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),face_id);
++        }
++        else
++        {
++            if (((*(temp->pPolygon) == id2) && (*(temp->pPolygon+size-1) != id3))
++                || ((*(temp->pPolygon) == id3) && (*(temp->pPolygon+size-1) != id2)))
++            {
++                saved[x++] = Number_Adj(*(temp->pPolygon),*(temp->pPolygon+size-1),face_id);
++                big_saved[z++] = saved[x-1];
++            }
++            else
++                big_saved[z++] = Number_Adj(*(temp->pPolygon),*(temp->pPolygon+size-1),face_id);
++        }
++    }
++    /*  There was an input edge */
++    if (x == 2)
++    {
++        if (saved[0] < saved[1])
++            /*  Count the polygon that we will be cutting as another adjacency*/
++            *min = saved[0] + 1;
++        else
++            *min = saved[1] + 1;
++    }
++    /*  There was not an input edge */
++    else
++    {
++        if (z != size)
++        {
++            printf("There is an error with the z %d %d\n",size,z);
++            exit(0);
++        }
++        *min = 60;
++        for (x = 0; x < size; x++)
++        {
++            if (*min > big_saved[x])
++                *min = big_saved[x];
++        }
++    }
++}
++
++
++void New_Face (int face_id, int v1, int v2, int v3)
++{
++      /*      We want to change the face that was face_id, we will
++              change it to a triangle, since the rest of the polygon
++              was already outputtted
++      */
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++
++      pListHead = PolFaces[face_id];
++     temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0);
++      /*      Check each edge of the face and tally the number of adjacent
++              polygons to this face. 
++      */                      
++      if ( temp != NULL )
++      {
++              /*      Size of the polygon */
++              if (temp->nPolSize != 4)
++              {
++                      printf("There is a miscalculation in the partial\n");
++                      exit (0);
++              }
++              temp->nPolSize = 3;
++              *(temp->pPolygon) = v1;
++              *(temp->pPolygon+1) = v2;
++              *(temp->pPolygon+2) = v3;
++      }
++}
++
++void New_Size_Face (int face_id)
++{
++      /*      We want to change the face that was face_id, we will
++              change it to a triangle, since the rest of the polygon
++              was already outputtted
++      */
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      /*      Check each edge of the face and tally the number of adjacent
++              polygons to this face. 
++      */                      
++      if ( temp != NULL )
++              (temp->nPolSize)--;
++      else
++              printf("There is an error in updating the size\n");
++}
++
++
++
++void  Check_In_Quad(int face_id,int *min)
++{
++     /*   Check to see what the adjacencies are for the polygons that
++          are inside the quad, ie the 2 triangles that we can form.
++     */
++    ListHead *pListHead;
++    int y,id1,id2,id3,x=0;
++    int saved[4];
++    PF_FACES temp;
++    register int size = 4;
++
++    pListHead = PolFaces[face_id];
++    temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      
++     /*   Get the input edge that we came in on */
++    Last_Edge(&id1,&id2,&id3,0);
++      
++    /*    Now find the adjacencies for the inside triangles */
++    for (y = 0; y< size; y++)
++      {
++         /*     Will not do this if the edge is the input edge */
++         if (y != (size-1))
++         {
++              if ((((*(temp->pPolygon+y) == id2) && (*(temp->pPolygon+y+1) == id3))) ||
++             (((*(temp->pPolygon+y) == id3) && (*(temp->pPolygon+y+1) == id2))))
++                    saved[x++] = -1;
++              else
++              {
++                   if (x == 4)
++                   {
++                        printf("There is an error in the check in quad \n");
++                        exit(0);
++                   }
++                   /*    Save the number of Adjacent Polygons to this edge */
++                   saved[x++] = Number_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),face_id);
++              }
++         }
++              else if ((((*(temp->pPolygon) == id2) && (*(temp->pPolygon+size-1) == id3))) ||
++             (((*(temp->pPolygon) == id3) && (*(temp->pPolygon+size-1) == id2))) )
++             saved[x++] = -1;
++        else
++        {
++               if (x == 4)
++               {
++                    printf("There is an error in the check in quad \n");
++                    exit(0);
++               }
++               /*    Save the number of Adjacent Polygons to this edge */
++               saved[x++] = Number_Adj(*(temp->pPolygon),*(temp->pPolygon+size-1),face_id);
++
++        }
++    }
++    if (x != 4)
++    {
++         printf("Did not enter all the values %d \n",x);
++         exit(0);
++    }
++    
++    *min = 10;
++    for (x=0; x<4; x++)
++    {
++         if (x!= 3)
++         {
++              if ((saved[x] != -1) && (saved[x+1] != -1) && 
++                   ((saved[x] + saved[x+1]) < *min))
++                   *min = saved[x] + saved[x+1];
++         }
++         else
++         {
++              if ((saved[0] != -1) && (saved[x] != -1) &&
++                   ((saved[x] + saved[0]) < *min))
++                   *min = saved[0] + saved[x];
++         }
++    }
++}
++
++
++
++int Get_Output_Edge(int face_id, int size, int *index,int id2,int id3)
++{
++    /*  Return the vertex adjacent to either input1 or input2 that
++        is adjacent to the least number of polygons on the edge that
++        is shared with either input1 or input2.
++    */
++    register int x=0,y;
++    int saved[2];
++    int edges[2][1];
++
++    for (y = 0; y < size; y++)
++    {
++        if (y != (size-1))
++        {
++            if (((*(index+y) == id2) && (*(index+y+1) != id3))
++                || ((*(index+y) == id3) && (*(index+y+1) != id2)))
++            {
++                saved[x++] = Number_Adj(*(index+y),*(index+y+1),face_id);
++                edges[x-1][0] = *(index+y+1);
++            }
++            else if (y != 0)
++            {
++                if (( (*(index+y) == id2) && (*(index+y-1) != id3) ) ||
++                    ( (*(index+y) == id3) && (*(index+y-1) != id2)) )
++                {
++                    saved[x++] = Number_Adj(*(index+y),*(index+y-1),face_id);
++                    edges[x-1][0] = *(index+y-1);
++                }
++            }
++            else if (y == 0)
++            {
++                if (( (*(index) == id2) && (*(index+size-1) != id3) ) ||
++                    ( (*(index) == id3) && (*(index+size-1) != id2)) )
++                {
++                    saved[x++] = Number_Adj(*(index),*(index+size-1),face_id);
++                    edges[x-1][0] = *(index+size-1);
++                }
++            }
++
++        }
++        else
++        {
++            if (((*(index+size-1) == id2) && (*(index) != id3))
++                || ((*(index+size-1) == id3) && (*(index) != id2)))
++            {
++                saved[x++] = Number_Adj(*(index),*(index+size-1),face_id);
++                edges[x-1][0] = *(index);
++            }
++
++            if (( (*(index+size-1) == id2) && (*(index+y-1) != id3) ) ||
++                    ( (*(index+size-1) == id3) && (*(index+y-1) != id2)) )
++                {
++                    saved[x++] = Number_Adj(*(index+size-1),*(index+y-1),face_id);
++                    edges[x-1][0] = *(index+y-1);
++                }
++        }
++    }
++    if ((x != 2))
++    {
++        printf("There is an error in getting the input edge %d \n",x);
++        exit(0);
++    }
++    if (saved[0] < saved[1])
++        return edges[0][0];
++    else
++        return edges[1][0];
++
++}
++
++void Get_Input_Edge(int *index,int id1,int id2,int id3,int *new1,int *new2,int size,
++                    int face_id)
++{
++    /*  We had a polygon without an input edge and now we are going to pick one
++        as the input edge. The last triangle was id1,id2,id3, we will try to
++        get an edge to have something in common with one of those vertices, otherwise
++        we will pick the edge with the least number of adjacencies.
++    */
++
++    register int x;
++    int saved[3];
++
++    saved[0] = -1;
++    saved[1] = -1;
++    saved[2] = -1;
++    
++    /*  Go through the edges to see if there is one in common with one
++        of the vertices of the last triangle that we had, preferably id2 or
++        id3 since those are the last 2 things in the stack of size 2.
++    */
++    for (x=0; x< size; x++)
++    {
++        if (*(index+x) == id1)
++        {
++            if (x != (size-1))
++                saved[0] = *(index+x+1);
++            else
++                saved[0] = *(index);
++        }
++
++        if (*(index+x) == id2)
++        {
++            if (x != (size-1))
++                saved[1] = *(index+x+1);
++            else
++                saved[1] = *(index);
++        }
++        
++        if (*(index+x) == id3)
++        {
++            if (x != (size -1))
++                saved[2] = *(index+x+1);
++            else
++                saved[2] = *(index);
++        }
++    }
++    /*  Now see what we saved */
++    if (saved[2] != -1)
++    {
++        *new1 = id3;
++        *new2 = saved[2];
++        return;
++    }
++    else if (saved[1] != -1)
++    {
++        *new1 = id2;
++        *new2 = saved[1];
++        return;
++    }
++    else if (saved[0] != -1)
++    {
++        *new1 = id1;
++        *new2 = saved[0];
++        return;
++    }
++    /*  We did not find anything so get the edge with the least number of adjacencies */
++    Edge_Least(index,new1,new2,face_id,size);
++
++}
++
++int Find_Face(int current_face, int id1, int id2, int *bucket)
++{
++      /*      Find the face that is adjacent to the edge and is not the
++              current face.
++      */
++      register int size,each_poly=0,y,tally=0,count=0;
++      PF_EDGES temp = NULL;
++      PF_FACES temp2 = NULL;
++      ListHead *pListHead;
++      int next_face;
++      BOOL there = FALSE;
++
++    
++    /*        Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     /*  The input edge was a new edge */
++     if (temp == NULL)
++        return -1;
++        
++     while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          /*  The input edge was a new edge */
++          if (temp == NULL)
++            return -1;
++     }
++      /*      Was not adjacent to anything else except itself */
++      if (temp->edge[2] == -1)
++              return -1;
++      else
++      {
++              if (temp->edge[2] == current_face)
++                      next_face =  temp->edge[1];
++              else 
++                      next_face = temp->edge[2];
++      }
++      /*      We have the other face adjacent to this edge, it is 
++              next_face. 
++      */
++      pListHead = PolFaces[next_face];
++      temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++              
++     /*       See if the face was already deleted, and where
++              it is if it was not
++     */
++              
++     if (Done(next_face,59,bucket) == NULL)
++        return -1;
++
++     /*  Make sure the edge is still in this polygon, and that it is not
++         done
++     */
++              /*      Size of the polygon */
++              size = temp2->nPolSize;
++              for (y = 0; y< size; y++)
++              {
++                      /*      Make sure that the edge is still in the
++                              polygon and was not deleted, because if the edge was
++                              deleted, then we used it already.
++                      */
++                      if (y != (size-1))
++                      {
++                              if( ((id1 == *(temp2->pPolygon+y)) && (id2 ==*(temp2->pPolygon+y+1)))
++                                      || ((id2 == *(temp2->pPolygon+y)) && (id1 ==*(temp2->pPolygon+y+1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++                      else
++                      {               
++                              if( ((id1 == *(temp2->pPolygon)) && (id2 ==*(temp2->pPolygon+size-1)))
++                                      || ((id2 == *(temp2->pPolygon)) && (id1 ==*(temp2->pPolygon+size-1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++              }
++              
++              if (!there)
++                      /*      Edge already used and deleted from the polygon*/
++                      return -1;
++         else
++            return next_face;
++}
++
++BOOL Look_Up(int id1,int id2,int face_id)
++{
++      /*      See if the endpoints of the edge specified by id1 and id2
++              are adjacent to the face with face_id 
++      */
++      register int count = 0;
++      PF_EDGES temp  = NULL;
++      ListHead *pListHead;
++      PF_FACES temp2 = NULL;
++      
++      /*      Always want smaller id first */
++      switch_lower(&id1,&id2);
++
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++     /*       Was a new edge that we created */
++              return 0;
++      
++      while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          if (temp == NULL)
++                      /*      Was a new edge that we created */
++                      return 0;
++     }
++      /*      Was not adjacent to anything else except itself */
++      if ((temp->edge[2] == face_id) || (temp->edge[1] == face_id))
++      {
++              /*      Edge was adjacent to face, make sure that edge is 
++                      still there
++              */
++              if (Exist(face_id,id1,id2))
++                      return 1;
++              else
++                      return 0;
++      }
++      else
++              return 0;
++}
++
++
++void Add_Id_Strips(int id, int where)
++{
++     /*    Just save the triangle for later  */
++     P_STRIPS pfNode;
++
++      pfNode = (P_STRIPS) malloc(sizeof(Strips) );
++      if ( pfNode )
++      {
++           pfNode->face_id = id;
++           if (where == 1)
++               AddTail(strips[0],(PLISTINFO) pfNode);
++           /* We are backtracking in the strip */
++           else
++               AddHead(strips[0],(PLISTINFO) pfNode);
++      }
++      else
++      {
++           printf("There is not enough memory to allocate for the strips\n");
++           exit(0);
++      }
++}
++
++
++int Num_Adj(int id1, int id2)
++{
++      /*   Given edge whose endpoints are specified by id1 and id2,
++              determine how many polygons share this edge and return that
++              number minus one (since we do not want to include the polygon
++              that the caller has already).
++      */
++
++      PF_EDGES temp = NULL;
++      ListHead *pListHead;
++      register count=-1;
++
++      /*      Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++      {
++              printf("There is an error in the creation of the table \n");
++              exit(0);
++      }
++      while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++           if (temp == NULL)
++              {
++                      printf("There is an error in the creation of the table\n");
++                      exit(0);
++              }
++      }
++      /*      Was not adjacent to anything else except itself */
++      if (temp->edge[2] == -1)
++              return 0;
++      return 1;
++}
++
++
++void Add_Sgi_Adj(int bucket,int face_id)
++{
++      /*   This routine will add the face to the proper bucket,
++              depending on how many faces are adjacent to it (what the
++              value bucket should be).
++      */
++      P_ADJACENCIES pfNode;
++
++      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++     if ( pfNode )
++     {
++              pfNode->face_id = face_id;
++           AddHead(array[bucket],(PLISTINFO) pfNode);
++      }
++      else
++      {
++              printf("Out of memory for the SGI adj list!\n");
++              exit(0);
++      }
++}
++
++void Find_Adjacencies(int num_faces)
++{
++     register int     x,y;
++     register int     numverts;
++     PF_FACES temp=NULL;
++     ListHead *pListHead;
++
++      /*   Fill in the adjacencies data structure for all the faces */
++     for (x=0;x<num_faces;x++)
++      {
++              pListHead = PolFaces[x];
++              temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      if ( temp != NULL )
++              {
++                      numverts = temp->nPolSize;
++                      if (numverts != 1)
++               {
++                    for (y = 0; y< numverts; y++)
++                           {
++                                   if (y != (numverts-1))
++                                           Add_AdjEdge(*(temp->pPolygon+y),*(temp->pPolygon+y+1),x,y);
++                      
++                                   else 
++                                           Add_AdjEdge(*(temp->pPolygon),*(temp->pPolygon+(numverts-1)),x,numverts-1);
++                      
++                    }
++               }
++                      temp = NULL;
++              }
++      }
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a220b3628ca41e268a19037410481ebd769b1687
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,41 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: common.h
++-----------------------------------------------------------------------*/
++
++void Add_AdjEdge();
++void Find_Adjacencies();
++void Add_Sgi_Adj();
++int Num_Adj();
++void Add_Id_Strips();
++BOOL Look_Up();
++int Number_Adj();
++int  Old_Adj();
++int Min_Adj();
++int Find_Face();
++void Edge_Least();
++void Get_Input_Edge();
++int Get_Output_Edge();
++void Check_In_Polygon();
++void  Check_In_Quad();
++void New_Size_Face ();
++void New_Face ();
++
++
++
++
++
++
++
++
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..931e5713ffe952c1d4e2e0c499b526c6010671de
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,13 @@@
++
++#define   VRDATA              double
++#define   MAX1            60
++      
++#define       TRUE            1
++#define       FALSE           0
++
++#define   PI          3.1415926573
++
++struct vert_struct {
++      VRDATA  x, y, z;        /* point coordinates */
++};
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..78c135e3a308e9d841c89dae89350cca0388d66e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: extend.h
++-----------------------------------------------------------------------*/
++
++int Bottom_Left();
++int Top_Left();
++void Start_Edge();
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9494f4fb4ff12293ad122009c32b5fb02b57ed2c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,110 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: free.c
++     This file contains the code used to free the data structures.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "polverts.h"
++
++void ParseAndFreeList( ListHead *pListHead )
++{
++    PLISTINFO value;
++    register int c,num;
++        
++    /*    Freeing a linked list */
++    num = NumOnList(pListHead);
++    for (c = 0; c< num; c++)
++           value =   RemHead(pListHead);
++} 
++
++void FreePolygonNode( PF_VERTS pfVerts)
++{
++      /*   Free a vertex node */
++     if ( pfVerts->pPolygon )
++              free( pfVerts->pPolygon );
++      free( pfVerts );
++
++}
++ 
++void Free_Strips()
++{
++    P_STRIPS temp = NULL;
++
++    /*    Free strips data structure */
++    if (strips[0] == NULL)
++         return;
++    else
++         ParseAndFreeList(strips[0]);
++}
++
++void FreeFaceNode( PF_FACES pfFaces)
++{
++      /*   Free face node */
++     if ( pfFaces->pPolygon )
++                free( pfFaces->pPolygon );
++        free( pfFaces );
++}
++
++
++void FreeFaceTable(int nSize)
++{
++     register int nIndex;
++
++     for ( nIndex=0; nIndex < nSize; nIndex++ )
++     { 
++              if ( PolFaces[nIndex] != NULL ) 
++             ParseAndFreeList( PolFaces[nIndex] );
++     }
++     free( PolFaces );
++}
++
++void FreeEdgeTable(int nSize)
++{
++        register int nIndex;
++
++        for ( nIndex=0; nIndex < nSize; nIndex++ )
++        {
++                if ( PolEdges[nIndex] != NULL )
++                        ParseAndFreeList( PolEdges[nIndex] );
++        }
++        free( PolEdges );
++}
++
++
++void Free_All_Strips()
++{
++
++      ListHead *pListHead;
++      register int y;
++
++      for (y =0; ; y++)
++      {
++              pListHead = all_strips[y];
++              if (pListHead == NULL)
++                      return;
++              else
++                      ParseAndFreeList(all_strips[y]);
++      }
++}
++
++void End_Face_Struct(int numfaces)
++{
++     FreeFaceTable(numfaces);
++}
++
++void End_Edge_Struct(int numverts)
++{
++     FreeEdgeTable(numverts);
++}     
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3303d05e1886d8cb41b1d26c2043a05362d87af2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: free.h
++-----------------------------------------------------------------------*/
++
++void Free_All_Strips();
++void ParseAndFreeList();
++void FreePolygonNode();
++void Free_Strips();
++void FreeFaceTable();
++void FreeEdgeTable();
++void End_Face_Struct();
++void End_Edge_Struct();
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3621b25e1315826ddcf8c5c51b6e7191e7a5045e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,37 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: global.h
++-----------------------------------------------------------------------*/
++
++#define   VRDATA              double
++#define   MAX1            60
++      
++#define       TRUE            1
++#define       FALSE           0
++
++#ifndef PI
++#  define   PI                3.1415926573
++#endif /* PI */
++#define   ATOI(C)        (C -'0')
++#define   X              0
++#define   Y              1
++#define   Z              2
++#define   EVEN(x)       (((x) & 1) == 0)
++#define   MAX_BAND      10000
++
++struct vert_struct {
++      VRDATA  x, y, z;        /* point coordinates */
++};
++
++int     ids[MAX1];
++int     norms[MAX1];
++int     *vert_norms;
++int     *vert_texture;
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..74bcd07da1cbd892c82b232685a9c5e985819440
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,151 @@@
++/*
++ * dg2lib.h - header file for the DG2 library libdg2.a
++ *
++ * copyright 1988-92 VPL Research Inc.
++ *
++ */
++
++
++
++/******** error returns from the library */
++
++extern int DG2_error;                 /* for error information */
++extern float DG2_lib_version;         /* for the library version */
++extern int DG2_box_version;   /* for the firmware version */
++extern int DG2_glove_sensors; /* for the number of sensors in the glove */
++
++/* defines for DG2_error values */
++
++#define DG2_AOK                       0 
++#define DG2_SETTINGS_FILE     -1
++#define DG2_SERIAL_OPEN               -2 
++#define DG2_SERIAL_PORT               -4   
++#define DG2_RESET             -6  
++#define DG2_PARAMETER         -7  
++#define DG2_FILE_IO           -8
++#define DG2_CALIBRATION_FILE  -9
++#define DG2_GESTURE_FILE      -10
++#define DG2_CAL_GEST_FILES    -11
++/* defines for DG2_response() */
++
++#define DATAGLOVE     1
++#define POLHEMUS      2
++#define GESTURE               8
++
++#define DG2_60Hz      1
++#define DG2_30Hz      2
++#define DG2_oneShot   3
++
++/* defines for DG2_DataGlove_select() */
++
++#define THUMB_INNER   0x1
++#define THUMB_OUTER   0x2
++#define INDEX_INNER   0x4
++#define INDEX_OUTER   0x8
++#define MIDDLE_INNER  0x10
++#define MIDDLE_OUTER  0x20
++#define RING_INNER    0x40
++#define RING_OUTER    0x80
++#define LITTLE_INNER  0x100
++#define LITTLE_OUTER  0x200
++#define NORMAL_JOINTS 0x3ff
++#define FLEX11                0x400
++#define FLEX12                0x800
++#define FLEX13                0x1000
++#define FLEX14                0x2000
++#define FLEX15                0x4000
++#define FLEX16                0x8000
++
++
++/* defines for DG2_DataGlove_trans_select() */
++
++#define DG2_TRANSLATED        5
++#define DG2_RAW               6
++
++/* defines for DG2_Polhemus_units() */
++
++#define POL_RAW               0
++#define POL_INCHES    1
++#define POL_CM                2
++
++/* defines for DG2_user_IRQ() */
++
++#define IRQ_ON        1
++#define IRQ_OFF       2
++
++
++/* defines for DG2_get_data() */
++
++#define DG2_report    1
++#define DG2_userport  2
++
++
++/* dg2 command codes*/
++#define LEADINGBYTE   0x24
++#define RPT60         0x41    /* repeat 60 */
++#define RPT30         0x42    /* repeat 30 */
++#define ONESHOT       0x43    /* one shot */
++#define SYSID         0x44    /* system ID */
++#define EPTBUF        0x45    /* empty buffer */
++#define USRRD         0x46    /* user read */
++#define USRIRQ        0x47    /* user IRQ */
++#define QBRT          0x48    /* query bright */      
++#define CDRST         0x49    /* cold reset */
++#define WMRST         0x4A    /* warm reset */
++#define MEMALLO       0x4B    /* memory alloc */
++#define DLTSND        0x4C    /* delta send */
++#define SETBRT        0x4D    /* set bright */
++#define SETDIM        0x4E    /* set dim */
++#define FILBUF        0x4F    /* fill buffer */
++#define LDTBL         0x50    /* load table */
++#define LDPOL         0x51    /* send up to 63 bytes to Polhemus  */
++#define ANGLE         0x52    /* angles */
++#define NSNSR         0x53    /* num sensors */
++#define SETFB         0x54    /* set feedback */
++#define QCUT          0X55    /* query cutoff*/
++#define SETCUT        0X56    /* set cutoff */
++#define FLXVAL        0X57    /* raw flex values */
++#define USRWR         0X58    /* user write */
++#define JNTMAP        0X59    /* joint map */
++#define ERRMESS               0XFF    /* error in command input */
++#define TIMOUT                0XFE    /* timed out during command */
++
++/* response structure */
++
++typedef struct DG2_data {
++      char gesture;
++      double location[3];     /* X,Y,Z */
++      double orientation[3];  /* yaw, pitch, roll */
++      short flex[16];
++      char gesture_name[20];
++      short reserved[16];
++              /* user port data: */
++      char user_nibble;
++      char user_analog[3];
++} DG2_data;
++
++
++/**************function prototypes*************/
++/*NOTE: all DG2_ functions return -1 on error*/
++
++extern int DG2_open(char *portname, int baud);
++extern int DG2_close(int filedes);
++extern int DG2_direct(int filedes,char *message,int count);
++extern int DG2_response(int filedes,int devices,int rate);
++extern int DG2_DataGlove_select(int filedes,int flex_sensors);
++extern int DG2_DataGlove_translation(int filedes,int flex_sensors,char table[16][256]);
++extern int DG2_DataGlove_trans_select(int filedes,int status);
++extern int DG2_DataGlove_LED_set(int filedes,int LED);
++extern int DG2_DataGlove_LED_read(int filedes);
++extern int DG2_Polhemus_units(int filedes,char type);
++extern int DG2_Polhemus_direct(int filedes,char *message,int count);
++extern int DG2_user_write(int filedes,int nibble);
++extern int DG2_user_IRQ(int filedes,int mode);
++extern int DG2_user_read(int filedes,DG2_data *data);
++extern int DG2_get_data(int filedes,DG2_data *data);
++extern int DG2_gesture_load(int filedes,char *calib,char *gest);
++
++/*use this with caution since it does not return until it gets a correct
++ *response from the DG2
++*/
++extern int DG2U_get_reply(int filedes,char *buff,int response,int size);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b3b218ceceea978fef3dac2c4323911fbc43a51a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,217 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: init.c
++     This file contains the initialization of data structures.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "global.h"
++#include "polverts.h"
++
++void init_vert_norms(int num_vert)
++{
++     /*   Initialize vertex/normal array to have all zeros to
++          start with.
++     */
++     register int x;
++
++     for (x = 0; x < num_vert; x++)
++          *(vert_norms + x) = 0;
++}
++
++void init_vert_texture(int num_vert)
++{
++     /*   Initialize vertex/normal array to have all zeros to
++          start with.
++     */
++     register int x;
++
++     for (x = 0; x < num_vert; x++)
++          *(vert_texture + x) = 0;
++}
++
++BOOL InitVertTable( int nSize )
++{
++     register int nIndex;
++
++      /*   Initialize the vertex table */
++     PolVerts = (ListHead**) malloc(sizeof(ListHead*) * nSize ); 
++      if ( PolVerts )
++      {
++              for ( nIndex=0; nIndex < nSize; nIndex++ )
++              {
++                      PolVerts[nIndex] = NULL;
++              }
++              return( TRUE ); 
++      }
++      return( FALSE );
++}  
++
++BOOL InitFaceTable( int nSize )
++{
++        register int nIndex;
++
++        /*     Initialize the face table */
++        PolFaces = (ListHead**) malloc(sizeof(ListHead*) * nSize ); 
++        if ( PolFaces )
++        {
++                for ( nIndex=0; nIndex < nSize; nIndex++ )
++                {
++                        PolFaces[nIndex] = NULL;
++                }
++                return( TRUE );
++        }
++        return( FALSE );
++} 
++
++BOOL InitEdgeTable( int nSize )
++{
++        register int nIndex;
++
++        /*     Initialize the edge table */
++        PolEdges = (ListHead**) malloc(sizeof(ListHead*) * nSize );
++        if ( PolEdges )
++        {
++                for ( nIndex=0; nIndex < nSize; nIndex++ )
++                {
++                        PolEdges[nIndex] = NULL;
++                }
++                return( TRUE );
++        }
++        return( FALSE );
++}
++
++
++void InitStripTable(  )
++{
++
++     PLISTHEAD pListHead;
++
++     /*   Initialize the strip table */
++     pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
++      if ( pListHead )
++     {
++              InitList( pListHead );
++              strips[0] = pListHead;
++      }
++     else
++      {
++           printf("Out of memory !\n");
++              exit(0);
++      }
++
++}
++
++void Init_Table_SGI()
++{
++      PLISTHEAD pListHead;
++      int max_adj = 60;
++      register int x;
++      
++      /*   This routine will initialize the table that will
++              have the faces sorted by the number of adjacent polygons
++              to it.
++      */
++
++      for (x=0; x< max_adj; x++)
++      {
++              /*   We are allowing the max number of sides of a polygon
++                      to be max_adj.
++              */                      
++              pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
++              if ( pListHead )
++           {
++                      InitList( pListHead );
++                      array[x] = pListHead;
++              }
++           else
++              {
++                   printf("Out of memory !\n");
++                      exit(0);
++              }
++      }
++}
++
++void BuildVertTable( int nSize )
++{
++     register int nIndex;
++     PLISTHEAD pListHead;
++      
++      for ( nIndex=0; nIndex < nSize; nIndex++ )
++      {
++              pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
++              if ( pListHead )
++              {
++                      InitList( pListHead );
++                      PolVerts[nIndex] = pListHead;
++              }
++              else
++                      return; 
++              
++      }
++}
++   
++
++void BuildFaceTable( int nSize )
++{
++        register int nIndex;
++        PLISTHEAD pListHead;
++        
++        for ( nIndex=0; nIndex < nSize; nIndex++ )
++        {
++                pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
++                if ( pListHead )
++                {
++                        InitList( pListHead );
++                        PolFaces[nIndex] = pListHead;
++                }
++                else
++                        return; 
++                
++        }
++}
++   
++void BuildEdgeTable( int nSize )
++{
++        register int nIndex;
++        PLISTHEAD pListHead;
++
++        for ( nIndex=0; nIndex < nSize; nIndex++ )
++        {
++                pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
++                if ( pListHead )
++                {
++                        InitList( pListHead );
++                        PolEdges[nIndex] = pListHead;
++                }
++                else
++                        return;
++        }
++}
++
++void Start_Face_Struct(int numfaces)
++{
++      if (InitFaceTable(numfaces))
++      {
++              BuildFaceTable(numfaces);
++      }
++}
++
++void Start_Edge_Struct(int numverts)
++{
++        if (InitEdgeTable(numverts))
++        {
++                BuildEdgeTable(numverts);
++        }
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2faf0e838677c86a08297c949e7e6ee5667cdf71
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,30 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: init.h
++-----------------------------------------------------------------------*/
++
++void init_vert_norms();
++void init_vert_texture();
++BOOL InitVertTable();
++BOOL InitFaceTable();
++BOOL InitEdgeTable();
++void InitStripTable();
++void Init_Table_SGI();
++void BuildVertTable();
++void BuildFaceTable();
++void BuildEdgeTable();
++void Start_Face_Struct();
++void Start_Edge_Struct();
++
++
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2db94904eabb10746d9c9f0c388345f60e33b3cc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,123 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: local.c
++     This file contains the code that initializes the data structures for
++     the local algorithm, and starts the local algorithm going.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "polverts.h"
++#include "local.h"
++#include "triangulatex.h"
++#include "sturctsex.h"
++#include "common.h"
++#include "outputex.h"
++#include "util.h"
++#include "init.h"
++
++void Find_StripsEx(FILE *output,FILE *strip,int *ties,
++                               int  tie, int triangulate,
++                 int  swaps,int *next_id)
++{
++      /*      This routine will peel off the strips from the model */
++
++      ListHead *pListHead;
++      P_ADJACENCIES temp = NULL;
++      register int max,bucket=0;
++      BOOL whole_flag = TRUE;
++     int dummy = 0;
++      
++      /*  Set the last known input edge to be null */
++     Last_Edge(&dummy,&dummy,&dummy,1);
++    
++     /*       Search for lowest adjacency polygon and output strips */
++      while (whole_flag)
++      {
++              bucket = -1;
++              /*      Search for polygons in increasing number of adjacencies */
++              while (bucket < 59)
++              {
++                      bucket++;
++                      pListHead = array[bucket];
++                      max = NumOnList(pListHead);
++                      if (max > 0)
++                      {
++                              temp = (P_ADJACENCIES) PeekList(pListHead,LISTHEAD,0);
++                              if (temp == NULL)
++                              {
++                                      printf("Error in the buckets%d %d %d\n",bucket,max,0);
++                                      exit(0);
++                              }
++                              Polygon_OutputEx(temp,temp->face_id,bucket,pListHead,
++                                             output,strip,ties,tie,triangulate,swaps,next_id,1);
++                              /*  Try to extend backwards, if the starting polygon in the
++                        strip had 2 or more adjacencies to begin with
++                    */
++                    if (bucket >= 2)
++                         Extend_BackwardsEx(temp->face_id,output,strip,ties,tie,triangulate,
++                                            swaps,next_id);
++                    break;  
++                      }
++              }
++              /*      Went through the whole structure, it is empty and we are done.
++              */
++              if ((bucket == 59) && (max == 0))
++                      whole_flag = FALSE;
++        
++          /*  We just finished a strip, send dummy data to signal the end
++              of the strip so that we can output it.
++          */
++         else
++         {
++             Output_TriEx(-1,-2,-3,output,-1,-10,1);
++             Last_Edge(&dummy,&dummy,&dummy,1);
++         }
++      }
++}
++
++
++
++void SGI_Strip(int num_verts,int num_faces,FILE *output,
++                         int ties,int triangulate)
++               
++{
++      FILE *strip;
++     int next_id = -1,t=0;
++
++     strip = fopen("output.d","w");
++     /*       We are going to output and find triangle strips
++              according the the method that SGI uses, ie always
++              choosing as the next triangle in our strip the triangle
++              that has the least number of adjacencies. We do not have
++              all triangles and will be triangulating on the fly those
++              polygons that have more than 3 sides.
++      */
++
++      /*      Build a table that has all the polygons sorted by the number
++              of polygons adjacent to it.
++      */
++      /*      Initialize it */
++      Init_Table_SGI();
++      /*      Build it */
++      Build_SGI_Table(num_verts,num_faces);
++
++      /*    We will have a structure to hold all the strips, until
++          outputted.
++     */
++     InitStripTable();
++     /*       Now we have the structure built to find the polygons according
++              to the number of adjacencies. Now use the SGI Method to find
++              strips according to the adjacencies
++      */
++     Find_StripsEx(output,strip,&t,ties,triangulate,ON,&next_id);
++
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..34769ebb85fb5a87202c2ac080b9eaccc140b3da
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,19 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE:local.h
++-----------------------------------------------------------------------*/
++
++void Local_Polygon_Output();
++void Local_Output_Tri();
++int Different();
++void Local_Non_Blind_Triangulate();
++void Local_Blind_Triangulate();
++void Local_Triangulate_Polygon();
++void SGI_Strip();
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..629c120745622fe7dae5da12544bf8c5f6e31eec
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++int change_in_stripEx = 0;
++int change_in_strip = 0;
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9adbfd651de22f89a6ea05e23abb635664936e94
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1667 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: newpolve.c
++     This routine contains the bulk of the code that will find the
++     patches of quads in the data model
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdlib.h>
++#include "polverts.h"
++#include "extend.h"
++#include "output.h"
++#include "triangulate.h"
++#include "common.h"
++#include "util.h"
++#include "global.h"        
++#include "init.h"
++#include "add.h"
++
++ListHead **PolVerts;
++ListHead **PolFaces;
++ListHead **PolEdges;
++int length;
++BOOL resetting = FALSE;
++int     ids[MAX1];
++int   added_quad = 0;
++BOOL reversed = FALSE;
++int patch = 0;
++int *vn;
++int *vt;
++
++int Calculate_Walks(int lastvert,int y, PF_FACES temp2)
++{
++      /* Find the length of the walk */
++      
++      int previous_edge1, previous_edge2;
++      register int nextvert,numverts,counter,walk=0;
++      BOOL flag;
++      F_EDGES *node;
++     ListHead *pListHead;
++     static int seen = 0;
++     
++      /* Find the edge that we are currently on */
++      if (y != 3)
++      {
++              previous_edge1 = *(temp2->pPolygon +y);
++              previous_edge2 = *(temp2->pPolygon + y + 1);
++      }
++      else
++      {
++              previous_edge1 = *(temp2->pPolygon +y);
++              previous_edge2 = *(temp2->pPolygon);
++      }
++
++      temp2->seen = seen;
++     counter = y;
++
++     /*Find the adjacent face to this edge */
++      node = *(temp2->VertandId+y);                   
++      if (node->edge[2] != lastvert)
++        nextvert = node->edge[2];
++     else
++        nextvert = node->edge[1];
++                                      
++      /* Keep walking in this direction until we cannot do so */
++      while ((nextvert != lastvert) && (nextvert != -1))
++      {
++              walk++;
++              pListHead = PolFaces[nextvert];
++              temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++              numverts = temp2->nPolSize;
++              if ((numverts != 4) || (temp2->seen == seen))
++              {
++                      walk--;
++                      nextvert = -1;
++              }
++              else
++              {
++                      temp2->seen = seen;
++               /* Find edge that is not adjacent to the previous one */
++                      counter = 0;
++                      flag = TRUE;
++                      while ((counter < 3) && (flag))
++                      {
++                              if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                                      (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                                      ((*(temp2->pPolygon+counter) == previous_edge2) || 
++                                      (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                                      counter++;              
++                              else
++                                      flag = FALSE;   
++                      }
++              /* Get the IDs of the next edge */
++                   if (counter < 3)
++                   {
++                           previous_edge1 = *(temp2->pPolygon + counter);
++                           previous_edge2 = *(temp2->pPolygon + counter + 1);
++                   }
++                   else
++                   {
++                    previous_edge1 = *(temp2->pPolygon + counter);
++                    previous_edge2 = *(temp2->pPolygon);
++                   }
++      
++                   node = *(temp2->VertandId + counter);
++                   if (node->edge[1] == nextvert)
++                           nextvert = node->edge[2];
++                   else
++                           nextvert = node->edge[1];
++              }
++      }
++     seen++;
++      return walk;
++}
++
++
++BOOL Check_Right(int last_seen,PF_FACES temp2,int y,int face_id)
++{
++      /* Check when we last saw the face to the right of the current
++         one. We want to have seen it just before we started this strip
++      */
++
++      F_EDGES *node;
++      ListHead *pListHead;
++      register int nextvert,oldy;
++      PF_FACES t;
++      
++     oldy = y;
++      if (y != 3)
++              y = y+1;
++      else
++              y = 0;
++      node = *(temp2->VertandId + y);
++      if (face_id == node->edge[1])
++              nextvert = node->edge[2];
++      else
++              nextvert = node->edge[1];
++      
++     if (nextvert == -1)
++          return FALSE;
++     
++     pListHead = PolFaces[nextvert];
++      t = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++      if (t->seen != (last_seen - 1))
++      {
++               /* maybe because of the numbering, we are not
++                  on the right orientation, so we have to check the
++                  opposite one to be sure 
++           */
++              if (oldy != 0)
++                      y = oldy-1;
++              else
++                      y = 3;
++              node = *(temp2->VertandId + y);
++              if (face_id == node->edge[1])
++                      nextvert = node->edge[2];
++              else
++                      nextvert = node->edge[1];
++              if (nextvert == -1)
++               return FALSE;
++          pListHead = PolFaces[nextvert];
++              t = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++              if (t->seen != (last_seen - 1))
++                      return FALSE;
++      }
++      return TRUE;
++}
++
++
++int Update_and_Test(PF_FACES temp2,int y,BOOL first,int distance,int lastvert, int val)
++{
++           
++        static int last_seen = 17;
++        int previous_edge1, previous_edge2;
++        register int original_distance,nextvert,numverts,counter;
++        BOOL flag;
++        F_EDGES *node;
++        ListHead *pListHead;
++                                                        
++        original_distance = distance;
++        /* Find the edge that we are currently on */
++        if (y != 3)
++        {
++                previous_edge1 = *(temp2->pPolygon +y);
++                previous_edge2 = *(temp2->pPolygon + y + 1);
++        }
++        else
++        {
++                previous_edge1 = *(temp2->pPolygon +y);
++                previous_edge2 = *(temp2->pPolygon);
++        }
++
++        temp2->seen = val;
++        temp2->seen2 = val;
++              
++        node = *(temp2->VertandId+y);                   
++        if (lastvert != node->edge[2])
++                      nextvert = node->edge[2];
++         else
++                      nextvert = node->edge[1];
++                                        
++        /* Keep walking in this direction until we cannot do so  or
++              we go to distance */
++        while ((distance > 0)  && (nextvert != lastvert) && (nextvert != -1))
++        {
++                distance--;
++                                 
++                pListHead = PolFaces[nextvert];
++                temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++                temp2->seen = val;
++                              
++                if (temp2->seen2 == val)
++                {
++                     last_seen++;
++                     return (original_distance - distance);
++                }
++                
++                temp2->seen2 = val;
++                
++                numverts = temp2->nPolSize;
++                                
++               if (numverts != 4)
++                   nextvert = -1;
++              
++                else if ((!first) && (!(Check_Right(last_seen,temp2,y,nextvert))))
++                {
++                    last_seen++;
++                    return (original_distance - distance);
++                }
++                    else
++                {
++                        /* Find edge that is not adjacent to the previous one */
++                        counter = 0;
++                        flag = TRUE;
++                        while ((counter < 3) && (flag))
++                        {
++                                if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                                        (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                                        ((*(temp2->pPolygon+counter) == previous_edge2) ||
++                                        (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                                        counter++;
++                                else
++                                        flag = FALSE;
++                        }
++                        /* Get the IDs of the next edge */
++                        if (counter < 3)
++                        {
++                              previous_edge1 = *(temp2->pPolygon + counter);
++                              previous_edge2 = *(temp2->pPolygon + counter + 1);
++                        }
++                        else
++                        {
++                              previous_edge1 = *(temp2->pPolygon + counter);
++                              previous_edge2 = *(temp2->pPolygon);
++                        }
++                        if      ( ((*(temp2->walked+counter) == -1) && 
++                                (*(temp2->walked+counter+2) == -1)))
++                        {
++                                printf("There is an error in the walks!\n");
++                                printf("1Code %d %d \n",*(temp2->walked+counter),*(temp2->walked+counter+2));
++                                exit(0);
++                        }
++                        else
++                        {
++                                if      ((*(temp2->walked+counter) == -1) && 
++                                        (*(temp2->walked+counter-2) ==  -1))
++                                {
++                                        printf("There is an error in the walks!\n");
++                                        printf("2Code %d %d \n",*(temp2->walked+counter),*(temp2->walked+counter-2));
++                                        exit(0);
++                                }
++                        }
++                        node = *(temp2->VertandId + counter);
++                        y = counter;
++                            if (node->edge[1] == nextvert)
++                              nextvert = node->edge[2];
++                        else
++                              nextvert = node->edge[1];
++             }
++    }
++      
++    last_seen++;
++
++    if  (distance != 0)  
++    {
++              if (((nextvert == -1) || (nextvert == lastvert)) && (distance != 1))
++                      return (original_distance - distance);
++    }
++    return original_distance;
++}
++
++
++int Test_Adj(PF_FACES temp2,int x,int north,int distance,int lastvert, int value)
++{
++      /* if first time, then just update the last seen field */
++      if (x==1)
++              return(Update_and_Test(temp2,north,TRUE,distance,lastvert,value));
++      /* else we have to check if we are adjacent to the last strip */
++      else
++              return(Update_and_Test(temp2,north,FALSE,distance,lastvert,value));
++}
++  
++void Get_Band_Walk(PF_FACES temp2,int face_id,int *dir1,int *dir2, 
++                                      int orientation,int cutoff_length)
++{
++      int previous_edge1, previous_edge2;
++      F_EDGES *node;
++      ListHead *pListHead;
++      register int walk = 0, nextvert,numverts,counter;
++      BOOL flag;
++      
++      /*      Get the largest band that will include this face, starting
++              from orientation. Save the values of the largest band
++              (either north and south together, or east and west together)
++              in the direction variables.
++      */
++      /* Find the edge that we are currently on */
++     if (orientation != 3)
++     {
++                previous_edge1 = *(temp2->pPolygon + orientation);
++                previous_edge2 = *(temp2->pPolygon + orientation + 1);
++     }
++     else
++     {
++                previous_edge1 = *(temp2->pPolygon + orientation );
++                previous_edge2 = *(temp2->pPolygon);
++     }
++              
++     if (orientation == 0)
++     {
++                       if (*dir1 > *(temp2->walked + 1))
++                              *dir1 = *(temp2->walked + 1);
++                       if (*dir2 > *(temp2->walked + 3))
++                              *dir2 = *(temp2->walked + 3);
++      }
++      else if (orientation == 3)
++      {
++                      if (*dir1 > *(temp2->walked + orientation - 3))
++                           *dir1 = *(temp2->walked + orientation - 3) ;
++                      if (*dir2 > *(temp2->walked + orientation -1 ))
++                              *dir2 = *(temp2->walked + orientation - 1);
++      }
++      else
++      {
++                      if (*dir1 > *(temp2->walked + orientation - 1))
++                              *dir1 = *(temp2->walked + orientation -1) ;
++                      if (*dir2 > *(temp2->walked+ orientation + 1))
++                              *dir2 = *(temp2->walked + orientation + 1);
++      }
++        
++     /*       if we know already that we can't extend the
++              band from this face, we do not need to do the walk
++     */
++     if ((*dir1 != 0) && (*dir2 != 0))
++     {
++              /* Find the adjacent face to this edge */
++              node = *(temp2->VertandId+orientation);                   
++              if (face_id == node->edge[1])
++                      nextvert = node->edge[2];
++              else 
++                      nextvert = node->edge[1];
++      }
++     else
++              nextvert = -1; /* leave w/o walking */                                
++      
++      /* Keep walking in this direction until we cannot do so */
++     while ((nextvert != face_id) && (nextvert != -1))
++     {
++            walk++;
++            pListHead = PolFaces[nextvert];
++            temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++            numverts = temp2->nPolSize;
++            if ((numverts != 4)       || (walk > cutoff_length))
++                   nextvert = -1;
++            else
++            {
++                        /* Find edge that is not adjacent to the previous one */
++                 counter = 0;
++                 flag = TRUE;
++                 while ((counter < 3) && (flag))
++                 {
++                           if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                                (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                                ((*(temp2->pPolygon+counter) == previous_edge2) ||
++                                (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                                     counter++;
++                           else
++                                flag = FALSE;
++                 }
++                 /* Get the IDs of the next edge */
++                 if (counter < 3)
++                 {
++                        previous_edge1 = *(temp2->pPolygon + counter);
++                        previous_edge2 = *(temp2->pPolygon + counter + 1);
++                 }
++                 else
++                 {
++                        previous_edge1 = *(temp2->pPolygon + counter);
++                        previous_edge2 = *(temp2->pPolygon);
++                 }
++                
++                        /*    find out how far we can extend in the 2 directions
++                                      along this new face in the walk
++                        */
++                        if (counter == 0)
++                        {
++                                      if (*dir1 > *(temp2->walked + 1))
++                                              *dir1 = *(temp2->walked + 1);
++                                      if (*dir2 > *(temp2->walked + 3))
++                                              *dir2 = *(temp2->walked + 3);
++                        }
++                        else if (counter == 3)
++                        {
++                                      if (*dir1 > *(temp2->walked + counter - 3))
++                                              *dir1 = *(temp2->walked + counter - 3) ;
++                                      if (*dir2 > *(temp2->walked + counter -1 ))
++                                              *dir2 = *(temp2->walked + counter -1);
++                        }
++                        else
++                        {
++                                      if (*dir1 > *(temp2->walked + counter - 1))
++                                              *dir1 = *(temp2->walked + counter -1) ;
++                                      if (*dir2 > *(temp2->walked + counter + 1))
++                                              *dir2 = *(temp2->walked + counter + 1);
++                        }
++        
++                    /*        if we know already that we can't extend the
++                      band from this face, we do not need to do the walk
++                    */
++                       if ((*dir1 == 0) || (*dir2 == 0))
++                      nextvert = -1;
++                if (nextvert != -1)
++                {
++                      node = *(temp2->VertandId + counter);
++                      if (node->edge[1] == nextvert)
++                        nextvert = node->edge[2];
++                      else
++                        nextvert = node->edge[1];
++                }
++
++           }
++        }
++}
++
++
++
++
++int Find_Max(PF_FACES temp2,int lastvert,int north,int left,
++                      int *lastminup,int *lastminleft)
++{
++      int temp,walk,counter,minup,x,band_value;
++      int previous_edge1, previous_edge2;
++      F_EDGES *node;
++      ListHead *pListHead;
++      BOOL flag;      
++      static int last_seen = 0;
++      register int t,smallest_so_far,nextvert,max=-1;
++              
++     t= lastvert;
++     *lastminup = MAX_BAND;
++      *lastminleft = 1;
++
++     if (left == 3)
++      {
++          previous_edge1 = *(temp2->pPolygon + left);
++          previous_edge2 = *(temp2->pPolygon);
++      }
++                
++      else
++      {
++          previous_edge1 = *(temp2->pPolygon + left + 1);
++          previous_edge2 = *(temp2->pPolygon + left);
++      }
++
++      temp2->seen = last_seen;
++     walk = *(temp2->walked + left);
++
++     for (x=1;x<=(walk+1); x++)
++      {
++              /*   test to see if we have a true band
++                   that is, are they adjacent to each other
++              */
++        
++         minup = *(temp2->walked + north) + 1;
++
++          /*  if we are at the very first face, then we do not
++                   have to check the adjacent faces going up
++                   and our north distance is the distance of this face's
++                      north direction. 
++          */
++         if (x == 1) 
++          {
++                      *lastminup = minup;
++                      minup = Test_Adj(temp2,x,north,*lastminup,lastvert,last_seen);
++                      *lastminup = minup;
++               smallest_so_far = minup;       
++         }
++              
++      
++          /* find the largest band that we can have */
++          if (minup < (*lastminup))
++          {
++                      /*      see if we really can go up all the way 
++                              temp should by less than our equal to minup
++                              if it is less, then one of the faces was not
++                              adjacent to those next to it and the band height
++                              will be smaller
++                      */
++                      temp = Test_Adj(temp2,x,north,minup,lastvert,last_seen);
++                      if (temp > minup)
++                      {
++                              printf("There is an error in the test adj\n");
++                              exit(0);
++                      }
++                      minup = temp;
++                      band_value = x * minup;
++                      if (minup < smallest_so_far)
++                      {
++                              if (band_value > max)
++                      {
++                                      smallest_so_far = minup;
++                                      *lastminup = minup;
++                                      *lastminleft = x;
++                         max = band_value;
++                    }
++                              else
++                                      smallest_so_far = minup;
++                      }
++                      else
++                      {
++                              band_value = x * smallest_so_far;
++                if (band_value > max)
++                    {
++                           *lastminup = smallest_so_far;
++                         *lastminleft = x;
++                         max = band_value;
++                    }
++                      }
++              }
++              else
++              {
++                      if (x != 1)
++               {
++                    temp = Test_Adj(temp2,x,north,smallest_so_far,lastvert,last_seen);
++                           if (temp > smallest_so_far)
++                           {
++                                  printf("There is an error in the test adj\n");
++                                  exit(0);
++                           }
++                          smallest_so_far = temp;
++               }
++               band_value = x * smallest_so_far; 
++                      if (band_value > max)
++                      {
++                              *lastminup = smallest_so_far;
++                              *lastminleft = x;
++                              max = band_value;
++                      }
++              }
++              if ( x != (walk + 1))
++              {
++                      node = *(temp2->VertandId+left);
++                      if (lastvert == node->edge[1])
++                              nextvert = node->edge[2];
++                      else
++                              nextvert = node->edge[1];
++
++               lastvert = nextvert;
++               
++               if (nextvert == -1)
++                    return max;
++               
++               pListHead = PolFaces[nextvert];
++                      temp2 = (PF_FACES) PeekList(pListHead, LISTHEAD, 0);
++                      
++               /* if we have visited this face before, then there is an error */
++               if (((*(temp2->walked) == -1) && (*(temp2->walked+1) == -1) &&
++                              (*(temp2->walked+2) == -1) && (*(temp2->walked+3) == -1))
++                              || (temp2->nPolSize !=4) || (temp2->seen == last_seen))
++                      {
++
++                    if (lastvert == node->edge[1])
++                         nextvert = node->edge[2];
++                    else
++                         nextvert = node->edge[1];
++                    if (nextvert == -1)
++                         return max;
++                    lastvert = nextvert;
++                    /*   Last attempt to get the face ... */
++                    pListHead = PolFaces[nextvert];
++                      temp2 = (PF_FACES) PeekList(pListHead, LISTHEAD, 0);
++                    if (((*(temp2->walked) == -1) && (*(temp2->walked+1) == -1) &&
++                                   (*(temp2->walked+2) == -1) && (*(temp2->walked+3) == -1))
++                                   || (temp2->nPolSize !=4) || (temp2->seen == last_seen))
++                         return max;    /*   The polygon was not saved with the edge, not
++                                             enough room. We will get the walk when we come
++                                             to that polygon later.
++                                        */
++                      }
++                      else
++                      {
++                              counter = 0;
++                              flag = TRUE;
++                              temp2->seen = last_seen;
++
++                    while ((counter < 3) && (flag))
++                           {
++
++                         if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                                        (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                                        ((*(temp2->pPolygon+counter) == previous_edge2) ||
++                                        (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                                        counter++;
++                                   else
++                                        flag = FALSE;
++                    }
++               }
++              
++               /* Get the IDs of the next edge */
++               left = counter;
++                   north = left+1;
++               if (left ==3)
++                           north = 0; 
++                   if (counter < 3)
++               {
++                        previous_edge1 = *(temp2->pPolygon + counter + 1);
++                        previous_edge2 = *(temp2->pPolygon + counter);
++               }
++               else
++               {
++                        previous_edge1 = *(temp2->pPolygon + counter);
++                        previous_edge2 = *(temp2->pPolygon);
++               }
++
++          } 
++
++}
++last_seen++;
++return max;
++}
++
++void Mark_Face(PF_FACES temp2, int color1, int color2,
++                              int color3, FILE *output_file, BOOL end, int *edge1, int *edge2, 
++                    int *face_id, int norms, int texture)
++{
++     static int last_quad[4];
++     register int x,y,z=0;
++     int saved[2];
++     static int output1, output2,last_id;
++     BOOL cptexture;
++
++     /*   Are we done with the patch? If so return the last edge that
++          we will come out on, and that will be the edge that we will
++          start to extend upon.
++     */
++
++     cptexture = texture;
++     if (end)
++     {
++          *edge1 = output1;
++          *edge2 = output2;
++          *face_id = last_id;
++          return;
++     }
++
++     last_id = *face_id;
++      *(temp2->walked) = -1;
++      *(temp2->walked+1) = -1;
++      *(temp2->walked+2) = -1;
++      *(temp2->walked+3) = -1;
++      added_quad++;
++      temp2->nPolSize = 1;
++
++     if (patch == 0)
++     {
++          /*   At the first quad in the strip -- save it */
++          last_quad[0] = *(temp2->pPolygon);
++          last_quad[1] = *(temp2->pPolygon+1);
++          last_quad[2] = *(temp2->pPolygon+2);
++          last_quad[3] = *(temp2->pPolygon+3);
++          patch++;
++     }
++     else
++     {
++          /*   Now we have a triangle to output, find the edge in common */
++          for (x=0; x < 4 ;x++)
++          {
++              for (y=0; y< 4; y++)
++              {
++                   if (last_quad[x] == *(temp2->pPolygon+y))
++                   {
++                        saved[z++] = last_quad[x];               
++                        if (z > 2)
++                        {
++                             /*    This means that there was a non convex or
++                                   an overlapping polygon
++                             */
++                             z--;
++                             break;
++                        }
++                   }                             
++              }
++          }
++          
++          if (z != 2)
++          {
++               printf("Z is not 2 %d \n",patch);
++               printf("4 %d %d %d %d %d %d %d\n",*(temp2->pPolygon),
++                              *(temp2->pPolygon+1),*(temp2->pPolygon+2),*(temp2->pPolygon+3),
++                              color1,color2,color3);
++               printf("%d %d %d %d\n",last_quad[0],last_quad[1],last_quad[2],last_quad[3]);
++               exit(1);
++          }
++          
++          if (patch == 1)
++          {
++               /*   First one to output, there was no output edge */
++               patch++;
++               x = Adjacent(saved[0],saved[1],last_quad,4);
++               y = Adjacent(saved[1],saved[0],last_quad,4);
++               
++               /*   Data might be mixed and we do not have textures for some of the vertices */
++               if ((texture) && ( ((vt[x]) == 0) || ((vt[y])==0) || ((vt[saved[1]])==0)))
++                    cptexture = FALSE;
++
++               if ((!norms) && (!cptexture))
++               {
++                    fprintf(output_file,"\nt %d %d %d ",x+1,y+1,saved[1]+1);
++                    fprintf(output_file,"%d ",saved[0]+1);
++               }
++               else if ((norms) && (!cptexture))
++               {
++                    fprintf(output_file,"\nt %d//%d %d//%d %d//%d ",x+1,vn[x] +1,
++                                                                    y+1,vn[y] +1,
++                                                                    saved[1]+1,vn[saved[1]]+1);
++                    fprintf(output_file,"%d//%d ",saved[0]+1,vn[saved[0]]+1);
++               }
++               else if ((cptexture) && (!norms))
++               {
++                    fprintf(output_file,"\nt %d/%d %d/%d %d/%d ",x+1,vt[x] +1,
++                                                                    y+1,vt[y] +1,
++                                                                    saved[1]+1,vt[saved[1]]+1);
++                    fprintf(output_file,"%d//%d ",saved[0]+1,vt[saved[0]]+1);
++               }
++               else
++               {
++                    fprintf(output_file,"\nt %d/%d/%d %d/%d/%d %d/%d/%d ",x+1,vt[x]+1,vn[x] +1,
++                                                                    y+1,vt[y]+1,vn[y] +1,
++                                                                    saved[1]+1,vt[saved[1]]+1,vn[saved[1]]+1);
++                    fprintf(output_file,"%d/%d/%d ",saved[0]+1,vt[saved[0]]+1,vn[saved[0]]+1);
++               }
++
++               x = Adjacent(saved[0],saved[1],temp2->pPolygon,4);
++               y = Adjacent(saved[1],saved[0],temp2->pPolygon,4);
++
++               /*   Data might be mixed and we do not have textures for some of the vertices */
++               if ((texture) && ( (vt[x] == 0) || (vt[y]==0)))
++               {
++                    if (cptexture)
++                         fprintf(output_file,"\nq ");
++                    cptexture = FALSE;
++               }
++               if ((!norms) && (!cptexture))
++               {
++                    fprintf(output_file,"%d ",x+1);
++                    fprintf(output_file,"%d ",y+1);
++               }
++               else if ((norms) && (!cptexture))
++               {
++                    fprintf(output_file,"%d//%d ",x+1,vn[x]+1);
++                    fprintf(output_file,"%d//%d ",y+1,vn[y]+1);
++               }
++               else if ((cptexture) && (!norms))
++               {
++                    fprintf(output_file,"%d/%d ",x+1,vt[x]+1);
++                    fprintf(output_file,"%d/%d ",y+1,vt[y]+1);
++               }
++               else
++               {
++                    fprintf(output_file,"%d/%d/%d ",x+1,vt[x]+1,vn[x]+1);
++                    fprintf(output_file,"%d/%d/%d ",y+1,vt[y]+1,vn[y]+1);
++               }
++
++               output1 = x;
++               output2 = y;
++          }
++          
++          else 
++          {
++               x = Adjacent(output2,output1,temp2->pPolygon,4);
++               y = Adjacent(output1,output2,temp2->pPolygon,4);
++               /*   Data might be mixed and we do not have textures for some of the vertices */
++               if ((texture) && ( ((vt[x]) == 0) || ((vt[y])==0) ))
++                    texture = FALSE;
++
++               if ((!norms) && (!texture))
++               {
++                    fprintf(output_file,"\nq %d ",x+1);
++                    fprintf(output_file,"%d ",y+1);
++               }
++               else if ((norms) && (!texture))
++               {
++                    fprintf(output_file,"\nq %d//%d ",x+1,vn[x]+1);
++                    fprintf(output_file,"%d//%d ",y+1,vn[y]+1);
++               }
++               else if ((texture) && (!norms))
++               {
++                    fprintf(output_file,"\nq %d/%d ",x+1,vt[x]+1);
++                    fprintf(output_file,"%d/%d ",y+1,vt[y]+1);
++               }
++               else
++               {
++                    fprintf(output_file,"\nq %d/%d/%d ",x+1,vt[x]+1,vn[x]+1);
++                    fprintf(output_file,"%d/%d/%d ",y+1,vt[y]+1,vn[y]+1);
++               }
++               
++               output1 = x;
++               output2 = y;
++          }
++          
++          last_quad[0] = *(temp2->pPolygon);
++          last_quad[1] = *(temp2->pPolygon+1);
++          last_quad[2] = *(temp2->pPolygon+2);
++          last_quad[3] = *(temp2->pPolygon+3);
++     }
++}
++
++void Fast_Reset(int x)
++{
++      register int y,numverts;
++      register int front_walk, back_walk;
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++
++     pListHead = PolFaces[x];
++      temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++      numverts = temp->nPolSize;
++     
++     front_walk = 0; 
++     back_walk = 0;          
++     resetting = TRUE;
++          
++     /* we are doing this only for quads */
++      if (numverts == 4)
++      {
++                      /*      for each face not seen yet, do North and South together
++                              and East and West together
++                      */
++                      for (y=0;y<2;y++)
++                      {
++                              /* Check if the opposite sides were seen already */
++                      /* Find walk for the first edge */
++                              front_walk = Calculate_Walks(x,y,temp);
++                              /* Find walk in the opposite direction */
++                              back_walk = Calculate_Walks(x,y+2,temp);
++                              /*      Now put into the data structure the numbers that
++                              we have found
++                              */
++                    Assign_Walk(x,temp,front_walk,y,back_walk);
++                              Assign_Walk(x,temp,back_walk,y+2,front_walk);
++                      }
++      }
++     resetting = FALSE;
++}
++
++
++void Reset_Max(PF_FACES temp2,int face_id,int north,int last_north, int orientation,
++              int last_left,FILE *output_file,int color1,int color2,int color3,
++              BOOL start)
++{
++      register int walk = 0,count = 0;
++      int previous_edge1,previous_edge2;
++      int static last_seen = 1000;
++      F_EDGES *node;
++      ListHead *pListHead;
++      int f,t,nextvert,counter;
++     BOOL flag;
++
++ 
++     /*   Reset walks on faces, since we just found a patch */
++     if (orientation !=3)
++     {
++                previous_edge1 = *(temp2->pPolygon + orientation+1);
++                previous_edge2 = *(temp2->pPolygon + orientation );
++     }
++     else
++     {
++                previous_edge1 = *(temp2->pPolygon + orientation );
++                previous_edge2 = *(temp2->pPolygon);
++     }
++
++      /* only if we are going left, otherwise there will be -1 there */
++      /*Find the adjacent face to this edge */
++        
++     for (t = 0; t <=3 ; t++)
++     {
++             node = *(temp2->VertandId+t);
++              
++             if (face_id == node->edge[1])
++                f = node->edge[2];
++             else
++               f = node->edge[1];
++       
++             if (f != -1)
++                  Fast_Reset(f);
++        }
++
++        node = *(temp2->VertandId+orientation);
++        if (face_id == node->edge[1])
++             nextvert = node->edge[2];
++        else
++             nextvert = node->edge[1];
++
++      while ((last_left--) > 1)
++      {
++               
++          if (start)
++               Reset_Max(temp2,face_id,orientation,last_left,north,last_north,output_file,color1,color2,color3,FALSE);                
++        
++          face_id = nextvert;
++          pListHead = PolFaces[nextvert];                
++          temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++          if ((temp2->nPolSize != 4) && (temp2->nPolSize != 1))
++          {
++             /*   There is more than 2 polygons on the edge, and we could have
++                  gotten the wrong one
++             */
++             if (nextvert != node->edge[1])
++                  nextvert = node->edge[1];
++             else
++                  nextvert = node->edge[2];
++             pListHead = PolFaces[nextvert];          
++             temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++             node = *(temp2->VertandId+orientation);
++          }
++
++                
++         if (!start)
++         {
++             for (t = 0; t <=3 ; t++)
++             {
++                    node = *(temp2->VertandId+t);
++              
++                    if (face_id == node->edge[1])
++                         f = node->edge[2];
++                    else
++                         f = node->edge[1];
++          
++                    if (f != -1)
++                         Fast_Reset(f);
++             }
++        }
++
++
++        counter = 0;
++         flag = TRUE;
++         while ((counter < 3) && (flag))
++        {
++             if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                   (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                  ((*(temp2->pPolygon+counter) == previous_edge2) ||
++                   (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                   counter++;
++             else
++                  flag = FALSE;
++        }
++
++        /* Get the IDs of the next edge */
++        if (counter < 3)
++        {
++             previous_edge1 = *(temp2->pPolygon + counter+1);
++             previous_edge2 = *(temp2->pPolygon + counter);
++        }
++        else
++        {
++             previous_edge1 = *(temp2->pPolygon + counter);
++             previous_edge2 = *(temp2->pPolygon);
++        }
++        orientation = counter;
++
++        node = *(temp2->VertandId + counter);
++         if (node->edge[1] == nextvert)
++                      nextvert = node->edge[2];
++         else
++                      nextvert = node->edge[1];
++
++        if (!reversed)
++        {
++               if (counter != 3)
++                           north = counter +1;
++                   else
++                           north = 0;
++        }
++        else
++        {
++               if (counter != 0)
++                    north = counter -1;
++               else
++                    north = 3;
++    
++        }
++     }
++if (start)
++      Reset_Max(temp2,face_id,orientation,last_left,north,last_north,output_file,color1,color2,color3,FALSE);
++else if (nextvert != -1)       
++     Fast_Reset(nextvert);
++
++}
++
++
++int Peel_Max(PF_FACES temp2,int face_id,int north,int last_north, int orientation,
++              int last_left,FILE *output_file,int color1,int color2,int color3,
++              BOOL start, int *swaps_added, int norms, int texture)
++{
++      int end1,end2,last_id,s=0,walk = 0,count = 0;
++      int previous_edge1,previous_edge2;
++      int static last_seen = 1000;
++      F_EDGES *node;
++      ListHead *pListHead;
++      int nextvert,numverts,counter,dummy,tris=0;
++     BOOL flag;
++
++     /*   Peel the patch from the model.
++          We will try and extend off the end of each strip in the patch. We will return the
++          number of triangles completed by this extension only, and the number of swaps
++          in the extension only.
++     */       
++     patch = 0;
++     
++     if (orientation !=3)
++     {
++                previous_edge1 = *(temp2->pPolygon + orientation+1);
++                previous_edge2 = *(temp2->pPolygon + orientation );
++     }
++     else
++     {
++                previous_edge1 = *(temp2->pPolygon + orientation );
++                previous_edge2 = *(temp2->pPolygon);
++     }
++
++
++     walk = *(temp2->walked + orientation);
++      
++     /* only if we are going left, otherwise there will be -1 there */
++      if ((start) && ((walk+1) < last_left))
++      {
++              printf("There is an error in the left %d %d\n",walk,last_left);
++              exit(0);
++      }
++      
++     /* Find the adjacent face to this edge */
++     node = *(temp2->VertandId+orientation);
++     if (face_id == node->edge[1])
++          nextvert = node->edge[2];
++     else
++          nextvert = node->edge[1];
++      temp2->seen = last_seen;
++
++
++      while ((last_left--) > 1)
++      {
++              if (start)
++             tris += Peel_Max(temp2,face_id,orientation,last_left,north,last_north,output_file,
++                              color1,color2,color3,FALSE,swaps_added,norms,texture);              
++          else
++             Mark_Face(temp2,color1,color2,color3,output_file,FALSE,&dummy,&dummy,&face_id,norms,texture);
++              
++
++          pListHead = PolFaces[nextvert];      
++          temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++          numverts = temp2->nPolSize;
++      
++          if ((numverts != 4) || (temp2->seen == last_seen) 
++                      ||  (nextvert == -1))
++          {
++      
++             /*   There is more than 2 polygons on the edge, and we could have
++                  gotten the wrong one
++             */
++             if (nextvert != node->edge[1])
++                  nextvert = node->edge[1];
++             else
++                  nextvert = node->edge[2];
++             pListHead = PolFaces[nextvert];
++             temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++             numverts = temp2->nPolSize;
++             if ((numverts != 4) || (temp2->seen == last_seen) )
++             {
++                  printf("Peel 2 %d\n",numverts);
++                  exit(1);
++             }
++        }
++
++        face_id = nextvert;
++        temp2->seen = last_seen;
++                
++        counter = 0;
++        flag = TRUE;
++         while ((counter < 3) && (flag))
++        {
++             if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                   (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                  ((*(temp2->pPolygon+counter) == previous_edge2) ||
++                   (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                   counter++;
++             else
++                  flag = FALSE;
++        }
++        /* Get the IDs of the next edge */
++        if (counter < 3)
++        {
++             previous_edge1 = *(temp2->pPolygon + counter+1);
++             previous_edge2 = *(temp2->pPolygon + counter);
++        }
++        else
++        {
++             previous_edge1 = *(temp2->pPolygon + counter);
++             previous_edge2 = *(temp2->pPolygon);
++        }
++        orientation = counter;
++                            
++         node = *(temp2->VertandId + counter);
++         if (node->edge[1] == nextvert)
++                      nextvert = node->edge[2];
++         else
++                      nextvert = node->edge[1];
++
++         if (!reversed)
++        {
++               if (counter != 3)
++                           north = counter +1;
++                   else
++                           north = 0;
++        }
++        else
++        {
++               if (counter != 0)
++                    north = counter -1;
++               else
++                    north = 3;
++        }
++}
++
++if (start)
++      tris += Peel_Max(temp2,face_id,orientation,last_left,north,last_north,output_file,
++                        color1,color2,color3,FALSE,swaps_added,norms,texture);        
++else
++     Mark_Face(temp2,color1,color2,color3,output_file,FALSE,&dummy,&dummy,&face_id,norms,texture);/* do the last face */
++
++last_seen++;
++
++/*    Get the edge that we came out on the last strip of the patch */
++Mark_Face(NULL,0,0,0,output_file,TRUE,&end1,&end2,&last_id,norms,texture);
++tris += Extend_Face(last_id,end1,end2,&s,output_file,color1,color2,color3,vn,norms,vt,texture);
++*swaps_added = *swaps_added + s;
++return tris;
++}
++
++
++
++void Find_Bands(int numfaces, FILE *output_file, int *swaps, int *bands, 
++                int *cost, int *tri, int norms, int *vert_norms, int texture, int *vert_texture)
++{
++
++      register int x,y,max1,max2,numverts,face_id,flag,maximum = 25;
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++      int color1 = 0, color2 = 100, color3 = 255;
++      int color = 0,larger,smaller;
++      int north_length1,last_north,left_length1,last_left,north_length2,left_length2;
++     int total_tri = 0, total_swaps = 0,last_id;
++     int end1, end2,s=0;
++     register int cutoff = 20;
++    
++     /*   Code that will find the patches. "Cutoff" will be
++          the cutoff of the area of the patches that we will be allowing. After
++          we reach this cutoff length, then we will run the local algorithm on the
++          remaining faces.
++     */
++
++      /*      For each faces that is left find the largest possible band that we can
++              have with the remaining faces. Note that we will only be finding patches
++          consisting of quads.
++      */
++
++vn = vert_norms;
++vt = vert_texture;
++y=1;
++*bands = 0;
++
++while ((maximum >= cutoff))
++{
++      y++;
++     maximum = -1;
++      for (x=0; x<numfaces; x++)
++      { 
++                      
++          /*   Used to produce the triangle strips */
++               
++          /* for each face, get the face */
++              pListHead = PolFaces[x];
++              temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++              numverts = temp->nPolSize;
++              
++          /* we are doing this only for quads */
++              if (numverts == 4)
++              {
++                      /*   We want a face that is has not been used yet,
++                    since we know that that face must be part of
++                              a band. Then we will find the largest band that
++                              the face may be contained in
++                      */
++                      
++               /*  Doing the north and the left */
++                      if ((*(temp->walked) != -1) && (*(temp->walked+3) != -1))
++                              max1 = Find_Max(temp,x,0,3,&north_length1,&left_length1);
++                      if ((*(temp->walked+1) != -1) && (*(temp->walked+2) != -1))
++                              max2 = Find_Max(temp,x,2,1,&north_length2,&left_length2);
++                      if ((max1 != (north_length1 * left_length1)) ||
++                          (max2 != (north_length2 * left_length2)))
++                      {
++                              printf("Max1 %d, %d %d  Max2 %d, %d %d\n",max1,north_length1,left_length1,max2,north_length2,left_length2);
++                              exit(0);
++                      }
++                
++                    
++               if ((max1 > max2) && (max1 > maximum))
++                      {
++                    maximum = max1;
++                    face_id = x;
++                    flag = 1; 
++                    last_north = north_length1;
++                    last_left = left_length1;
++                    /* so we know we saved max1 */
++                      }
++                      else if ((max2 > maximum) )
++                      {
++                    maximum = max2;
++                    face_id = x;
++                    flag = 2; 
++                    last_north = north_length2;
++                    last_left = left_length2;
++                    /* so we know we saved max2 */
++               }
++          }
++     }
++     if ((maximum < cutoff) && (*bands == 0))
++          return;
++     pListHead = PolFaces[face_id];
++     temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0);        
++     /*   There are no patches that we found in this pass */
++     if (maximum == -1)
++          break;
++     /*printf("The maximum is  face %d area %d: lengths %d %d\n",face_id,maximum,last_north,last_left);*/
++
++     if (last_north > last_left)
++     {
++          larger = last_north;
++          smaller = last_left;
++     }
++     else
++     {
++          larger = last_left;
++          smaller = last_north;
++     }
++
++     length = larger;
++
++if (flag == 1)
++{
++      if (last_north > last_left) /*     go north sequentially */
++     {
++          total_tri += Peel_Max(temp,face_id,0,last_north,3,last_left,output_file,color1,color2,color3,TRUE,&s,norms,texture);
++          Reset_Max(temp,face_id,0,last_north,3,last_left,output_file,color1,color2,color3,TRUE);
++          total_swaps += s;
++     }
++    else
++    {
++         reversed = TRUE;
++         total_tri += Peel_Max(temp,face_id,3,last_left,0,last_north,output_file,color1,color2,color3,TRUE,&s,norms,texture);
++         Reset_Max(temp,face_id,3,last_left,0,last_north,output_file,color1,color2,color3,TRUE);
++         reversed = FALSE;
++         total_swaps += s;
++    }
++
++     
++    /*    Get the edge that we came out on the last strip of the patch */
++    Mark_Face(NULL,0,0,0,NULL,TRUE,&end1,&end2,&last_id,norms,texture);
++    total_tri += Extend_Face(last_id,end1,end2,&s,output_file,color1,color2,color3,vn,norms,vt,texture);
++    total_swaps += s;
++
++}
++else
++{
++     if (last_north > last_left)
++     {
++          total_tri += Peel_Max(temp,face_id,2,last_north,1,last_left,output_file,color1,color2,color3,TRUE,&s,norms,texture); 
++          Reset_Max(temp,face_id,2,last_north,1,last_left,output_file,color1,color2,color3,TRUE); 
++          total_swaps += s;
++     }
++     else
++     {
++          reversed = TRUE;
++          total_tri += Peel_Max(temp,face_id,1,last_left,2,last_north,output_file,color1,color2,color3,TRUE,&s,norms,texture);
++          Reset_Max(temp,face_id,1,last_left,2,last_north,output_file,color1,color2,color3,TRUE);
++          reversed = FALSE;
++          total_swaps += s;
++     }
++
++     /*    Get the edge that we came out on on the patch */
++    Mark_Face(NULL,0,0,0,NULL,TRUE,&end1,&end2,&last_id,norms,texture);
++    total_tri += Extend_Face(last_id,end1,end2,&s,output_file,color1,color2,color3,vn,norms,vt,texture);
++    total_swaps += s;
++}
++
++    /*  Now compute the cost of transmitting this band, is equal to 
++        going across the larger portion sequentially,
++        and swapping 3 times per other dimension
++    */
++
++total_tri += (maximum * 2);
++*bands = *bands + smaller;
++
++}
++
++/*printf("We transmitted %d triangles,using %d swaps and %d strips\n",total_tri,
++        total_swaps, *bands);
++printf("COST %d\n",total_tri + total_swaps + *bands + *bands);*/
++*cost = total_tri + total_swaps + *bands + *bands;
++*tri = total_tri;
++added_quad = added_quad * 4;
++*swaps = total_swaps;
++}
++
++ 
++void Save_Rest(int *numfaces)
++{
++    /*  Put the polygons that are left into a data structure so that we can run the
++        stripping code on it.
++    */
++    register int x,y=0,numverts;
++    ListHead *pListHead;
++    PF_FACES temp=NULL;
++
++    for (x=0; x<*numfaces; x++)
++    { 
++                      /* for each face, get the face */
++                      pListHead = PolFaces[x];
++                      temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++                      numverts = temp->nPolSize;
++               /*  If we did not do the face before add it to data structure with new 
++                   face id number
++               */
++               if (numverts != 1)
++               {
++                   CopyFace(temp->pPolygon,numverts,y+1,temp->pNorms);
++                   y++;
++               }
++               /*   Used it, so remove it */
++               else
++                    RemoveList(pListHead,(PLISTINFO) temp);
++
++    }
++    *numfaces = y;
++}
++
++void Assign_Walk(int lastvert,PF_FACES temp2, int front_walk,int y,
++                              int back_walk)
++{
++/*      Go back and do the walk again, but this time save the lengths inside
++        the data structure.
++        y was the starting edge number for the front_walk length
++        back_walk is the length of the walk along the opposite edge
++ */
++        int previous_edge1, previous_edge2;
++        register int walk = 0,nextvert,numverts,counter;
++        BOOL flag;
++        F_EDGES *node;
++        ListHead *pListHead;
++        register int total_walk, start_back_walk;
++        static int seen = 0;
++        static BOOL first = TRUE;         
++        int test;
++        BOOL f = TRUE, wrap = FALSE, set = FALSE;
++             test = lastvert;
++
++        /*     In the "Fast_Reset" resetting will be true */
++        if ((resetting) && (first))
++        {
++             seen = 0;
++             first = FALSE;
++        }
++
++        seen++;
++        total_walk = front_walk + back_walk;
++        start_back_walk = back_walk;
++        /*     Had a band who could be a cycle  */
++        if (front_walk == back_walk)
++             wrap = TRUE;
++             
++        /* Find the edge that we are currently on */
++        if (y != 3)
++        {
++                previous_edge1 = *(temp2->pPolygon +y);
++                previous_edge2 = *(temp2->pPolygon + y + 1);
++        }
++        else
++        {
++                previous_edge1 = *(temp2->pPolygon +y);
++                previous_edge2 = *(temp2->pPolygon);
++        }
++
++        /* Assign the lengths */
++         if (y < 2) 
++         {
++                *(temp2->walked+y) = front_walk--;
++                       *(temp2->walked+y+2) = back_walk++;
++         }
++         else
++         {                            
++               *(temp2->walked+y) = front_walk--;
++                      *(temp2->walked+y-2) = back_walk++;
++         }
++
++         /*Find the adjacent face to this edge */
++        node = *(temp2->VertandId+y);                   
++
++        if (node->edge[2] != lastvert)
++          nextvert = node->edge[2];
++        else
++          nextvert = node->edge[1];
++                                       
++        temp2->seen3 = seen;
++        
++        /* Keep walking in this direction until we cannot do so */
++        while ((nextvert != lastvert) && (nextvert != -1) && (front_walk >= 0))
++        {
++                   walk++;
++               pListHead = PolFaces[nextvert];
++               
++               temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++               numverts = temp2->nPolSize;
++               if ((numverts != 4))
++               {
++                    nextvert = -1;
++                    /* Don't include this face in the walk */
++                    walk--;
++               }
++               else
++               {
++                    /* Find edge that is not adjacent to the previous one */
++                    counter = 0;
++                    flag = TRUE;
++                    while ((counter < 3) && (flag))
++                    {
++                         if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                               (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                              ((*(temp2->pPolygon+counter) == previous_edge2) ||
++                               (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                              counter++;
++                         else
++                              flag = FALSE;
++                    }
++                    /* Get the IDs of the next edge */
++                    if (counter < 3)
++                    {
++                         previous_edge1 = *(temp2->pPolygon + counter);
++                         previous_edge2 = *(temp2->pPolygon + counter + 1);
++                    }
++                    else
++                    {
++                         previous_edge1 = *(temp2->pPolygon + counter);
++                         previous_edge2 = *(temp2->pPolygon);
++                    }
++               
++
++                        /*      Put in the walk lengths */
++                        if (counter < 2)
++                        {
++                        if (((*(temp2->walked + counter) >= 0)
++                                || (*(temp2->walked +counter + 2) >= 0)))
++                                {
++                                        if ((resetting == FALSE) && ((temp2->seen3) != (seen-1)))
++                                        {
++                                                /*   If there are more than 2 polygons adjacent
++                                        to an edge then we can be trying to assign more than
++                                        once. We will save the smaller one
++                                   */
++                                   temp2->seen3 = seen;
++                                   if ( (*(temp2->walked+counter) <= front_walk) &&
++                                        (*(temp2->walked+counter+2) <= back_walk) )
++                                        return;
++                                   if (*(temp2->walked+counter) > front_walk)
++                                       *(temp2->walked+counter) = front_walk--;
++                                   else
++                                        front_walk--;
++                                   if (*(temp2->walked+counter+2) > back_walk)
++                                       *(temp2->walked+counter+2) = back_walk++;
++                                   else
++                                        back_walk++;
++                                        }
++                                        else if (resetting == FALSE)
++                                        {
++                                                /* if there was a cycle then all lengths are the same */
++                                                walk--;
++                                                back_walk--;
++                                                front_walk++;
++                                   temp2->seen3 = seen;
++                                   *(temp2->walked+counter) = front_walk--;
++                                   *(temp2->walked+counter+2) = back_walk++;
++                              }
++                              else if (((temp2->seen3 == (seen-1))
++                                   && (wrap) && (walk == 1)) || (set))
++                              {
++                                                /* if there was a cycle then all lengths are the same */
++                                                set = TRUE;
++                                   walk--;
++                                                back_walk--;
++                                                front_walk++;
++                                   temp2->seen3 = seen;
++                                   *(temp2->walked+counter) = front_walk--;
++                                   *(temp2->walked+counter+2) = back_walk++;
++                              }
++                              else
++                              {
++                                   temp2->seen3 = seen;
++                                   *(temp2->walked+counter) = front_walk--;
++                                   *(temp2->walked+counter+2) = back_walk++;
++                              }
++                        } /* if was > 0 */    
++                        else
++                        {
++                             temp2->seen3 = seen;
++                             *(temp2->walked+counter) = front_walk--;
++                             *(temp2->walked+counter+2) = back_walk++;
++                        }
++                    }
++              
++               else
++               {
++                    if (((*(temp2->walked + counter) >= 0 )
++                        || (*(temp2->walked +counter - 2) >= 0)) )
++                    {
++                         if ((temp2->seen3 != (seen-1))  && (resetting == FALSE))
++                         {
++                              /*   If there are more than 2 polygons adjacent
++                                   to an edge then we can be trying to assign more than
++                                   once. We will save the smaller one
++                              */
++                              temp2->seen3 = seen;
++                              if ( (*(temp2->walked+counter) <= front_walk) &&
++                                   (*(temp2->walked+counter-2) <= back_walk) )
++                                   return;
++                              if (*(temp2->walked+counter) > front_walk)
++                                   *(temp2->walked+counter) = front_walk--;
++                              else
++                                   front_walk--;
++                              if (*(temp2->walked+counter-2) > back_walk)
++                                   *(temp2->walked+counter-2) = back_walk++;
++                              else
++                                   back_walk++;
++                              }
++                                   else if (resetting == FALSE)
++                              {
++                                      walk--;
++                                      back_walk--;
++                                      front_walk++;
++                               temp2->seen3 = seen;
++                              *(temp2->walked+counter) = front_walk--;
++                              *(temp2->walked+counter-2) = back_walk++;
++                         }
++                         else if (((temp2->seen3 == (seen-1)) && (walk == 1) && (wrap))
++                              || (set))
++                         {
++                                           /* if there was a cycle then all lengths are the same */
++                                           set = TRUE;
++                              walk--;
++                                           back_walk--;
++                                           front_walk++;
++                              temp2->seen3 = seen;
++                              *(temp2->walked+counter) = front_walk--;
++                              *(temp2->walked+counter-2) = back_walk++;
++                         }
++                         else
++                         {
++                              temp2->seen3 = seen;
++                              *(temp2->walked+counter) = front_walk--;
++                              *(temp2->walked+counter-2) = back_walk++;
++                         }
++                      }
++                    else
++                    {
++                         temp2->seen3 = seen;
++                         *(temp2->walked+counter) = front_walk--;
++                         *(temp2->walked+counter-2) = back_walk++;
++                    }
++                              
++                   } 
++                   if (nextvert != -1)
++                   {
++                           node = *(temp2->VertandId + counter);
++                      if (node->edge[1] == nextvert)
++                              nextvert = node->edge[2];
++                      else
++                              nextvert = node->edge[1];
++               }
++              
++     }
++}
++if ((EVEN(seen)) )
++     seen+=2;
++}
++
++void Save_Walks(int numfaces)
++{
++      int x,y,numverts;
++      int front_walk, back_walk;
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++
++      for (x=0; x<numfaces; x++)
++      { 
++              /* for each face, get the face */
++              pListHead = PolFaces[x];
++              temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++              numverts = temp->nPolSize;
++              front_walk = 0; 
++          back_walk = 0;
++
++          /* we are finding patches only for quads */
++              if (numverts == 4)
++              {
++                      /*      for each face not seen yet, do North and South together
++                              and East and West together
++                      */
++                      for (y=0;y<2;y++)
++                      {
++                              /*   Check if the opposite sides were seen already from another
++                         starting face, if they were then there is no need to do the walk again
++                    */
++
++                              if      ( ((*(temp->walked+y) == -1) &&
++                                      (*(temp->walked+y+2) == -1) ))
++                              {
++                                      /* Find walk for the first edge */
++                                      front_walk = Calculate_Walks(x,y,temp);
++                                      /* Find walk in the opposite direction */
++                                      back_walk = Calculate_Walks(x,y+2,temp);
++                                      /*      Now put into the data structure the numbers that
++                                              we have found
++                                      */
++                         Assign_Walk(x,temp,front_walk,y,back_walk);
++                                      Assign_Walk(x,temp,back_walk,y+2,front_walk);
++                      }
++                      }
++              }
++      }
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7322d937c8c8b69a329bb1a1ec32022376939e08
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,181 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: options.c
++     This file contains routines that are used to determine the options
++     that were specified by the user
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "options.h"
++#include "global.h"
++
++int power_10(int power)
++{
++      /*      Raise 10 to the power */
++      register int i,p;
++
++      p = 1;
++      for (i = 1; i <= power; ++i)
++              p = p * 10;
++      return p;
++}
++
++float power_negative(int power)
++{
++     /*   Raise 10 to the negative power */
++
++     register int i;
++     float p;
++     
++     p = (float)1;
++     for (i = 1; i<=power; i++)
++          p = p * (float).1;
++     return p;
++}
++
++float convert_array(int num[],int stack_size)
++{
++      /* Convert an array of characters to an integer */
++      
++      register int counter,c;
++      float temp =(float)0.0;
++
++      for (c=(stack_size-1), counter = 0; c>=0; c--, counter++)
++     {
++          if (num[c] == -1)
++          /*   We are at the decimal point, convert to decimal
++               less than 1
++          */
++          {
++               counter = -1;
++               temp = power_negative(stack_size - c - 1) * temp;
++          }
++          else 
++               temp += power_10(counter) * num[c];
++     }
++                      
++      return(temp);
++}
++
++float get_options(int argc, char **argv, int *f, int *t, int *tr, int *group)
++{
++     char c;
++     int count = 0;
++     int buffer[MAX1];
++     int next = 0;
++     /*    tie variable */
++     enum tie_options tie = FIRST;
++     /*   triangulation variable */
++     enum triangulation_options triangulate = WHOLE;
++     /*   normal difference variable (in degrees) */
++     float norm_difference = (float)360.0;
++     /*   file-type variable */
++     enum file_options file_type = ASCII;
++
++     /*      User has the wrong number of options */
++      if ((argc > 5) || (argc < 2))
++      {
++              printf("Usage: bands -[file_option][ties_option][triangulation_option][normal_difference] file_name\n");
++              exit(0);
++      }
++      
++     /* Interpret the options specified */
++      while (--argc > 0 && (*++argv)[0] == '-')
++     {
++          /*   At the next option that was specified */
++          next = 1;
++          while (c = *++argv[0])
++                      switch (c)
++              {
++                              case 'f': 
++                                      /*      Use the first polygon we see. */
++                         tie = FIRST;
++                                      break;
++                              
++                              case 'r':
++                                      /*      Randomly choose the next polygon */
++                         tie = RANDOM;
++                                      break;
++
++                              case 'a':
++                                      /*      Alternate direction in choosing the next polygon */
++                         tie = ALTERNATE;
++                                      break;
++
++                              case 'l':
++                                      /*      Use lookahead to choose the next polygon */
++                         tie = LOOK;
++                                      break;
++
++                              case 'q':
++                                      /*  Try to reduce swaps */
++                         tie = SEQUENTIAL;
++                                      break;
++
++                              case 'p':
++                                      /*      Use partial triangulation of polygons */
++                         triangulate = PARTIAL;
++                                      break;
++
++                              case 'w':
++                                      /*      Use whole triangulation of polygons */
++                         triangulate = WHOLE;
++                                      break;
++
++                    case 'b':
++                         /*      Input file is in binary */
++                         file_type = BINARY;
++                         break;
++
++                    case 'g':
++                         /*   Strips will be grouped according to the groups in 
++                              the data file. We will have to restrict strips to be
++                              in the grouping of the data file.
++                         */
++                         *group = 1;
++                  
++                         /*   Get each the value of the integer */
++                         /*   We have an integer */
++                    default:
++                         if ((c >= '0') && (c <= '9'))
++                         {
++                              /*   More than one normal difference specified, use the last one */
++                              if (next == 1)
++                              {
++                                   count = 0;
++                                   next = 0;
++                              }
++                              buffer[count++] = ATOI(c);
++                         }
++                              /*   At the decimal point */
++                         else if (c == '.')
++                         {
++                              /*   More than one normal difference specified, use the last one */
++                              if (next == 1)
++                              {
++                                   count = 0;
++                                   next = 0;
++                              }
++                              buffer[count++] = -1;
++                         }
++                         else 
++                              break;
++              }
++     }
++     /*   Convert the buffer of characters to a floating pt integer */
++     if (count != 0) 
++          norm_difference = convert_array(buffer,count);
++     *f = file_type;
++     *t = tie;
++     *tr = triangulate;
++     return norm_difference;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..055d33ea7512bce959fecbcf677c7e3f0a03e538
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: options.h
++-----------------------------------------------------------------------*/
++
++float get_options();
++enum file_options {ASCII,BINARY};
++enum tie_options {FIRST, RANDOM, ALTERNATE, LOOK, SEQUENTIAL};
++enum triangulation_options {PARTIAL,WHOLE};
++     
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d6c30f613757f52d831b32e2d38cd7ac98b16ddd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,582 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: output.c
++     This file contains routines that are finding and outputting the
++     strips from the local algorithm
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "global.h"
++#include "polverts.h"
++#include "triangulate.h"
++#include "partial.h"
++#include "sturcts.h"
++#include "ties.h"
++#include "options.h"
++#include "common.h"
++#include "util.h"
++#include "free.h"
++
++int *vn;
++int *vt;
++int norm;
++int text;
++
++int Finished(int *swap, FILE *output, BOOL global)
++{
++     /*   We have finished all the triangles, now is time to output to
++           the data file. In the strips data structure, every three ids
++           is  a triangle. Now we see whether we can swap, or make a new strip
++           or continue the strip, and output the data accordingly to the
++           data file. 
++     */
++     register int start_swap = 0;
++     int num,x,vertex1,vertex2;
++     ListHead *pListHead;
++     int id[2],other1,other2,index = 0,a,b,c;
++     P_STRIPS temp1,temp2,temp3,temp4,temp5,temp6;
++     BOOL cptexture;
++     *swap =0;
++    
++     cptexture = text;
++     pListHead = strips[0];
++     if (pListHead == NULL)
++         return 0;
++
++     num = NumOnList(pListHead);
++     /*printf ("There are %d triangles in the extend\n",num/3);*/
++
++     /* Go through the list triangle by triangle */
++      temp1 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 0);
++      temp2 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 1);
++      temp3 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 2);
++      
++      /*   Next triangle for lookahead */
++     temp4 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 3);
++        
++
++     /*    There is only one polygon in the strip */
++     if (temp4 == NULL)
++     {
++           /*   Data might be mixed and we do not have textures for some of the vertices */
++           if ((text) &&  (vt[temp3->face_id] == 0))
++                    cptexture = FALSE;
++           if ((norm) && (!cptexture))
++                fprintf(output,"%d//%d %d//%d %d//%d",temp3->face_id+1,vn[temp3->face_id]+1,
++                                temp2->face_id+1,vn[temp2->face_id]+1,
++                                temp1->face_id+1,vn[temp1->face_id]+1);
++           else if ((cptexture) && (!norm))
++                fprintf(output,"%d/%d %d/%d %d/%d",temp3->face_id+1,vt[temp3->face_id]+1,
++                        temp2->face_id+1,vt[temp2->face_id]+1,
++                        temp1->face_id+1,vt[temp1->face_id]+1);
++           else if ((cptexture)&& (norm))
++                fprintf(output,"%d/%d/%d %d/%d/%d %d/%d/%d",temp3->face_id+1,vt[temp3->face_id]+1,vn[temp3->face_id]+1,
++                        temp2->face_id+1,vt[temp2->face_id]+1,vn[temp2->face_id]+1,
++                        temp1->face_id+1,vt[temp1->face_id]+1,vn[temp1->face_id]+1);
++           else 
++                fprintf(output,"%d %d %d",temp3->face_id+1,temp2->face_id+1,temp1->face_id+1);
++           Free_Strips();
++            return 1;
++        }
++        
++        /*    We have a real strip */
++        temp5 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 4);
++        temp6 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 5);
++        
++        if ((temp1 == NULL) || (temp2 == NULL) || (temp3 == NULL) || (temp5 == NULL) || (temp6 == NULL))
++        {
++             printf("There is an error in the output of the triangles\n");
++             exit(0);
++        }
++
++        /*   Find the vertex in the first triangle that is not in the second */
++        vertex1 = Different(temp1->face_id,temp2->face_id,temp3->face_id,temp4->face_id,temp5->face_id,temp6->face_id,&other1,&other2);
++        /*    Find the vertex in the second triangle that is not in the first */
++        vertex2 = Different(temp4->face_id,temp5->face_id,temp6->face_id,temp1->face_id,temp2->face_id,temp3->face_id,&other1,&other2);
++
++        /* Lookahead for the correct order of the 2nd and 3rd vertex of the first triangle */
++       temp1 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 6);
++        temp2 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 7);
++        temp3 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 8);
++       
++       if (temp1 != NULL)
++          other1 = Different(temp3->face_id,temp4->face_id,temp5->face_id,temp1->face_id,temp2->face_id,temp3->face_id,&other1,&a);
++         
++        id[index] = vertex1; index = !index;
++        id[index] = other1; index = !index;
++        id[index] = other2; index = !index;
++
++        a = temp4->face_id; 
++        b = temp5->face_id; 
++        c = temp6->face_id;
++
++      /*    If we need to rearrange the first sequence because otherwise
++            there would have been a swap.
++      */
++
++      if ((temp3 != NULL) && (text) && ( vt[temp3->face_id]==0))
++           cptexture = FALSE;
++      if ((norm) && (!cptexture))
++           fprintf(output,"%d//%d %d//%d %d//%d ",vertex1+1,vn[vertex1]+1,other1+1,vn[other1]+1,
++                                                  other2+1,vn[other2]+1);
++      else if ((cptexture) && (!norm))
++           fprintf(output,"%d/%d %d/%d %d/%d ",vertex1+1,vt[vertex1]+1,other1+1,vt[other1]+1,
++                                               other2+1,vt[other2]+1);
++      else if ((cptexture) && (norm))
++           fprintf(output,"%d/%d/%d %d/%d/%d %d/%d/%d ",vertex1+1,vt[vertex1]+1,vn[vertex1]+1,
++                                                        other1+1,vt[other1]+1,vn[other1]+1,
++                                                        other2+1,vt[other2]+1,vn[other2]+1);
++      else
++           fprintf(output,"%d %d %d ",vertex1+1,other1+1,other2+1);
++
++
++       for (x = 6; x < num ; x = x+3)
++        {
++
++            /*    Get the next triangle */
++            temp1 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, x);
++            temp2 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, x+1);
++            temp3 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, x+2);
++
++           /*    Error checking */
++            if (!(member(id[0],a,b,c)) || !(member(id[1],a,b,c)) || !(member(vertex2,a,b,c)))
++            {
++                   /*   If we used partial we might have a break in the middle of a strip */
++                   fprintf(output,"\nt ");
++                /*   Find the vertex in the first triangle that is not in the second */
++                vertex1 = Different(a,b,c,temp1->face_id,temp2->face_id,temp3->face_id,&other1,&other2);
++                /*    Find the vertex in the second triangle that is not in the first */
++                vertex2 = Different(temp1->face_id,temp2->face_id,temp3->face_id,a,b,c,&other1,&other2);
++         
++                id[index] = vertex1; index = !index;
++                id[index] = other1; index = !index;
++                id[index] = other2; index = !index;
++            }
++
++            if ((temp1 == NULL ) || (temp2 == NULL) || (temp3 == NULL))
++            {
++                printf("There is an error in the triangle list \n");
++                exit(0);
++            }
++         
++           if ((id[0] == id[1]) || (id[0] == vertex2))
++                continue;
++
++           if ((member(id[index],temp1->face_id,temp2->face_id,temp3->face_id)))
++           {
++                if ((text) && ( vt[id[index]]==0))
++                     cptexture = FALSE;
++                if ((!norm) && (!cptexture))
++                     fprintf(output,"%d ",id[index]+1);
++                else if ((norm) && (!cptexture))
++                     fprintf(output,"%d//%d ",id[index]+1,vn[id[index]]+1);
++                else if ((!norm) && (cptexture))
++                     fprintf(output,"%d/%d ",id[index]+1,vt[id[index]]+1);
++                else
++                     fprintf(output,"%d/%d/%d ",id[index]+1,vt[id[index]]+1,vn[id[index]]+1);
++                index = !index;
++                *swap = *swap + 1;
++           }
++           
++           if ((text) && ( vt[vertex2]==0))
++                cptexture = FALSE;
++            if ((!norm) && (!cptexture))
++                fprintf(output,"\nq %d ",vertex2+1);
++           else if ((norm) && (!cptexture))
++                fprintf(output,"\nq %d//%d ",vertex2+1,vn[vertex2]+1);
++           else if ((!norm) && (cptexture))
++                fprintf(output,"\nq %d/%d ",vertex2+1,vt[vertex2]+1);
++           else
++                fprintf(output,"\nq %d/%d/%d ",vertex2+1,vt[vertex2]+1,vn[vertex2]+1);
++
++            id[index] = vertex2; index = !index;
++
++            /*    Get the next vertex not in common */
++            vertex2 = Different(temp1->face_id,temp2->face_id,temp3->face_id,a,b,c,&other1,&other2);
++            a = temp1->face_id;
++            b = temp2->face_id;
++            c = temp3->face_id;
++        }
++        /*    Do the last vertex */
++       if ((text) && (vt[vertex2]==0))
++       {
++            if (cptexture)
++                 fprintf(output,"\nq ");
++            cptexture = FALSE;
++       }
++       if ((!norm) && (!cptexture))
++            fprintf(output,"%d ",vertex2+1);
++       else if ((norm) && (!cptexture))
++            fprintf(output,"%d//%d ",vertex2+1,vn[vertex2]+1);
++       else if ((!norm) && (cptexture))
++            fprintf(output,"%d/%d ",vertex2+1,vt[vertex2]+1);
++       else
++            fprintf(output,"%d/%d/%d ",vertex2+1,vt[vertex2]+1,vn[vertex2]+1);
++
++        
++       Free_Strips();
++      return (num/3);       
++}
++
++void Output_Tri(int id1, int id2, int id3,FILE *bands, int color1, int color2, int color3,BOOL end)
++{
++     /*   We will save everything into a list, rather than output at once,
++           as was done in the old routine. This way for future modifications
++           we can change the strips later on if we want to.
++     */
++
++    int temp1,temp2,temp3;
++    
++    /*  Make sure we do not have an error */
++    /*    There are degeneracies in some of the files */
++      if ( (id1 == id2) || (id1 == id3) || (id2 == id3))
++      {
++              printf("Degenerate triangle %d %d %d\n",id1,id2,id3);
++              exit(0);
++      }
++     else
++     {
++          Last_Edge(&temp1,&temp2,&temp3,0);
++           Add_Id_Strips(id1,end);
++           Add_Id_Strips(id2,end);
++           Add_Id_Strips(id3,end);
++           Last_Edge(&id1,&id2,&id3,1);
++     }
++}
++
++
++int Polygon_Output(P_ADJACENCIES temp,int face_id,int bucket,
++                                      ListHead *pListHead, BOOL first, int *swaps,
++                         FILE *bands,int color1,int color2,int color3,BOOL global, BOOL end)
++{
++      ListHead *pListFace;
++      PF_FACES face;
++      P_ADJACENCIES pfNode;
++      static BOOL begin = TRUE;
++      int old_face,next_face_id,next_bucket,e1,e2,e3,other1,other2,other3;
++      P_ADJACENCIES lpListInfo; 
++     int ties=0;
++     int  tie = SEQUENTIAL;
++     
++     /* We have a polygon to output, the id is face id, and the number
++         of adjacent polygons to it is bucket. This routine extends the patches from
++        either end to make longer triangle strips.
++      */
++                
++                   
++     /*  Now get the edge */
++     Last_Edge(&e1,&e2,&e3,0);
++    
++     /*  Get the polygon with id face_id */
++      pListFace  = PolFaces[face_id];
++      face = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
++
++     /*  We can't go any more */
++     if ((face->nPolSize == 1) || ((face->nPolSize == 4) && (global))) /* if global, then we are still doing patches */
++     {
++        /*     Remove it from the list so we do not have to waste
++               time visiting it in the future, or winding up in an infinite loop
++               if it is the first on that we are looking at for a possible strip
++        */
++        if (face->nPolSize == 1)
++             RemoveList(pListHead,(PLISTINFO) temp);
++        if (first)
++             return 0;
++        else
++             return (Finished(swaps,bands,global));
++    }
++
++    if (face->nPolSize == 3)
++    {
++              /*      It is already a triangle */
++              if (bucket == 0)
++              {
++                      /*      It is not adjacent to anything so we do not have to
++                                 worry about the order of the sides or updating adjacencies
++                      */
++                          
++                next_face_id = Different(*(face->pPolygon),*(face->pPolygon+1),*(face->pPolygon+2),
++                                            e1,e2,e3,&other1,&other2);  
++                      face->nPolSize = 1;
++                       
++               /* If this is the first triangle in the strip */
++               if ((e2 == 0) && (e3 ==0))
++               {
++                    e2 = other1;
++                    e3 = other2;
++               }
++
++               Output_Tri(e2,e3,next_face_id,bands,color1,color2,color3,end);
++               RemoveList(pListHead,(PLISTINFO) temp);
++               return (Finished(swaps,bands,global));
++          }
++              
++        
++          /*  It is a triangle with adjacencies. This means that we
++                  have to:
++                              1. Update the adjacencies in the list, because we are
++                                      using this polygon and it will be deleted.
++                              2. Get the next polygon.
++              */
++              else
++              {
++                      /*   Return the face_id of the next polygon we will be using,
++                              while updating the adjacency list by decrementing the
++                              adjacencies of everything adjacent to the current triangle.
++                      */
++            
++               next_face_id = Update_Adjacencies(face_id, &next_bucket, &e1,&e2,&ties);
++               /*  Maybe we deleted something in a patch and could not find an adj polygon */
++               if (next_face_id == -1)
++               {
++                       Output_Tri(*(face->pPolygon),*(face->pPolygon+1),*(face->pPolygon+2),bands,color1,
++                                  color2,color3,end);
++                       face->nPolSize = 1;
++                       RemoveList(pListHead,(PLISTINFO) temp);
++                       return (Finished(swaps,bands,global));
++               }
++                
++               old_face = next_face_id;
++                   /*      Find the other vertex to transmit in the triangle */
++                   e3 = Return_Other(face->pPolygon,e1,e2);
++                Last_Edge(&other1,&other2,&other3,0);
++          
++                if ((other2 != 0) && (other3 != 0))
++                {
++                    /*   See which vertex in the output edge is not in the input edge */
++                    if ((e1 != other2) && (e1 != other3))
++                          e3 = e1;
++                    else if ((e2 != other2) && (e2 != other3))
++                           e3 = e2;
++                    else
++                    {
++                          printf("There is an error in the tri with adj\n");
++                          exit(0);
++                    }
++
++                    /*   See which vertex of the input edge is not in the output edge */
++                    if ((other2 != e1) && (other2 != e2))
++                    {
++                          other1 = other2;
++                          other2 = other3;
++                    }
++                    else if ((other3 != e1) && (other3 != e2))
++                          other1 = other3;
++                    else
++                    {
++                          printf("There is an error in getting the tri with adj\n");
++                          exit(0);
++                    }
++                    
++                }
++               else
++               {
++                  /*     We are the first triangle in the strip and the starting edge
++                         has not been set yet
++                  */
++                  /*  Maybe we deleted something in a patch and could not find an adj polygon */
++                  if (next_face_id == -1)
++                  {
++                       Output_Tri(*(face->pPolygon),*(face->pPolygon+1),*(face->pPolygon+2),bands,color1,
++                                  color2,color3,end);
++                       face->nPolSize = 1;
++                       RemoveList(pListHead,(PLISTINFO) temp);
++                       return (Finished(swaps,bands,global));
++                  }
++
++                  other1 = e3;
++                  e3 = e2;
++                  other2 = e1;
++               }
++         
++                /*   At this point the adjacencies have been updated  and we
++                              have the next polygon id 
++                */
++
++               Output_Tri(other1,other2,e3,bands,color1,color2,color3,end);
++               face->nPolSize = 1;
++                   RemoveList(pListHead,(PLISTINFO) temp);
++                   begin = FALSE;
++                
++               /*  Maybe we deleted something in a patch and could not find an adj polygon */
++               if (next_face_id == -1)
++                    return (Finished(swaps,bands,global));
++        
++               if (Done(next_face_id,59,&next_bucket) == NULL)
++                   {
++                           printf("We deleted the next face 4%d\n",next_face_id);
++                           exit(0);
++                }
++
++                      pListHead = array[next_bucket];
++                      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                      if ( pfNode )
++                              pfNode->face_id = next_face_id;
++                      lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                              (int (*)(void *,void *)) (Compare)));
++                      if (lpListInfo == NULL)
++                      {
++                              printf("There is an error finding the next polygon3 %d\n",next_face_id);
++                              exit(0);
++                      }
++                      return (Polygon_Output(lpListInfo,next_face_id,next_bucket,
++                                                   pListHead, FALSE, swaps,bands,color1,color2,color3,global,end));
++
++              }
++      }
++
++      else
++      {
++              /*   It is not a triangle, we have to triangulate it .
++                      Since it is not adjacent to anything we can triangulate it
++                      blindly
++              */
++              if (bucket == 0)
++              {
++                        /*   It is the first polygon in the strip, therefore there is no
++                         input edge to start with.
++                    */
++                    if ((e2 == 0) && (e3 ==0))
++                       Blind_Triangulate(face->nPolSize,face->pPolygon,bands,
++                                                TRUE,1,color1,color2,color3);
++
++                    else
++                       Blind_Triangulate(face->nPolSize,face->pPolygon,bands,
++                                                FALSE,1,color1,color2,color3);
++
++                           RemoveList(pListHead,(PLISTINFO) temp);
++                                     
++                    /*      We will be at the beginning of the next strip. */
++                    face->nPolSize = 1;
++                    return (Finished(swaps,bands,global));
++              }
++
++
++              else
++              {
++                      
++             
++               /*  WHOLE triangulation */
++                /*  It is not a triangle and has adjacencies. 
++                              This means that we have to:
++                              1. Triangulate this polygon, not blindly because
++                                      we have an edge that we want to come out on, that
++                                      is the edge that is adjacent to a polygon with the
++                                      least number of adjacencies. Also we must come in
++                                      on the last seen edge.
++                              2. Update the adjacencies in the list, because we are
++                                      using this polygon .
++                              3. Get the next polygon.
++                      */
++                      /*      Return the face_id of the next polygon we will be using,
++                              while updating the adjacency list by decrementing the
++                              adjacencies of everything adjacent to the current polygon.
++                      */
++                              
++               next_face_id = Update_Adjacencies(face_id, &next_bucket, &e1,&e2,&ties);
++          
++               /*  Maybe we deleted something in a patch and could not find an adj polygon */
++               if (next_face_id == -1)
++               {
++ 
++                    /*   If we are at the first polygon in the strip and there is no input
++                         edge, then begin is TRUE
++                    */
++                    if ((e2 == 0) && (e3 == 0))
++                         Blind_Triangulate(face->nPolSize,face->pPolygon,
++                                                  bands,TRUE,1,color1,color2,color3);
++
++                    else
++                         Blind_Triangulate(face->nPolSize,face->pPolygon,
++                                                  bands,FALSE,1,color1,color2,color3);
++
++                        RemoveList(pListHead,(PLISTINFO) temp);
++                            
++                     /*      We will be at the beginning of the next strip. */
++                    face->nPolSize = 1;
++                    return (Finished(swaps,bands,global));
++               }
++
++               if (Done(next_face_id,59,&next_bucket) == NULL)
++                {
++                          printf("We deleted the next face 6 %d %d\n",next_face_id,face_id);
++                          exit(0);
++                   }
++                      
++                      Non_Blind_Triangulate(face->nPolSize,face->pPolygon, 
++                                               bands,next_face_id,face_id,1,color1,color2,color3);
++                                   
++               RemoveList(pListHead,(PLISTINFO) temp);
++               begin = FALSE;
++               face->nPolSize = 1;
++                      pListHead = array[next_bucket];
++                      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                      if ( pfNode )
++                              pfNode->face_id = next_face_id;
++                      lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                                         (int (*)(void *,void *)) (Compare)));
++                      if (lpListInfo == NULL)
++                   {
++                              printf("There is an error finding the next polygon2 %d %d\n",next_face_id,next_bucket);
++                              exit(0);
++                      }
++                      return (Polygon_Output(lpListInfo,next_face_id,next_bucket,
++                                                   pListHead, FALSE, swaps,bands,color1,color2,color3,global,end));
++              }
++
++      }
++    Last_Edge(&e1,&e2,&e3,0);
++
++}       
++
++
++int Extend_Face(int face_id,int e1,int e2,int *swaps,FILE *bands,
++                int color1,int color2,int color3,int *vert_norm, int normals,
++                int *vert_texture, int texture)
++{
++    int dummy=0,next_bucket;
++    P_ADJACENCIES pfNode,lpListInfo;
++    ListHead *pListHead;
++
++    /*    Try to extend backwards off of the local strip that we just found */
++    
++    vn = vert_norm;
++    vt = vert_texture;
++    norm = normals;
++    text = texture;
++
++    *swaps = 0;
++    /*        Find the face that is adjacent to the edge and is not the
++              current face.
++    */
++    face_id = Find_Face(face_id, e1, e2,&next_bucket);
++    if (face_id == -1)
++          return 0;
++                      
++    pListHead = array[next_bucket];
++    pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++    if ( pfNode )
++              pfNode->face_id = face_id;
++    lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                     (int (*)(void *,void *)) (Compare)));
++    if (lpListInfo == NULL)
++    {
++              printf("There is an error finding the next polygon3 %d\n",face_id);
++              exit(0);
++    }
++    Last_Edge(&dummy,&e1,&e2,1);
++    
++    /*  Find a strip extending from the patch and return the cost */
++    return (Polygon_Output(lpListInfo,face_id,next_bucket,pListHead,TRUE,swaps,bands,color1,color2,color3,TRUE,TRUE));
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d9aed50a93c06dea2845437774972051269cae9f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,26 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: output.h
++-----------------------------------------------------------------------*/
++
++
++#define TRIANGLE 3
++#define MAGNITUDE 1000000
++
++void Output_Tri();
++void Sgi_Test();
++int Polygon_Output();
++void Last_Edge();
++void Extend_Backwards();
++int Finished();
++int Extend_Face();
++void Fast_Reset();
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..48d4da1470481eed089ade3d0e180139d22b16c9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,518 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: outputex.c
++     This file contains routines that are used for various functions in
++     the local algorithm.
++*/
++/*---------------------------------------------------------------------*/
++
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "global.h"
++#include "outputex.h"
++#include "triangulatex.h"
++#include "polverts.h"
++#include "ties.h"
++#include "partial.h"
++#include "sturctsex.h"
++#include "options.h"
++#include "output.h"
++#include "common.h"
++#include "util.h"
++
++
++void Output_TriEx(int id1, int id2, int id3, FILE *output, int next_face, int flag,
++              int where)
++{
++     /*   We will save everything into a list, rather than output at once,
++        as was done in the old routine. This way for future modifications
++        we can change the strips later on if we want to.
++     */
++
++    int swap,temp1,temp2,temp3;
++    static int total=0;
++    static int tri=0;
++    static int strips = 0;
++    static int cost = 0;
++    
++    if (flag == -20)
++    {
++         cost = cost + where+total+tri+strips+strips;
++         printf("We will need to send %d vertices to the renderer\n",cost);
++         total = 0;
++         tri = 0;
++         strips = 0;
++         return ;
++    }
++
++
++    if (flag == -10)
++       /*    We are finished, now is time to output the triangle list
++       */
++    {
++          fprintf(output,"\nt ");
++          tri = tri + Finished(&swap,output,FALSE);
++          total = total + swap;
++          strips++;
++          /*printf("There are %d swaps %d tri %d strips\n",total,tri,strips);*/
++    }
++       
++    else
++    {
++       Last_Edge(&temp1,&temp2,&temp3,0);
++       Add_Id_Strips(id1,where);
++       Add_Id_Strips(id2,where);
++       Add_Id_Strips(id3,where);
++       Last_Edge(&id1,&id2,&id3,1);
++    }
++}
++
++              
++
++
++void Extend_BackwardsEx(int face_id, FILE *output, FILE *strip, int *ties, 
++                    int tie, int triangulate, 
++                    int swaps,int *next_id)
++{
++    /*  We just made a strip, now we are going to see if we can extend
++         backwards from the starting face, which had 2 or more adjacencies
++         to start with.
++    */
++    int bucket,next_face,num,x,y,z,c,d=1,max,f;
++    ListHead *pListFace;
++    PF_FACES face;
++    P_ADJACENCIES temp;
++
++    /*  Get the first triangle that we have saved the the strip data 
++         structure, so we can see if there are any polygons adjacent
++         to this edge or a neighboring one
++    */
++    First_Edge(&x,&y,&z); 
++    
++    pListFace  = PolFaces[face_id];
++    face = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
++
++    num = face->nPolSize;
++
++    /*  Go through the edges to see if there is an adjacency
++         with a vertex in common to the first triangle that was
++         outputted in the strip. (maybe edge was deleted....)
++    */
++    for (c=0; c<num ; c++)
++    {
++         
++      if ( (c != (num-1)) && 
++           (( (*(face->pPolygon+c) == x) && (*(face->pPolygon+c+1) == y)) ||
++              (*(face->pPolygon+c) == y) && (*(face->pPolygon+c+1) == x)))
++      {
++          /*  Input edge is still there see if there is an adjacency */
++          next_face = Find_Face(face_id, x, y, &bucket);
++          if (next_face == -1)
++              /*  Could not find a face adjacent to the edge */
++              break;
++          pListFace = array[bucket];
++          max = NumOnList(pListFace);
++          for (f=0;;f++)
++          {
++                      temp = (P_ADJACENCIES) PeekList(pListFace,LISTHEAD,f);  
++                   if (temp->face_id == next_face)
++                   {
++                        Last_Edge(&z,&y,&x,1);
++                        Polygon_OutputEx(temp,temp->face_id,bucket,pListFace,
++                                                     output,strip,ties,tie,triangulate,swaps,next_id,0);
++                        return;
++                   }
++
++                      if (temp == NULL)
++                      {
++                                      printf("Error in the new buckets%d %d %d\n",bucket,max,0);
++                                      exit(0);
++                      }
++          }
++
++      }
++      else if ( (c == (num -1)) &&
++         ( ((*(face->pPolygon) == x) && (*(face->pPolygon+num-1) == y)) ||
++            (*(face->pPolygon) == y) && (*(face->pPolygon+num-1) == x)))
++      {
++           next_face = Find_Face(face_id,x,y,&bucket);
++           if (next_face == -1)
++              /*  Could not find a face adjacent to the edge */
++                   break;
++              pListFace = array[bucket];
++              max = NumOnList(pListFace);
++              for (f=0;;f++)
++              {
++                      temp = (P_ADJACENCIES) PeekList(pListFace,LISTHEAD,f);
++                   if (temp->face_id == next_face)
++                   {
++                        Last_Edge(&z,&y,&x,1);
++                        Polygon_OutputEx(temp,temp->face_id,bucket,pListFace,
++                                                  output,strip,ties,tie,triangulate,swaps,next_id,0);
++                        return;
++                   }
++
++                      if (temp == NULL)
++                      {
++                                      printf("Error in the new buckets%d %d %d\n",bucket,max,0);
++                                      exit(0);
++                      }
++          }
++      }
++    
++    }
++
++}
++
++void Polygon_OutputEx(P_ADJACENCIES temp,int face_id,int bucket,
++                                      ListHead *pListHead, FILE *output, FILE *strips,
++                                      int *ties, int tie, 
++                                      int triangulate, int swaps,
++                                      int *next_id, int where)
++{
++      ListHead *pListFace;
++      PF_FACES face;
++      P_ADJACENCIES pfNode;
++      static BOOL begin = TRUE;
++      int old_face,next_face_id,next_bucket,e1,e2,e3,other1,other2,other3;
++      P_ADJACENCIES lpListInfo; 
++
++      /*      We have a polygon to output, the id is face id, and the number
++                 of adjacent polygons to it is bucket.
++      */
++
++     Last_Edge(&e1,&e2,&e3,0);
++    
++     /*  Get the polygon with id face_id */
++      pListFace  = PolFaces[face_id];
++      face = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
++
++     if (face->nPolSize == 3)
++      {
++              /*      It is already a triangle */
++              if (bucket == 0)
++              {
++                      /*      It is not adjacent to anything so we do not have to
++                                 worry about the order of the sides or updating adjacencies
++                      */
++                          
++                Last_Edge(&e1,&e2,&e3,0);
++                next_face_id = Different(*(face->pPolygon),*(face->pPolygon+1),*(face->pPolygon+2),
++                                            e1,e2,e3,&other1,&other2);
++                /*  No input edge, at the start */
++                if ((e2 ==0) && (e3 == 0))
++                {
++                        e2 = other1;
++                        e3 = other2;
++                }
++          
++                      Output_TriEx(e2,e3,next_face_id,strips,-1,begin,where);
++                      RemoveList(pListHead,(PLISTINFO) temp);
++                      /*      We will be at the beginning of the next strip. */
++                      begin = TRUE;
++              }
++              /*      It is a triangle with adjacencies. This means that we
++                         have to:
++                              1. Update the adjacencies in the list, because we are
++                                      using this polygon and it will be deleted.
++                              2. Get the next polygon.
++              */
++              else
++              {
++                      /*   Return the face_id of the next polygon we will be using,
++                              while updating the adjacency list by decrementing the
++                              adjacencies of everything adjacent to the current triangle.
++                      */
++            
++               next_face_id = Update_AdjacenciesEx(face_id, &next_bucket, &e1,&e2,ties);
++                      old_face = next_face_id;
++                                      
++              /*  Break the tie,  if there was one */
++                  if (tie != FIRST)
++                              old_face = Get_Next_Face(tie,face_id,triangulate);
++
++              if (next_face_id == -1)
++              {
++                    Polygon_OutputEx(temp,face_id,0,pListHead,output,strips,ties,tie, 
++                          triangulate,swaps,next_id,where);
++                    return;
++              }
++
++
++              /*  We are using a different face */
++              if ((tie != FIRST) && (old_face != next_face_id) && (swaps == ON))
++             {
++                      next_face_id = old_face;
++                      /*  Get the new output edge, since e1 and e2 are for the
++                          original next face that we got.
++                      */
++                  e3 = Get_EdgeEx(&e1,&e2,face->pPolygon,next_face_id,face->nPolSize,0,0);
++              }
++                      
++                 /*      Find the other vertex to transmit in the triangle */
++                 e3 = Return_Other(face->pPolygon,e1,e2);
++              Last_Edge(&other1,&other2,&other3,0);
++          
++              if ((other1 != 0) && (other2 != 0))
++              {
++                     /*   See which vertex in the output edge is not in the input edge */
++                     if ((e1 != other2) && (e1 != other3))
++                             e3 = e1;
++                     else if ((e2 != other2) && (e2 != other3))
++                             e3 = e2;
++                     /* can happen with > 2 polys on an edge  but won't form a good strip so stop
++                       the strip here
++                    */
++                    else
++                     {
++                         Polygon_OutputEx(temp,face_id,0,pListHead,output,strips,ties,tie, 
++                                                 triangulate,swaps,next_id,where);
++                         return;
++             }
++
++             /*   See which vertex of the input edge is not in the output edge */
++             if ((other2 != e1) && (other2 != e2))
++             {
++                        other1 = other2;
++                        other2 = other3;
++             }
++             else if ((other3 != e1) && (other3 != e2))
++                        other1 = other3;
++             else
++             {
++                 /* Degenerate triangle just return*/
++               Output_TriEx(other1,other2,e3,strips,next_face_id,begin,where);
++                      RemoveList(pListHead,(PLISTINFO) temp);
++                      begin = FALSE;
++               return;
++             }
++                    
++         }
++         
++         /*   There was not an input edge, we are the first triangle in a strip */
++         else 
++         {
++             /*   Find the correct order to transmit the triangle, what is
++                     the output edge that we want ?
++             */
++             other1 = e3;
++             e3 = e2;
++             other2 = e1;
++         }
++         
++         /*   At this point the adjacencies have been updated  and we
++                 have the next polygon id 
++         */
++        Output_TriEx(other1,other2,e3,strips,next_face_id,begin,where);
++         RemoveList(pListHead,(PLISTINFO) temp);
++         begin = FALSE;
++
++         if (Done(next_face_id,59,&next_bucket) == NULL)
++              return;
++
++        pListHead = array[next_bucket];
++         pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++         if ( pfNode )
++              pfNode->face_id = next_face_id;
++         lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                               (int (*)(void *,void *)) (Compare)));
++         if (lpListInfo == NULL)
++         {
++                              printf("There is an error finding the next polygon3 %d\n",next_face_id);
++                              exit(0);
++         }
++         Polygon_OutputEx(lpListInfo,next_face_id,next_bucket,
++                                      pListHead, output, strips,ties,tie,triangulate,swaps,next_id,where);
++
++      }
++}
++
++      else
++      {
++              /*      It is not a triangle, we have to triangulate it .
++                         Since it is not adjacent to anything we can triangulate it
++                         blindly
++              */
++              if (bucket == 0)
++              {
++                      /*  Check to see if there is not an input edge */
++                Last_Edge(&other1,&other2,&other3,0);
++                if ((other1 == 0) && (other2 ==0))
++                        Blind_TriangulateEx(face->nPolSize,face->pPolygon, strips,
++                                                        output,TRUE,where);
++                else
++                        Blind_TriangulateEx(face->nPolSize,face->pPolygon,strips,
++                                               output,FALSE,where);
++
++                      RemoveList(pListHead,(PLISTINFO) temp);
++                      /*      We will be at the beginning of the next strip. */
++                      begin = TRUE;
++              }
++
++               /*  If we have specified PARTIAL triangulation then
++                      we will go to special routines that will break the
++                      polygon and update the data structure. Else everything
++                      below will simply triangulate the whole polygon 
++              */
++              else if (triangulate == PARTIAL)
++              {
++          
++                /*  Return the face_id of the next polygon we will be using,
++                      */
++                      next_face_id = Min_Face_AdjEx(face_id,&next_bucket,ties);
++
++              
++                      /* Don't do it partially, because we can go inside and get
++                      less adjacencies, for a quad we can do the whole thing.
++                */
++                if ((face_id == next_face_id) && (face->nPolSize == 4)  && (swaps == ON))
++                {
++                    next_face_id = Update_AdjacenciesEx(face_id, &next_bucket, &e1,&e2,ties);
++                        if (next_face_id == -1)
++                        {
++                             /*  There is no sequential face to go to, end the strip */
++                             Polygon_OutputEx(temp,face_id,0,pListHead,output,strips,ties,tie, 
++                                                       triangulate,swaps,next_id,where);
++                             return;
++                        }
++               
++                    /* Break the tie,  if there was one */
++                        if (tie != FIRST)
++                                next_face_id = Get_Next_Face(tie,face_id,triangulate);
++                        Non_Blind_TriangulateEx(face->nPolSize,face->pPolygon, strips,
++                                                            output,next_face_id,face_id,where);
++                           RemoveList(pListHead,(PLISTINFO) temp);
++                }
++         
++                /*   Was not a quad but we still do not want to do it partially for
++                        now, since we want to only do one triangle at a time
++                */
++                else if ((face_id == next_face_id) && (swaps == ON))
++                     Inside_Polygon(face->nPolSize,face->pPolygon,strips,output,
++                                       next_face_id,face_id,next_id,pListHead,temp,where);
++
++                else
++                {
++                                       if ((tie != FIRST) && (swaps == ON))
++                                               next_face_id = Get_Next_Face(tie,face_id,triangulate);
++                                       Partial_Triangulate(face->nPolSize,face->pPolygon,strips,
++                                                              output,next_face_id,face_id,next_id,pListHead,temp,where);
++                                      /*    Check the next bucket again ,maybe it changed 
++                                               We calculated one less, but that might not be the case
++                                      */
++               }
++
++                      if (Done(next_face_id,59,&next_bucket) == NULL)
++                      {
++                      /*  Check to see if there is not an input edge */
++                     Last_Edge(&other1,&other2,&other3,0);
++                     if ((other1 == 0) && (other2 ==0))
++                             Blind_TriangulateEx(face->nPolSize,face->pPolygon, strips,
++                                                             output,TRUE,where);
++                     else
++                             Blind_TriangulateEx(face->nPolSize,face->pPolygon,strips,
++                                                    output,FALSE,where);
++                    
++                    if (Done(face_id,59,&bucket) != NULL)
++                    {
++                         pListHead = array[bucket];
++                                pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                                if ( pfNode )
++                                        pfNode->face_id = face_id;
++                                lpListInfo = (P_ADJACENCIES) (SearchList(array[bucket], pfNode,
++                                                (int (*)(void *,void *)) (Compare)));
++                                RemoveList(pListHead,(PLISTINFO)lpListInfo);
++                    }
++                    begin = TRUE;
++                              return;
++                      }
++                      
++                      begin = FALSE;
++                      pListHead = array[next_bucket];
++                      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                      if ( pfNode )
++                              pfNode->face_id = next_face_id;
++                      lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                                      (int (*)(void *,void *)) (Compare)));
++                      if (lpListInfo == NULL)
++                      {
++                              printf("There is an error finding the next polygon1 %d %d\n",next_face_id,next_bucket);
++                              exit(0);
++                      }
++                      Polygon_OutputEx(lpListInfo,next_face_id,next_bucket,
++                                          pListHead, output, strips,ties,tie,triangulate,swaps,next_id,where);
++              }
++
++          
++              else
++              {
++                      /*  WHOLE triangulation */
++                /*  It is not a triangle and has adjacencies. 
++                              This means that we have to:
++                              1. TriangulateEx this polygon, not blindly because
++                                      we have an edge that we want to come out on, that
++                                      is the edge that is adjacent to a polygon with the
++                                      least number of adjacencies. Also we must come in
++                                      on the last seen edge.
++                              2. Update the adjacencies in the list, because we are
++                                      using this polygon .
++                              3. Get the next polygon.
++                      */
++                      /*   Return the face_id of the next polygon we will be using,
++                              while updating the adjacency list by decrementing the
++                              adjacencies of everything adjacent to the current polygon.
++                      */
++                              
++               next_face_id = Update_AdjacenciesEx(face_id, &next_bucket, &e1,&e2,ties);
++
++               if (Done(next_face_id,59,&next_bucket) == NULL)
++               {
++                    Polygon_OutputEx(temp,face_id,0,pListHead,output,strips,ties,tie, 
++                                            triangulate,swaps,next_id,where);
++                    /*    Because maybe there was more than 2 polygons on the edge */
++                    return;
++                   }
++
++                   /*      Break the tie,  if there was one */
++                      else if (tie != FIRST)
++                              next_face_id = Get_Next_Face(tie,face_id,triangulate);
++                              
++                      Non_Blind_TriangulateEx(face->nPolSize,face->pPolygon, strips,
++                                                       output,next_face_id,face_id,where);
++                      RemoveList(pListHead,(PLISTINFO) temp);
++                      begin = FALSE;
++                      pListHead = array[next_bucket];
++                      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                      if ( pfNode )
++                              pfNode->face_id = next_face_id;
++                      lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                                         (int (*)(void *,void *)) (Compare)));
++                      if (lpListInfo == NULL)
++                   {
++                                      printf("There is an error finding the next polygon2 %d %d\n",next_face_id,next_bucket);
++                                      exit(0);
++               }
++                      Polygon_OutputEx(lpListInfo,next_face_id,next_bucket,
++                                             pListHead, output, strips,ties,tie,triangulate,swaps,next_id,where);
++              }
++
++      }
++    Last_Edge(&e1,&e2,&e3,0);
++
++}       
++
++
++
++      
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..68cff0ca29fda8f5087e32e63035174199a8b983
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,23 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: outputex.h
++-----------------------------------------------------------------------*/
++
++
++#define TRIANGLE 3
++#define MAGNITUDE 1000000
++
++void Output_TriEx();
++void Sgi_Test();
++void Polygon_OutputEx();
++void Extend_BackwardsEx();
++void FinishedEx();
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9afb03c191ec939ff39e12cefe1a2fd783bbcae8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,665 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: partial.c
++     This file contains routines that are used partial triangulation of polygons
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include "global.h"
++#include "outputex.h"
++#include "polvertsex.h"
++#include "triangulatex.h"
++#include "sturctsex.h"
++#include "polverts.h"
++#include "common.h"
++#include "util.h"
++
++void P_Triangulate_Quad(int out_edge1,int out_edge2,int in_edge1,
++                                        int in_edge2,int size,int *index,
++                                        FILE *output,FILE *fp,int reversed,int face_id,
++                                        int *next_id,ListHead *pListHead, 
++                                        P_ADJACENCIES temp,
++                      int where)
++{
++    int vertex4,vertex5,dummy=60;
++      
++    /*        This routine will nonblindly triangulate a quad, meaning
++              that there is a definite input and a definite output
++              edge that we must adhere to. Reversed will tell the orientation
++              of the input edge. (Reversed is -1 is we do not have an input
++              edge, in other words we are at the beginning of a strip.)
++              Out_edge* is the output edge, and in_edge* is the input edge. 
++              Index are the edges of the polygon
++              and size is the size of the polygon. Begin is whether we are
++              at the start of a new strip.
++              Note that we will not necessarily triangulate the whole quad;
++              maybe we will do half and leave the other half (a triangle)
++              for later.
++      */
++      
++
++    /*        If we do not have an input edge, then we can make our input
++              edge whatever we like, therefore it will be easier to come
++              out on the output edge. In this case the whole quad is done.
++      */
++      if (reversed == -1)
++      {
++              vertex4 = AdjacentEx(out_edge1,out_edge2,index,size);
++              vertex5 = Get_Other_Vertex(vertex4,out_edge1,out_edge2,index);
++              Output_TriEx(vertex5,vertex4,out_edge1,output,-1,-1,where);
++              Output_TriEx(vertex4,out_edge1,out_edge2,output,-1,-1,where);
++              dummy = Update_AdjacenciesEx(face_id, &dummy, &dummy,&dummy,&dummy);
++              RemoveList(pListHead,(PLISTINFO) temp);
++              return;
++      }
++      
++      /*      These are the 5 cases that we can have for the output edge */
++      
++      /*  Are they consecutive so that we form a triangle to
++              peel off, but cannot use the whole quad?
++      */
++
++      if (in_edge2 == out_edge1) 
++      {
++              /*      Output the triangle that comes out the correct
++                      edge. Save the other half for later.
++              */
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge2,index);
++          Output_TriEx(in_edge1,in_edge2,out_edge2,output,-1,-1,where);
++              /*      Now we have a triangle used, and a triangle that is
++                      left for later.
++              */
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,
++                              face_id,&dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,in_edge2,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              /*      Put the new face in the proper bucket of adjacencies 
++                      There are 2 edges that need to be checked for the triangle
++                      that was just outputted. For the output edge we definitely
++                      will be decreasing the adjacency, but we must check for the
++                      input edge.
++              */
++
++              dummy = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp,FALSE);
++              dummy = Change_FaceEx(face_id,in_edge2,out_edge2,pListHead,temp,TRUE);
++              
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the triangle as the new face 
++              */
++              New_Face(face_id,in_edge1,out_edge2,vertex4);
++              return;                                                                   
++      }
++      else if (in_edge1 == out_edge1)
++      {
++              /*      We want to output the first triangle (whose output
++                      edge is not the one that we want.
++                      We have to find the vertex that we need, which is
++                      the other vertex which we do not have.
++              */                                              
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge2,index);
++              Output_TriEx(in_edge2,in_edge1,out_edge2,output,-1,-1,where);
++              /*      Now we have a triangle used, and a triangle that is
++                      left for later.
++              */
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              dummy = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp,FALSE);
++              dummy = Change_FaceEx(face_id,in_edge1,out_edge2,pListHead,temp,TRUE);
++              
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the triangle as the new face 
++              */
++              New_Face(face_id,in_edge2,out_edge2,vertex4);
++              return;
++      }
++      
++      /*      Consecutive cases again, but with the output edge reversed */
++      else if (in_edge1 == out_edge2)
++      {
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
++              Output_TriEx(in_edge2,in_edge1,out_edge1,output,-1,-1,where);
++              /*      Now we have a triangle used, and a triangle that is
++                      left for later.
++              */
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              dummy = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp,FALSE);
++              dummy = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp,TRUE);
++              
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the triangle as the new face 
++              */
++              New_Face(face_id,in_edge2,out_edge1,vertex4);
++          return;
++      }
++      else if (in_edge2 == out_edge2)
++      {
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
++              Output_TriEx(in_edge1,in_edge2,out_edge1,output,-1,-1,where);
++              /*      Now we have a triangle used, and a triangle that is
++                      left for later.
++              */
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              dummy = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp,FALSE);
++              dummy = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp,TRUE);
++              
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the triangle as the new face 
++              */
++              New_Face(face_id,in_edge1,out_edge1,vertex4);
++              return;
++      }
++
++      /*      The final case is where we want to come out the opposite
++              edge.
++      */
++      else
++      {
++        if( ((!reversed) && (out_edge1 == (AdjacentEx(in_edge1,in_edge2,index,size)))) ||
++                    ((reversed) && (out_edge2 == (AdjacentEx(in_edge2,in_edge1,index,size)))))
++              {
++                      /*      We need to know the orientation of the input
++                              edge, so we know which way to put the diagonal.
++                And also the output edge, so that we triangulate
++                correctly. Does not need partial.
++             */
++                      Output_TriEx(in_edge1,in_edge2,out_edge2,output,-1,-1,where);
++                      Output_TriEx(in_edge2,out_edge2,out_edge1,output,-1,-1,where);
++                      dummy = Update_AdjacenciesEx(face_id, &dummy, &dummy,&dummy,&dummy);
++                      RemoveList(pListHead,(PLISTINFO) temp);
++              }
++              else
++              {
++                      /*      Input and output orientation was reversed, so diagonal will
++                                      be reversed from above.
++                      */
++                      Output_TriEx(in_edge1,in_edge2,out_edge1,output,-1,-1,where);
++                      Output_TriEx(in_edge2,out_edge1,out_edge2,output,-1,-1,where);
++                      dummy = Update_AdjacenciesEx(face_id, &dummy, &dummy,&dummy,&dummy);
++                      RemoveList(pListHead,(PLISTINFO) temp);
++              }
++              return;
++      }
++}
++
++void P_Triangulate_Polygon(int out_edge1,int out_edge2,int in_edge1,
++                                                 int in_edge2,int size,
++                                                int *index,FILE *output,FILE *fp,
++                                                int reversed,int face_id,int *next_id,
++                                                ListHead *pListHead, P_ADJACENCIES temp2,
++                          int where)
++{
++      /*      We have a polygon greater than 4 sides, which we wish
++              to partially triangulate
++      */
++      int next_bucket,vertex4,dummy = 60;
++      int *temp;
++      P_ADJACENCIES pfNode;
++
++              
++    /*        Since we are calling this recursively, we have to check whether         
++              we are down to the case of the quad.
++      */
++      if (size == 4)
++      {
++              P_Triangulate_Quad(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                                      index,output,fp,reversed,face_id,next_id,
++                                                      pListHead,temp2,where);
++              return;
++      }
++      
++      /*      We do not have a specified input edge, and therefore we
++              can make it anything we like, as long as we still come out 
++              the output edge that we want.
++      */
++      if (reversed  == -1)
++      {
++              /*      Get the vertex for the last triangle, which is
++                      the one coming out the output edge, before we do
++                      any deletions to the list. We will be doing this
++                      bottom up.
++              */
++              vertex4 = AdjacentEx(out_edge1,out_edge2,index,size);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_ListEx(out_edge2,index,size);
++              /*      We do not have to partially triangulate, since
++                      we will do the whole thing, so use the whole routine
++              */
++              Triangulate_PolygonEx(vertex4,out_edge1,in_edge2,
++                                               vertex4,size-1,index,output,fp,reversed,face_id,
++                                               next_id,pListHead,temp2,where);
++              memcpy(index,temp,sizeof(int)*size);
++              /*      Lastly do the triangle that comes out the output
++                      edge.
++              */
++              Output_TriEx(vertex4,out_edge1,out_edge2,output,-1,-1,where);
++              /*      We were able to do the whole polygon, now we
++                      can delete the whole thing from our data structure.
++              */
++              dummy = Update_AdjacenciesEx(face_id, &dummy, &dummy,&dummy,&dummy);
++              RemoveList(pListHead,(PLISTINFO) temp2);
++              return;
++      }         
++
++      /*      These are the 5 cases that we can have for the output edge */
++      
++      /*  Are they consecutive so that we form a triangle to
++              peel off that comes out the correct output edge, 
++              but we cannot use the whole polygon?
++      */
++      if (in_edge2 == out_edge1) 
++      {
++              Output_TriEx(in_edge1,out_edge1,out_edge2,output,-1,-1,where);
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++              next_bucket = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp2,TRUE);
++              
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++          Delete_From_ListEx(in_edge2,index,size);
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the polygon minus the triangle 
++                      as the new face, here we will be decrementing the size
++                      by one.
++              */
++              New_Size_Face(face_id);
++              return;
++      }
++
++      /*      Next case is where it is again consecutive, but the triangle
++              formed by the consecutive edges do not come out of the
++              correct output edge. (the input edge will be reversed in
++              the next triangle)
++      */
++      else if (in_edge1 == out_edge1)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              Output_TriEx(in_edge2,in_edge1,out_edge2,output,-1,-1,where);
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++              next_bucket = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp2,TRUE);
++              
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++          Delete_From_ListEx(in_edge1,index,size);
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the polygon minus the triangle 
++                      as the new face, here we will be decrementing the size
++                      by one.
++              */
++              New_Size_Face(face_id);
++              return;
++      }
++      
++      /*      Consecutive cases again, but with the output edge reversed */
++      else if (in_edge1 == out_edge2)
++      {
++              Output_TriEx(in_edge2,in_edge1,out_edge1,output,-1,-1,where);
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge1,out_edge2,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++              next_bucket = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp2,TRUE);
++              
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++        Delete_From_ListEx(in_edge1,index,size);
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the polygon minus the triangle 
++                      as the new face, here we will be decrementing the size
++                      by one.
++              */
++              New_Size_Face(face_id);
++              return;
++      }
++      else if (in_edge2 == out_edge2)
++      {
++              Output_TriEx(in_edge1,in_edge2,out_edge1,output,-1,-1,where);
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++              next_bucket = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp2,TRUE);
++              
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++          Delete_From_ListEx(in_edge2,index,size);
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the polygon minus the triangle 
++                      as the new face, here we will be decrementing the size
++                      by one.
++              */
++              New_Size_Face(face_id);
++              return;
++      }
++
++      /*      Else the edge is not consecutive, and it is sufficiently
++              far away, for us not to make a conclusion at this time.
++              So we can take off a triangle and recursively call this
++              function.
++      */
++      else
++      {
++          if (!reversed)
++              {
++                      vertex4 = AdjacentEx(in_edge2,in_edge1,index,size);
++                      Output_TriEx(in_edge1,in_edge2,vertex4,output,-1,-1,where);
++                      
++                      /*      Now delete the adjacencies by one for all the faces
++                              that are adjacent to the triangle that we just outputted.
++                      */
++                      Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++                      Delete_AdjEx(in_edge1,vertex4,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++                      
++                      /*      Put the new face in the proper bucket of adjacencies */
++                      next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++                      next_bucket = Change_FaceEx(face_id,in_edge1,vertex4,pListHead,temp2,FALSE);
++                      
++                      /*      Create a new edgelist without the triangle that
++                              was just outputted.
++                      */
++                      Delete_From_ListEx(in_edge1,index,size);
++                      /*      Update the face data structure, by deleting the old
++                              face and putting in the polygon minus the triangle 
++                              as the new face, here we will be decrementing the size
++                              by one.
++                      */
++                      New_Size_Face(face_id);
++
++                      /*      Save the info for the new bucket, we will need it on
++                              the next pass for the variables, pListHead and temp 
++                      */
++                      pListHead = array[next_bucket];
++                      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                      if ( pfNode )
++                              pfNode->face_id = face_id;
++                      temp2 = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                              (int (*)(void *,void *)) (Compare)));
++                      if (temp2 == NULL)
++                      {
++                              printf("There is an error finding the next polygon10\n",next_bucket,face_id);
++                              exit(0);
++                      }
++
++                      P_Triangulate_Polygon(out_edge1,out_edge2,in_edge2,
++                                               vertex4,size-1,index,output,fp,!reversed,
++                                               face_id,next_id,pListHead,temp2,where);
++              }
++              else
++              {
++                      vertex4 = AdjacentEx(in_edge1,in_edge2,index,size);
++                      Output_TriEx(in_edge2,in_edge1,vertex4,output,-1,-1,where);
++
++                      /*      Now delete the adjacencies by one for all the faces
++                              that are adjacent to the triangle that we just outputted.
++                      */
++                      Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++                      Delete_AdjEx(in_edge2,vertex4,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++                      
++                      /*      Put the new face in the proper bucket of adjacencies */
++                      next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++                      next_bucket = Change_FaceEx(face_id,in_edge2,vertex4,pListHead,temp2,FALSE);
++                      
++                      /*      Create a new edgelist without the triangle that
++                              was just outputted.
++                      */
++                      Delete_From_ListEx(in_edge2,index,size);
++                      
++                      /*      Update the face data structure, by deleting the old
++                              face and putting in the polygon minus the triangle 
++                              as the new face, here we will be decrementing the size
++                              by one.
++                      */
++                      New_Size_Face(face_id);
++                      
++                      /*      Save the info for the new bucket, we will need it on
++                              the next pass for the variables, pListHead and temp 
++                      */
++                      pListHead = array[next_bucket];
++                      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                      if ( pfNode )
++                              pfNode->face_id = face_id;
++                      temp2 = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                              (int (*)(void *,void *)) (Compare)));
++                      if (temp2 == NULL)
++                      {
++                              printf("There is an error finding the next polygon11 %d %d\n",face_id,next_bucket);
++                              exit(0);
++                      }
++
++                      P_Triangulate_Polygon(out_edge1,out_edge2,vertex4,
++                                                     in_edge1,size-1,index,output,fp,!reversed,
++                                                     face_id,next_id,pListHead,temp2,where);
++              }
++              return;
++      }
++}
++
++void P_Triangulate(int out_edge1,int out_edge2,int in_edge1,
++                               int in_edge2,int size,int *index,
++                               FILE *fp,FILE *output,int reversed,int face_id,
++                               int *next_id,ListHead *pListHead, 
++                               P_ADJACENCIES temp,int where)
++{
++              
++      if (size == 4)
++              P_Triangulate_Quad(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                    index,fp,output,reversed,face_id,next_id,pListHead, temp,where);
++      else
++              P_Triangulate_Polygon(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                       index,fp,output,reversed,face_id,next_id,pListHead,temp,where);
++}
++
++ void Partial_Triangulate(int size,int *index, FILE *fp,
++                                               FILE *output,int next_face_id,int face_id,
++                                               int *next_id,ListHead *pListHead,
++                                               P_ADJACENCIES temp, int where)
++{
++      int id1,id2,id3;
++      int nedge1,nedge2;
++      int reversed;
++
++      /*      We have a polygon that has to be triangulated and we cannot
++              do it blindly, ie we will try to come out on the edge that
++              has the least number of adjacencies, But also we do not
++              want to triangulate the whole polygon now, so that means 
++              we will output the least number of triangles that we can
++              and then update the data structures, with the polygon
++              that is left after we are done.
++      */
++      Last_Edge(&id1,&id2,&id3,0);
++      
++      /*      Find the edge that is adjacent to the new face ,
++              also return whether the orientation is reversed in the
++              face of the input edge, which is id2 and id3.
++      */
++      reversed = Get_EdgeEx(&nedge1,&nedge2,index,next_face_id,size,id2,id3);
++      
++      /*   Input edge and output edge can be the same if there are more than
++          one polygon on an edge 
++     */
++     if ( ((nedge1 == id2) && (nedge2 == id3)) ||
++          ((nedge1 == id3) && (nedge2 == id2)) )
++          /*   Set output edge arbitrarily but when come out of here the
++               next face will be on the old output edge (identical one)
++          */
++          nedge2 = Return_Other(index,id2,id3);
++
++          /*  Do the triangulation */ 
++      P_Triangulate(nedge1,nedge2,id2,id3,size,index,fp,output,reversed,
++                       face_id,next_id,pListHead,temp,where);
++}
++
++ void Input_Edge(int face_id, int *index, int size, int in_edge1, int in_edge2, 
++                FILE *fp, FILE *output,ListHead *pListHead, P_ADJACENCIES temp2,
++                int where)
++ {
++     /* The polygon had an input edge, specified by input1 and input2 */
++    
++     int output1,next_bucket;
++     int vertex4, vertex5,dummy=60;
++
++     output1 = Get_Output_Edge(face_id,size,index,in_edge1,in_edge2);
++      vertex5 = AdjacentEx(in_edge2,in_edge1,index,size); 
++     vertex4 = AdjacentEx(in_edge1,in_edge2,index,size);
++
++     if (vertex4 == output1)
++     {
++              Output_TriEx(in_edge2,in_edge1,output1,output,-1,-1,where);
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(in_edge2,output1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              /*      Put the new face in the proper bucket of adjacencies */
++              next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++              next_bucket = Change_FaceEx(face_id,in_edge2,output1,pListHead,temp2,FALSE);
++              
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++          Delete_From_ListEx(in_edge2,index,size);
++
++    } 
++    else if (vertex5 == output1)
++    {
++          Output_TriEx(in_edge1,in_edge2,vertex5,output,-1,-1,where);
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(in_edge1,vertex5,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              /*      Put the new face in the proper bucket of adjacencies */
++              next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++              next_bucket = Change_FaceEx(face_id,in_edge1,vertex5,pListHead,temp2,FALSE);
++              
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++          Delete_From_ListEx(in_edge1,index,size);
++    }
++              
++    /*        Update the face data structure, by deleting the old
++              face and putting in the polygon minus the triangle 
++              as the new face, here we will be decrementing the size
++              by one.
++    */
++    New_Size_Face(face_id);
++    return;
++ }
++ 
++ void Inside_Polygon(int size,int *index,FILE *fp,FILE *output,
++                   int next_face_id,int face_id,int *next_id,
++                   ListHead *pListHead,P_ADJACENCIES temp, int where)
++ {
++     /* We know that we have a polygon that is greater than 4 sides, and
++        that it is better for us to go inside the polygon for the next
++        one, since inside will have less adjacencies than going outside.
++        So, we are not doing partial for a part of the polygon.
++      */
++    int id1,id2,id3;
++    int new1,new2;
++
++    Last_Edge(&id1,&id2,&id3,0);
++
++    /*  See if the input edge existed in the polygon, that will help us */
++      if (Exist(face_id,id2,id3))
++        Input_Edge(face_id,index,size,id2,id3,output,fp,pListHead,temp,where);
++    else
++    {
++        /*  Make one of the input edges 
++            We will choose it by trying to get an edge that has something
++            in common with the last triangle, or by getting the edge that
++            is adjacent to the least number of thigs, with preference given
++            to the first option
++        */
++               
++        Get_Input_Edge(index,id1,id2,id3,&new1,&new2,size,face_id);
++        Input_Edge(face_id,index,size,new1,new2,output,fp,pListHead,temp,where);
++    }
++ }
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c9a9439c8a2444a1db9ff6d110d755e26b5965d7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: partial.h
++-----------------------------------------------------------------------*/
++
++void Partial_Triangulate();
++void Inside_Polygon();
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..79ece86dbc202f277c7692386d52ad42ccebac14
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,87 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: polverts.h
++-----------------------------------------------------------------------*/
++
++#include "queue.h"
++#include <malloc.h>
++
++
++/*      external functions */
++void Find_Adjacencies();
++void Test_Adj_Struct();
++void Test_SGI_Struct();
++void Write_Edges();
++void Build_SGI_Table();
++void Save_Walks();
++void Find_Bands();
++void Save_Rest();
++void Assign_Walk();
++void Save_Walks();
++      
++typedef struct adjacencies
++{
++      Node ListNode;
++      int face_id;
++} ADJACENCIES,*P_ADJACENCIES;
++
++typedef struct FVerts
++{
++      Node ListNode;
++      int *pPolygon;
++      int nPolSize;
++      int nId;
++} F_VERTS, *PF_VERTS;
++
++/*Every time we need to use this, cast it ( ListInfo*)*/
++
++typedef struct FEdges
++{
++      Node ListNode;
++      int edge[3];
++}F_EDGES,*PF_EDGES;
++
++typedef struct FFaces
++{
++      Node ListNode;
++      int *pPolygon;
++      int *pNorms;
++    int     seen;
++    int seen2;
++    int seen3;
++      int nPolSize;
++      F_EDGES **VertandId;
++      int *marked;
++              int *walked;
++} F_FACES,*PF_FACES;
++      
++
++typedef struct Strips
++{
++      Node ListNode;
++      int face_id;
++} Strips,*P_STRIPS;
++
++
++     struct vert_added
++     {
++          int num;
++          int *normal;
++     };
++
++
++/*      Globals */
++ListHead **PolVerts;
++ListHead **PolFaces;
++ListHead **PolEdges;
++ListHead *array[60];
++int     id_array[60];
++ListHead *strips[1];
++ListHead *all_strips[100000]; /*  Assume max 100000 strips */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8e05a7dd30c63271a6bb36a088d123fa4287f90e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,34 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: polvertsex.h
++-----------------------------------------------------------------------*/
++
++#include "queue.h"
++#include <malloc.h>
++
++
++/*      external functions */
++void Start_Vert_Struct();
++void Start_Face_StructEx();
++void Start_Edge_StructEx();
++void AddNewNode();
++void AddNewFaceEx();      
++void Find_AdjacenciesEx();
++void Test_Adj_Struct();
++void Test_SGI_Struct();
++void Write_Edges();
++void End_Verts_Struct();
++void End_Face_StructEx();
++void End_Edge_StructEx();
++void Build_SGI_TableEx();
++void Add_AdjEdgeEx();
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..29d5e9de099d5d3f2fcb3bd9b49f4abf6b4b1749
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,226 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: queue.c
++     This file contains the routines used in the data structures lists, which
++     are queues.
++*/
++/*---------------------------------------------------------------------*/
++
++ #include "queue.h"
++ 
++
++
++/*----------------------------------------------------------------------------
++ * InitList:
++ */
++BOOL  InitList  (PLISTHEAD LHead)
++ 
++{
++     if (LHead == NULL) return(FALSE);
++
++     LHead->LHeaders[LISTHEAD] = LHead->LHeaders[LISTTAIL] = NULL;
++     LHead->NumList = 0;
++     return(TRUE);
++}
++
++/*----------------------------------------------------------------------------
++ * AddHead:
++ */
++BOOL  AddHead(PLISTHEAD LHead, PLISTINFO LInfo)
++{
++     if (LHead == NULL || LInfo == NULL)
++          return(FALSE);
++     if (EMPTYLIST(LHead))
++          LHead->LHeaders[LISTTAIL] = LInfo;
++     else LHead->LHeaders[LISTHEAD]->ListNode.Previous = (void  *) LInfo;
++
++     LInfo->ListNode.Next = (void  *) LHead->LHeaders[LISTHEAD];
++     LHead->LHeaders[LISTHEAD] = LInfo;
++     LInfo->ListNode.Previous = NULL;
++     LHead->NumList++;
++     return(TRUE);
++}
++
++/*----------------------------------------------------------------------------
++ * AddTail
++ */
++BOOL  AddTail(PLISTHEAD LHead, PLISTINFO LInfo)
++{
++     if (LHead == NULL || LInfo == NULL)
++          return(FALSE);
++     if (EMPTYLIST(LHead))
++          LHead->LHeaders[LISTHEAD] = LInfo;
++     else LHead->LHeaders[LISTTAIL]->ListNode.Next = (void *) LInfo;
++
++     LInfo->ListNode.Previous = (void  *) LHead->LHeaders[LISTTAIL];
++     LHead->LHeaders[LISTTAIL] = LInfo;
++     LInfo->ListNode.Next = NULL;
++     LHead->NumList++;
++     return(TRUE);
++}
++
++
++BOOL  InsertNode( PLISTHEAD LHead, int nPos, PLISTINFO LInfo )
++{
++PLISTINFO LAddNode;
++
++     if ( LHead == NULL || LInfo == NULL || nPos > NumOnList( LHead ) ) 
++          return( FALSE );
++
++     if ( nPos == 0 )
++          AddHead( LHead, LInfo );
++     else if ( nPos == NumOnList( LHead ) ) 
++          AddTail( LHead, LInfo );
++     else
++     {
++          if ( (LAddNode = PeekList( LHead, LISTHEAD, nPos - 1 )) == NULL )
++               return( FALSE );
++          
++          ((PLISTINFO)LAddNode->ListNode.Next)->ListNode.Previous = LInfo;
++          LInfo->ListNode.Next      = LAddNode->ListNode.Next;
++          LInfo->ListNode.Previous  = LAddNode;
++          LAddNode->ListNode.Next   = LInfo;
++          
++          LHead->NumList++;
++     }
++
++     return( TRUE );
++}
++
++
++
++
++/*----------------------------------------------------------------------------
++ *  RemHead:
++ */
++PLISTINFO  RemHead(PLISTHEAD LHead)
++{
++     PLISTINFO t, t1;
++
++     if ( LHead == NULL || EMPTYLIST(LHead) )
++          return(NULL);
++
++     t = LHead->LHeaders[LISTHEAD];
++     LHead->LHeaders[LISTHEAD] = (PLISTINFO) t->ListNode.Next;
++
++     if (LHead->LHeaders[LISTHEAD] != NULL)
++     {
++          t1 = (PLISTINFO) t->ListNode.Next;
++          t1->ListNode.Previous = NULL;
++     }
++     else
++          LHead->LHeaders[LISTTAIL] = NULL;
++
++     LHead->NumList--;
++
++     return(t);
++}
++
++/*----------------------------------------------------------------------------
++ *  RemTail:
++ */
++PLISTINFO  RemTail(PLISTHEAD   LHead)
++{
++     PLISTINFO   t, t1;
++
++     if ( LHead == NULL || EMPTYLIST(LHead) )
++          return(NULL);
++
++     t = LHead->LHeaders[LISTTAIL];
++     LHead->LHeaders[LISTTAIL] = (PLISTINFO) t->ListNode.Previous;
++     if (LHead->LHeaders[LISTTAIL] != NULL)
++     {
++          t1 = (PLISTINFO) t->ListNode.Previous;
++          t1->ListNode.Next = NULL;
++     }
++     else
++          LHead->LHeaders[LISTHEAD] = NULL;
++
++     LHead->NumList--;
++     return(t);
++}
++
++/*----------------------------------------------------------------------------
++ * PeekList:
++ */
++PLISTINFO  PeekList(PLISTHEAD LHead, int wch, int index )
++{
++     PLISTINFO  t;
++
++     if (LHead == NULL)
++          return(NULL);
++     if ( (t = LHead->LHeaders[wch]) == NULL )
++          return(NULL);
++
++     for (; t != NULL && index > 0; index-- )
++          t = (wch == LISTHEAD)  ? (PLISTINFO) t->ListNode.Next  :
++                                   (PLISTINFO) t->ListNode.Previous;
++     return(t);
++}
++
++
++/*----------------------------------------------------------------------------
++ * RemoveList:
++ */
++PLISTINFO   RemoveList( PLISTHEAD LHead, PLISTINFO LInfo )
++{
++     PLISTINFO     t, t1;
++
++     t = LInfo;
++     if (LHead == NULL)
++          return(NULL);
++     if (LHead->LHeaders[LISTHEAD] == t)
++          t = (PLISTINFO) RemHead(LHead);
++     else if (LHead->LHeaders[LISTTAIL] == t)
++          t = (PLISTINFO) RemTail(LHead);
++     else
++     {
++          t1                    = (PLISTINFO) t->ListNode.Previous;
++          t1->ListNode.Next     = t->ListNode.Next;
++          t1                    = (PLISTINFO) t->ListNode.Next;
++          t1->ListNode.Previous = t->ListNode.Previous;
++          LHead->NumList--;
++     }
++
++     return(t);
++}
++
++/*----------------------------------------------------------------------------
++ * SearchList:
++ *       Try to find a specific node in the queue whose key matches with
++ *  searching key. Return the pointer to that node if found, return NULL
++ *  otherwise
++ *
++ *  Input:
++ *    lpHashTbl       => a far pointer to the hash table
++ *    lpKey           => a far poniter to searching key
++ *    CompareCallBack => comparision function
++ *
++ *  Output: a far pointer to the node to be found
++ *
++ */
++PLISTINFO  SearchList(
++                        PLISTHEAD lpListHead,
++                        PVOID lpSKey,
++                        int (* CompareCallBack) ( PVOID, PVOID ) )
++{
++PLISTINFO lpListInfo;
++
++     lpListInfo = PeekList( lpListHead, LISTHEAD, 0);
++     while ( lpListInfo != NULL )
++     {
++          if ( CompareCallBack( lpListInfo, lpSKey ) )
++               break;
++          lpListInfo = GetNextNode( lpListInfo );
++     }
++
++     return( lpListInfo );
++}
++ 
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0bf926e0f389ddb62faa16f26139285eed538938
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,283 @@@
++
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE:queue.h
++-----------------------------------------------------------------------*/
++
++#ifndef QUEUE_INCLUDED
++#define QUEUE_INCLUDED
++
++/*        %%s  Node      */
++/*****************************************************************
++     This structure is used to store the List linkage information of a
++ListInfo structure.  It contains all the necessary information for the
++List functions to function properly.  This structure must be the first
++one defined in any block of memory to be linked with the List functions.
++for an example of the used of The Node structure look in the files
++ipd2dms.c and ipd2man.h
++******************************************************************/
++#include <stdio.h>
++#define FALSE 0
++#define TRUE  1
++typedef struct
++{
++     void  *Next;
++     void  *Previous;
++}
++     Node, * PNODE;
++
++/*****************************************************************
++     Next     :  is a pointer to the next structure in this List.
++     Previous :  is a pointer to the previous structure in this List.
++     priority :  this is the priority of this structure in the List.  The
++                 highest priority is 0.  This field is only used by the
++                 functions EnQue and DeQue.
++******************************************************************/
++/*        %%e       */
++
++
++/*        %%s  ListInfo      */
++
++/*****************************************************************
++      This is the general means of linking application defined information into
++Lists and queues.  All structures must begin with the Node Structure.  All
++other data in the structure is user definable.
++******************************************************************/
++
++typedef struct List
++{
++     Node     ListNode;       /*  link to the next Listinfo Structure  */
++     /*  user definable data  */
++}    ListInfo, *PLISTINFO;
++
++/*****************************************************************
++     ListNode  :  this is the required node structure for the List
++                  mainpulation functions.  This must be the first
++                  element of a user definable structure.
++
++     In order for an application to use the List routines, it must define
++a structure with all the needed information.  The first element in the
++user definable structure must be a Node structure.  The Node structure
++contains all the necessary information for the List routines to do their
++magic.  For an example of a user defined List structure see the file
++ipd2i.h.  The User definable structure can be passed to any List function
++that excepts a pointer to a ListInfo structure.
++
++example:
++
++typedef  mstruct
++{
++     Node   ListNode;
++     int    a,b,c,d,e,f,g;
++}
++     mystruct;
++
++     the user definable portion of the above structure is represented by
++the integers a,b,c,d,e,f,g.  When passing this structure to a List
++function a cast of (ListInfo *) must be made to satisify the "C" complier.
++******************************************************************/
++/*        %%e       */
++
++
++/*        %%s ListHead        */
++/*****************************************************************
++     ListHead is used as a header to a List.  LHeaders[0] points to the
++head of the List.  LHeaders[1] points the tail of the list.  When
++accessing these variables use the defines  LISTHEAD, LISTTAIL.
++******************************************************************/
++
++typedef struct LHead
++{
++     PLISTINFO  LHeaders[2];
++     int         NumList;
++}
++ListHead, *PLISTHEAD;
++
++/*****************************************************************
++     LHeaders   :  this is an array of two pointers to ListInfo structures.
++                   This information is used to point to the head and tail of
++                   a list.
++     NumList    :  this integer hold the number of structures linked into this
++                   list.
++
++ListHead #define:
++
++     LISTHEAD  :  when Peeking down a list this specifies you should
++                  start at the Head of the list and search downward.
++
++     LISTTAIL  :  when Peeking down a list this specifies you should
++                  start at the tail of the list and search foward.
++ ******************************************************************/
++
++#define  LISTHEAD  0
++
++#define  LISTTAIL  1
++/*        %%e       */ 
++
++typedef int BOOL;
++typedef void * PVOID;
++
++#define PEEKFROMHEAD( lh, ind )     ( PeekList( (lh), LISTHEAD, (ind) ) )
++#define PEEKFROMTAIL( lh, ind )     ( PeekList( (lh), LISTTAIL, (ind) ) )
++#define EMPTYLIST( lh )             ( ( (lh)->LHeaders[LISTHEAD] == NULL ) )
++
++/*   General utility routines   */
++/*        %%s QueRoutines          */
++BOOL    InitList      ( PLISTHEAD );
++
++/*****************************************************************
++     InitList :  Initialize a new list structure for use with the List
++                 routines
++
++     INPUTS   :  LHead : a pointer to a ListHead structure.
++     OUTPUT   :  a boolean value TRUE if no errors occured FALSE
++                 otherwise
++******************************************************************/
++
++
++PLISTINFO  PeekList      ( PLISTHEAD, int, int   );
++
++/*****************************************************************
++     PeekList :  This funciton peeks down a list for the N'th element
++                 from the HEAD or TAIL of the list
++
++     INPUTS   :  LHead    :  a pointer to a List head structure.
++                 from     :  can either search from the HEAD or TAIL
++                             of the list
++                 where    :  how many nodes from the begining should the
++                             List routines look.
++     OUTPUT   :  a pointer to a ListInfo structure identified by
++                 from/where or NULL if an error occurred.
++******************************************************************/
++
++
++PLISTINFO   RemoveList( PLISTHEAD LHead, PLISTINFO LInfo );
++
++
++/*****************************************************************
++     RemoveList: Remove a ListInfo structure from a List.
++
++     INPUTS    : LHead  :  a pointer to a ListHead structure.
++                 LInfo  :  a pointer to the ListInfo structure to remove
++                           from the list.
++     OUTPUT    : a pointer to the ListInfo structure that was removed or
++                 NULL if an error occurred.
++******************************************************************/
++
++BOOL  InsertNode( PLISTHEAD LHead, int nPos, PLISTINFO LInfo );
++
++/*****************************************************************
++     InsertNode: add a node to a list after a given node
++     
++     INPUTS    : LHead : a pointer to a ListHead structure.
++                 nPos  : the position to insert the node into
++                 LInfo : a pointer to the new node to add to the list.
++     OUTPUT: a boolean value TRUE if all goes well false otherwise
++*****************************************************************/
++
++BOOL   AddHead       ( PLISTHEAD, PLISTINFO );
++
++/*****************************************************************
++     AddHead   : add a ListInfo structure to the HEAD of a list.
++
++     INPUTS    : LHead  : a pointer to a ListHead structure of the list
++                          to add to.
++                 LInfo  : a pointer to the ListInfo structure to add to
++                          the list.
++     OUTPUT    : A boolean value TRUE if no errors occurred FALSE
++                 otherwise.
++******************************************************************/
++
++
++BOOL     AddTail       ( PLISTHEAD, PLISTINFO );
++
++/*****************************************************************
++     AddTail   : Add a ListInfo structure to the TAIL of a list.
++
++     INPUTS    : LHead  : a pointer to a ListHead structure of the List
++                          to add to.
++                 LInfo  : a pointer to the ListInfo structure to add to
++                          the List.
++     OUTPUT    : a boolean value TRUE if no errors occurred FALSE
++                 otherwise.
++******************************************************************/
++
++
++PLISTINFO  RemTail       ( PLISTHEAD );
++
++/*****************************************************************
++     RemTail   : Remove a ListInfo structure from the TAIL of a List.
++
++     INPUTS    : LHead  : a pointer to a ListHead structure of the List
++                          to remove from.
++     OUTPUT    : a pointer to the ListInfo structure that was removed
++                 or NULL if an error occurred.
++******************************************************************/
++
++
++PLISTINFO  RemHead       ( PLISTHEAD );
++
++/*****************************************************************
++     RemHead   : Remove a ListInfo structure from the Head of a List.
++
++     INPUTS    : LHead  : a pointer to a ListHead structure of the List
++                          to remove from.
++     OUTPUT    : a pointer to the ListInfo structure that was removed or
++                 NULL if an error occurred.
++******************************************************************/
++
++PLISTINFO  SearchList(
++                        PLISTHEAD lpListHead,
++                        PVOID lpSKey,
++                        int ( * CompareCallBack) ( PVOID, PVOID ) );
++
++/*****************************************************************
++  SearchList:
++        Try to find a specific node in the queue whose key matches with
++   searching key. Return the pointer to that node if found, return NULL
++   otherwise
++
++   Input:
++     lpHashTbl       => a far pointer to the hash table
++     lpKey           => a far poniter to searching key
++     CompareCallBack => comparision function
++
++   Output: a far pointer to the node to be found
++
++ ******************************************************************/
++
++#define           NumOnList(lh) ( ((lh)->NumList)        )
++
++/*****************************************************************
++     NumOnList: Returns the number of Nodes linked to a ListHead
++                structure.  This number is maintained by the List
++                routines.
++******************************************************************/
++
++#define           GetNextNode(pli) ( ((pli)->ListNode.Next) )
++
++/********************************************************
++     GetNextNode: This macro returns the Next Structure in this list.
++                  This macro will return NULL if no more structures are
++                  in the List.
++*********************************************************/
++
++#define           GetPrevNode(pli) ( ((pli)->ListNode.Previous) )
++
++/********************************************************
++     GetPrevNode: This macro returns the Previous Structure in this list.
++                  This macro will reutrn NULL if no more structures are
++                  in the List.
++********************************************************/
++/*        %%e       */
++
++#endif
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..40dff70f61c7068f3c51e68b0c3258a8ddeb99d9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,631 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: sgi_triang.c
++     File contains the routines that do the whole triangulation
++     of polygons.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include "global.h"
++#include "output.h"
++#include "polverts.h"
++#include "sturcts.h"
++#include "common.h"
++#include "util.h"
++#include "init.h"
++
++int Adjacent(int id2,int id1, int *list, int size)
++{
++      /*      Return the vertex that is adjacent to id1,
++              but is not id2, in the list of integers.
++      */
++
++      register int x=0;
++      
++      while (x < size)
++      {
++              if (*(list+x) == id1)
++              {
++                      if ((x != (size -1)) && (x != 0))
++                      {
++                              if ( *(list+x+1) != id2)
++                                      return *(list+x+1);
++                              else
++                                      return *(list+x-1);
++                      }
++                      else if (x == (size -1))
++                      {
++                              if (*(list) != id2)
++                                      return *(list);
++                              else
++                                      return *(list+x-1);
++                      }
++                      else
++                      {
++                              if (*(list+size-1) != id2)
++                                      return *(list+size-1);
++                              else
++                                      return *(list+x+1);
++                      }
++              }
++              x++;
++      }
++      /*   if there are degeneracies */
++     return id1;
++}
++
++
++void Rearrange_Index(int *index, int size)
++{
++      /*      If we are in the middle of a strip we must find the
++              edge to start on, which is the last edge that we had
++              transmitted.
++      */
++      int x,f,y,e1,e2,e3;
++      register int increment = 1;
++     int *temp;
++
++      /*      Find where the input edge is in the input list */
++      Last_Edge(&e1,&e2,&e3,0);
++      for (y = 0; y < size; y++)
++      {
++              if (*(index+y) == e2)
++              {
++                      if ((y != (size - 1)) && (*(index+y+1) == e3))
++                              break;
++                      else if ((y == (size - 1)) && (*(index) == e3))
++                              break;
++               else if ((y != 0) && (*(index+y-1) == e3))
++               {
++                    increment = -1;
++                    break;
++               }
++               else if ((y==0) && (*(index+size-1) == e3))
++               {
++                    increment = -1;
++                    break;
++               }
++              }
++              if (*(index+y) == e3)
++              {
++                      if ((y != (size - 1)) && (*(index+y+1) == e2))
++                              break;
++                      else if ((y == (size - 1)) && (*(index) == e2))
++                              break;
++            else if ((y != 0) && (*(index+y-1) == e2))
++            {
++                increment = -1;
++                break;
++            }
++            else if ((y==0) && (*(index+size-1) == e2))
++            {
++                increment = -1;
++                break;
++            }
++              }
++              /*      Edge is not here, we are at the beginning */
++              if ((y == (size-1)) && (increment != -1))
++                      return;
++      }
++      
++      /*      Now put the list into a new list, starting with the
++              input edge. Increment tells us whether we have to go 
++              forward or backward.
++      */
++      /*      Was in good position already */
++      if ((y == 0) && (increment == 1)) 
++              return;
++      
++     temp = (int *) malloc(sizeof(int) * size);
++     memcpy(temp,index,sizeof(int)*size);
++
++      if (increment == 1)
++      {
++              x=0;
++              for (f = y ; f< size; f++)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++              /*      Finish the rest of the list */  
++              for(f = 0; f < y ; f++)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++      }
++      else
++      {
++              x=0;
++              for (f = y ; f >= 0; f--)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++              /*      Finish the rest of the list */  
++              for(f = (size - 1); f > y ; f--)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++      }
++}
++
++void Delete_From_List(int id,int *list, int *size)
++{
++      /*      Delete the occurence of id in the list.
++              (list has size size)
++      */
++
++      int *temp;
++      register int x,y=0;
++
++      temp = (int *) malloc(sizeof(int) * (*size));
++      for (x=0; x<(*size); x++)
++      {
++              if (*(list+x) != id)
++              {
++                      *(temp+y) = *(list+x);
++                      y++;
++              }
++      }
++      *(temp+y) = -1;
++     *size = *size - (*size - y - 1);
++      memcpy(list,temp,sizeof(int)*(*size));
++}
++
++
++void Build_SGI_Table(int num_verts,int num_faces)
++{
++      /*      Build a table that has the polygons sorted by the
++              number of adjacent polygons.
++      */
++      int x,y,size,tally=0;
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++
++      /* For each face....*/
++      for (x=0;x < num_faces;x++)
++      {
++              pListHead = PolFaces[x];
++              temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++              /*   Check each edge of the face and tally the number of adjacent
++                      polygons to this face. 
++              */                      
++              if ( temp != NULL )
++              {
++                      /*      Size of the polygon */
++                      size = temp->nPolSize;
++                      if (size != 1)
++               {
++                    for (y = 0; y< size; y++)
++                           {
++                                   if (y != (size-1))
++                                           tally += Num_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1));
++                                   else
++                                           tally += Num_Adj(*(temp->pPolygon),*(temp->pPolygon+(size-1)));
++                    }
++                      
++                           /*   Tally is the number of polygons that is adjacent to
++                                   the current polygon. 
++                           */
++                           /*      Now put the face in the proper bucket depending on tally. */
++                           Add_Sgi_Adj(tally,x);
++                           temp = NULL;
++                           tally=0;
++               }
++              }
++      }
++}
++
++
++void Triangulate_Quad(int out_edge1,int out_edge2,int in_edge1,
++                                        int in_edge2,int size,int *index,
++                                        FILE *output,int reversed,int face_id,
++                      int where,int color1,int color2,int color3)
++{
++      int vertex4,vertex5;
++      
++      /*      This routine will nonblindly triangulate a quad, meaning
++              that there is a definite input and a definite output
++              edge that we must adhere to. Reversed will tell the orientation
++              of the input edge. (Reversed is -1 is we do not have an input
++              edge, in other words we are at the beginning of a strip.)
++              Out_edge* is the output edge, and in_edge* is the input edge. 
++              Index are the edges of the polygon
++              and size is the size of the polygon. Begin is whether we are
++              at the start of a new strip.
++      */
++      
++      /*      If we do not have an input edge, then we can make our input
++              edge whatever we like, therefore it will be easier to come
++              out on the output edge.
++      */
++      if (reversed == -1)
++      {
++              vertex4 = Adjacent(out_edge1,out_edge2,index,size);
++              vertex5 = Get_Other_Vertex(vertex4,out_edge1,out_edge2,index);
++              Output_Tri(vertex5,vertex4,out_edge1,output,color1,color2,color3,where);
++              Output_Tri(vertex4,out_edge1,out_edge2,output,color1,color2,color3,where);
++              return;
++      }
++      
++      /*      These are the 5 cases that we can have for the output edge */
++      
++      /*  Are they consecutive so that we form a triangle to
++              peel off, but cannot use the whole quad?
++      */
++
++      if (in_edge2 == out_edge1) 
++      {
++              /*      Output the triangle that comes out the correct
++                      edge last. First output the triangle that comes out
++                      the wrong edge.
++              */
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge2,index);
++          Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where);
++          Output_Tri(vertex4,in_edge2,out_edge2,output,color1,color2,color3,where);
++              return;
++      }
++      /*      The next case is where it is impossible to come out the
++              edge that we want. So we will have to start a new strip to
++              come out on that edge. We will output the one triangle
++              that we can, and then start the new strip with the triangle
++              that comes out on the edge that we want to come out on.
++      */
++      else if (in_edge1 == out_edge1)
++      {
++              /*      We want to output the first triangle (whose output
++                      edge is not the one that we want.
++                      We have to find the vertex that we need, which is
++                      the other vertex which we do not have.
++              */
++              vertex4 = Get_Other_Vertex(in_edge2,in_edge1,out_edge2,index);
++              Output_Tri(in_edge2,in_edge1,vertex4,output,color1,color2,color3,where);
++              Output_Tri(vertex4,in_edge1,out_edge2,output,color1,color2,color3,where);
++              return;
++      }
++      
++      /*      Consecutive cases again, but with the output edge reversed */
++      else if (in_edge1 == out_edge2)
++      {
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
++              Output_Tri(in_edge2,in_edge1,vertex4,output,color1,color2,color3,where);
++              Output_Tri(vertex4,in_edge1,out_edge1,output,color1,color2,color3,where);
++              return;
++      }
++      else if (in_edge2 == out_edge2)
++      {
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
++              Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where);
++              Output_Tri(vertex4,in_edge2,out_edge1,output,color1,color2,color3,where);
++              return;
++      }
++
++      /*      The final case is where we want to come out the opposite
++              edge.
++      */
++      else
++      {
++            if( ((!reversed) && (out_edge1 == (Adjacent(in_edge1,in_edge2,index,size)))) ||
++                    ((reversed) && (out_edge2 == (Adjacent(in_edge2,in_edge1,index,size)))))
++                      {
++                      /*      We need to know the orientation of the input
++                              edge, so we know which way to put the diagonal.
++                And also the output edge, so that we triangulate
++                correctly.
++             */
++                      Output_Tri(in_edge1,in_edge2,out_edge2,output,color1,color2,color3,where);
++                      Output_Tri(in_edge2,out_edge2,out_edge1,output,color1,color2,color3,where);
++              }
++              else
++              {
++                      /*      Input and output orientation was reversed, so diagonal will
++                                      be reversed from above.
++                      */
++                      Output_Tri(in_edge1,in_edge2,out_edge1,output,color1,color2,color3,where);
++                      Output_Tri(in_edge2,out_edge1,out_edge2,output,color1,color2,color3,where);
++              }
++              return;
++      }
++}
++
++void Triangulate_Polygon(int out_edge1,int out_edge2,int in_edge1,
++                                               int in_edge2,int size,int *index,
++                                               FILE *output,int reversed,int face_id,
++                         int where,int color1,int color2,int color3)
++{
++      /*      We have a polygon that we need to nonblindly triangulate.
++              We will recursively try to triangulate it, until we are left
++              with a polygon of size 4, which can use the quad routine
++              from above. We will be taking off a triangle at a time
++              and outputting it. We will have 3 cases similar to the
++              cases for the quad above. The inputs to this routine
++              are the same as for the quad routine.
++      */
++
++      int vertex4;
++      int *temp;
++
++              
++      /*      Since we are calling this recursively, we have to check whether
++              we are down to the case of the quad.
++      */
++      
++    if (size == 4)
++      {
++              Triangulate_Quad(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                                      index,output,reversed,face_id,where,color1,color2,color3);
++              return;
++      }
++
++    
++      
++      /*      We do not have a specified input edge, and therefore we
++              can make it anything we like, as long as we still come out 
++              the output edge that we want.
++      */
++      if (reversed  == -1)
++      {
++              /*      Get the vertex for the last triangle, which is
++                      the one coming out the output edge, before we do
++                      any deletions to the list. We will be doing this
++                      bottom up.
++              */
++              vertex4 = Adjacent(out_edge1,out_edge2,index,size);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_List(out_edge2,index,&size);
++              Triangulate_Polygon(out_edge1,vertex4,in_edge2,
++                                               vertex4,size-1,index,output,reversed,face_id,where,color1,color2,color3);
++              memcpy(index,temp,sizeof(int)*size);
++              /*      Lastly do the triangle that comes out the output
++                      edge.
++              */
++              Output_Tri(vertex4,out_edge1,out_edge2,output,color1,color2,color3,where,where);
++              return;
++      }
++
++      /*      These are the 5 cases that we can have for the output edge */
++      
++      /*  Are they consecutive so that we form a triangle to
++              peel off that comes out the correct output edge, 
++              but we cannot use the whole polygon?
++      */
++      if (in_edge2 == out_edge1) 
++      {
++              /*      Output the triangle that comes out the correct
++                      edge last. First recursively do the rest of the
++                      polygon.
++              */
++              /*      Do the rest of the polygon without the triangle. 
++                      We will be doing a fan triangulation.
++              */
++              /*      Get the vertex adjacent to in_edge1, but is not
++                      in_edge2.
++              */
++              vertex4 = Adjacent(in_edge2,in_edge1,index,size);
++              Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where);
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++          Delete_From_List(in_edge1,index,&size);
++              Triangulate_Polygon(out_edge1,out_edge2,in_edge2,
++                                              vertex4,size-1,index,output,!reversed,face_id,where,color1,color2,color3);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++
++      /*      Next case is where it is again consecutive, but the triangle
++              formed by the consecutive edges do not come out of the
++              correct output edge. For this case, we can not do much to
++              keep it sequential. Try and do the fan.
++      */
++      else if (in_edge1 == out_edge1)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              vertex4 = Adjacent(in_edge1,in_edge2,index,size);
++              Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where,where);
++              /*      Since that triangle goes out of the polygon (the
++                      output edge of it), we can make our new input edge
++                      anything we like, so we will try to make it good for
++                      the strip. (This will be like starting a new strip,
++                      all so that we can go out the correct output edge.)
++              */
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_List(in_edge2,index,&size);
++              Triangulate_Polygon(out_edge1,out_edge2,in_edge1,
++                                              vertex4,size-1,index,output,reversed,face_id,where,color1,color2,color3);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++      /*      Consecutive cases again, but with the output edge reversed */
++      else if (in_edge1 == out_edge2)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              vertex4 = Adjacent(in_edge1,in_edge2,index,size);
++              Output_Tri(in_edge2,in_edge1,vertex4,output,color1,color2,color3,where,where);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_List(in_edge2,index,&size);
++          Triangulate_Polygon(out_edge1,out_edge2,in_edge1,
++                                              vertex4,size-1,index,output,reversed,face_id,where,color1,color2,color3);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++      else if (in_edge2 == out_edge2)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              vertex4 = Adjacent(in_edge2,in_edge1,index,size);
++              Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where,where);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_List(in_edge1,index,&size);
++          Triangulate_Polygon(out_edge1,out_edge2,vertex4,
++                                              in_edge2,size-1,index,output,reversed,face_id,where,color1,color2,color3);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++
++      /*      Else the edge is not consecutive, and it is sufficiently
++              far away, for us not to make a conclusion at this time.
++              So we can take off a triangle and recursively call this
++              function.
++      */
++      else
++      {
++                      vertex4 = Adjacent(in_edge2,in_edge1,index,size);
++                      Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where,where);
++                      temp = (int *) malloc(sizeof(int) * size);
++                      memcpy(temp,index,sizeof(int)*size);
++                      Delete_From_List(in_edge1,index,&size);
++               Triangulate_Polygon(out_edge1,out_edge2,in_edge2,
++                                                   vertex4,size-1,index,output,!reversed,face_id,where,color1,color2,color3);
++                      memcpy(index,temp,sizeof(int)*size);
++                   return;
++      }
++}
++
++void Triangulate(int out_edge1,int out_edge2,int in_edge1,
++                               int in_edge2,int size,int *index,
++                               FILE *output,int reversed,int face_id, int where,
++                     int color1, int color2,int color3)
++{
++      /*      We have the info we need to triangulate a polygon */
++
++      if (size == 4)
++              Triangulate_Quad(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                  index,output,reversed,face_id,where,color1,color2,color3);
++      else
++              Triangulate_Polygon(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                     index,output,reversed,face_id,where,color1,color2,color3);
++}
++
++void Non_Blind_Triangulate(int size,int *index,
++                                        FILE *output,int next_face_id,int face_id,int where,
++                           int color1,int color2,int color3)
++{
++      int id1,id2,id3;
++      int nedge1,nedge2;
++      int reversed;
++      /*      We have a polygon that has to be triangulated and we cannot
++              do it blindly, ie we will try to come out on the edge that
++              has the least number of adjacencies
++      */
++
++      Last_Edge(&id1,&id2,&id3,0);
++      /*      Find the edge that is adjacent to the new face ,
++              also return whether the orientation is reversed in the
++              face of the input edge, which is id2 and id3.
++      */
++      if (next_face_id == -1)
++     {
++        printf("The face is -1 and the size is %d\n",size);
++        exit(0);
++     }
++    
++     reversed = Get_Edge(&nedge1,&nedge2,index,next_face_id,size,id2,id3);
++      /*      Do the triangulation */
++      
++      /*      If reversed is -1, the input edge is not in the polygon, therefore we can have the
++              input edge to be anything we like, since we are at the beginning
++              of a strip
++      */
++      Triangulate(nedge1,nedge2,id2,id3,size,index,output,reversed,
++                     face_id, where,color1,color2,color3);
++}
++
++
++
++void Blind_Triangulate(int size, int *index, FILE *output,
++                                 BOOL begin, int where ,int color1,int color2,
++                       int color3)
++{
++      /*      save sides in temp array, we need it so we know
++              about swaps.
++      */
++      int mode, decreasing,increasing,e1,e2,e3;
++      int x = 0;
++      BOOL flag = FALSE;
++
++      /*      Rearrange the index list so that the input edge is first
++      */
++      if (!begin)
++              Rearrange_Index(index,size);
++      
++      /*      We are given a polygon of more than 3 sides
++              and want to triangulate it. We will output the
++              triangles to the output file.
++      */
++      
++    /*        Find where the input edge is in the input list */
++      Last_Edge(&e1,&e2,&e3,0);
++     if (( (!begin) && (*(index) == e2) ) || (begin))
++     {
++          Output_Tri(*(index+0),*(index+1),*(index+size-1),output,color1,color2,color3,where,where);
++        /*    If we have a quad, (chances are yes), then we know that
++                   we can just add one diagonal and be done. (divide the
++                   quad into 2 triangles.
++        */
++        if (size == 4)
++        {
++                  Output_Tri(*(index+1),*(index+size-1),*(index+2),output,color1,color2,color3,where,where);
++              return;
++        }
++        increasing = 1;
++        mode = 1;
++
++    }
++    else if (!begin)
++    {
++        Output_Tri(*(index+1),*(index+0),*(index+size-1),output,color1,color2,color3,where,where);
++        if (size == 4)
++        {
++            Output_Tri(*(index+0),*(index+size-1),*(index+2),output,color1,color2,color3,where,where);
++            return;
++        }
++        Output_Tri(*(index+0),*(index+size-1),*(index+2),output,color1,color2,color3,where,where);
++        increasing = 2;
++        mode = 0;
++    }
++    if (size != 4)
++    {
++              /*      We do not have a quad, we have something bigger. */
++              decreasing = size - 1;          
++              do
++              {
++                      /*      Will be alternating diagonals, so we will be increasing
++                              and decreasing around the polygon.
++                      */
++                      if (mode)
++                      {
++                              Output_Tri(*(index+increasing),*(index+decreasing),*(index+increasing+1),output,color1,color2,color3,where,where);
++                              increasing++;
++                      }
++                      else
++                      {
++                              Output_Tri(*(index+decreasing),*(index+increasing),*(index+decreasing-1),output,color1,color2,color3,where,where);
++                    decreasing--;
++               }
++                      mode = !mode;
++              } while ((decreasing - increasing) >= 2);
++
++      }
++}
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..afa2fd7db5e5fe5b420cb20e875d0541e791fabf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,584 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: sgi_triangex.c
++     This file contains routines that are used for various functions in
++     the local algorithm.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include "global.h"
++#include "outputex.h"
++#include "polverts.h"
++#include "sturctsex.h"
++#include "common.h"
++#include "util.h"
++
++
++int AdjacentEx(int id2,int id1, int *list, int size)
++{
++      /*      Return the vertex that is adjacent to id1,
++              but is not id2, in the list of integers.
++      */
++
++      register int x=0;
++      
++      while (x < size)
++      {
++              if (*(list+x) == id1)
++              {
++                      if ((x != (size -1)) && (x != 0))
++                      {
++                              if ( *(list+x+1) != id2)
++                                      return *(list+x+1);
++                              else
++                                      return *(list+x-1);
++                      }
++                      else if (x == (size -1))
++                      {
++                              if (*(list) != id2)
++                                      return *(list);
++                              else
++                                      return *(list+x-1);
++                      }
++                      else
++                      {
++                              if (*(list+size-1) != id2)
++                                      return *(list+size-1);
++                              else
++                                      return *(list+x+1);
++                      }
++              }
++              x++;
++      }
++      printf("Error in the list\n");
++      exit(0);
++}
++
++
++void Delete_From_ListEx(int id,int *list, int size)
++{
++      /*      Delete the occurence of id in the list.
++              (list has size size)
++      */
++
++      int *temp;
++      register int x,y=0;
++
++      temp = (int *) malloc(sizeof(int) * size);
++      for (x=0; x<size; x++)
++      {
++              if (*(list+x) != id)
++              {
++                      *(temp+y) = *(list+x);
++                      y++;
++              }
++      }
++      if(y != (size-1))
++      {
++              printf("There is an error in the delete\n");
++              exit(0);
++      }
++      *(temp+size-1) = -1;
++      memcpy(list,temp,sizeof(int)*size);
++
++}
++
++
++void Triangulate_QuadEx(int out_edge1,int out_edge2,int in_edge1,
++                                        int in_edge2,int size,int *index,
++                                        FILE *output,FILE *fp,int reversed,int face_id,
++                      int where)
++{
++      int vertex4,vertex5;
++      
++      /*      This routine will nonblindly triangulate a quad, meaning
++              that there is a definite input and a definite output
++              edge that we must adhere to. Reversed will tell the orientation
++              of the input edge. (Reversed is -1 is we do not have an input
++              edge, in other words we are at the beginning of a strip.)
++              Out_edge* is the output edge, and in_edge* is the input edge. 
++              Index are the edges of the polygon
++              and size is the size of the polygon. Begin is whether we are
++              at the start of a new strip.
++      */
++      
++      /*      If we do not have an input edge, then we can make our input
++              edge whatever we like, therefore it will be easier to come
++              out on the output edge.
++      */
++      if (reversed == -1)
++      {
++              vertex4 = AdjacentEx(out_edge1,out_edge2,index,size);
++              vertex5 = Get_Other_Vertex(vertex4,out_edge1,out_edge2,index);
++              Output_TriEx(vertex5,vertex4,out_edge1,output,-1,-1,where);
++              Output_TriEx(vertex4,out_edge1,out_edge2,output,-1,-1,where);
++              return;
++      }
++      
++      /*      These are the 5 cases that we can have for the output edge */
++      
++      /*   Are they consecutive so that we form a triangle to
++              peel off, but cannot use the whole quad?
++      */
++
++      if (in_edge2 == out_edge1) 
++      {
++              /*      Output the triangle that comes out the correct
++                      edge last. First output the triangle that comes out
++                      the wrong edge.
++              */
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge2,index);
++          Output_TriEx(in_edge1,in_edge2,vertex4,output,-1,-1,where);
++          Output_TriEx(vertex4,in_edge2,out_edge2,output,-1,-1,where);
++              return;
++      }
++      /*      The next case is where it is impossible to come out the
++              edge that we want. So we will have to start a new strip to
++              come out on that edge. We will output the one triangle
++              that we can, and then start the new strip with the triangle
++              that comes out on the edge that we want to come out on.
++      */
++      else if (in_edge1 == out_edge1)
++      {
++              /*      We want to output the first triangle (whose output
++                      edge is not the one that we want.
++                      We have to find the vertex that we need, which is
++                      the other vertex which we do not have.
++              */
++              vertex4 = Get_Other_Vertex(in_edge2,in_edge1,out_edge2,index);
++              Output_TriEx(in_edge2,in_edge1,vertex4,output,-1,-1,where);
++              Output_TriEx(vertex4,in_edge1,out_edge2,output,-1,-1,where);
++              return;
++      }
++      
++      /*      Consecutive cases again, but with the output edge reversed */
++      else if (in_edge1 == out_edge2)
++      {
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
++              Output_TriEx(in_edge2,in_edge1,vertex4,output,-1,-1,where);
++              Output_TriEx(vertex4,in_edge1,out_edge1,output,-1,-1,where);
++              return;
++      }
++      else if (in_edge2 == out_edge2)
++      {
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
++              Output_TriEx(in_edge1,in_edge2,vertex4,output,-1,-1,where);
++              Output_TriEx(vertex4,in_edge2,out_edge1,output,-1,-1,where);
++              return;
++      }
++
++      /*      The final case is where we want to come out the opposite edge.*/
++      else
++      {
++           if( ((!reversed) && (out_edge1 == (AdjacentEx(in_edge1,in_edge2,index,size)))) ||
++                    ((reversed) && (out_edge2 == (AdjacentEx(in_edge2,in_edge1,index,size)))))
++               {
++                      /*      We need to know the orientation of the input
++                              edge, so we know which way to put the diagonal.
++                    And also the output edge, so that we triangulate correctly.
++               */
++                      Output_TriEx(in_edge1,in_edge2,out_edge2,output,-1,-1,where);
++                      Output_TriEx(in_edge2,out_edge2,out_edge1,output,-1,-1,where);
++               }
++              else
++              {
++                      /*   Input and output orientation was reversed, so diagonal will
++                              be reversed from above.
++                      */
++                      Output_TriEx(in_edge1,in_edge2,out_edge1,output,-1,-1,where);
++                      Output_TriEx(in_edge2,out_edge1,out_edge2,output,-1,-1,where);
++              }
++              return;
++      }
++}
++
++void Triangulate_PolygonEx(int out_edge1,int out_edge2,int in_edge1,
++                                        int in_edge2,int size,int *index,
++                                        FILE *output,FILE *fp,int reversed,int face_id,
++                           int where)
++{
++      /*      We have a polygon that we need to nonblindly triangulate.
++              We will recursively try to triangulate it, until we are left
++              with a polygon of size 4, which can use the quad routine
++              from above. We will be taking off a triangle at a time
++              and outputting it. We will have 3 cases similar to the
++              cases for the quad above. The inputs to this routine
++              are the same as for the quad routine.
++      */
++
++      int vertex4;
++      int *temp;
++
++              
++      /*      Since we are calling this recursively, we have to check whether
++              we are down to the case of the quad.
++      */
++      
++    if (size == 4)
++      {
++              Triangulate_QuadEx(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                          index,output,fp,reversed,face_id,where);
++              return;
++      }
++
++    
++      
++      /*      We do not have a specified input edge, and therefore we
++              can make it anything we like, as long as we still come out 
++              the output edge that we want.
++      */
++      if (reversed  == -1)
++      {
++              /*      Get the vertex for the last triangle, which is
++                      the one coming out the output edge, before we do
++                      any deletions to the list. We will be doing this
++                      bottom up.
++              */
++              vertex4 = AdjacentEx(out_edge1,out_edge2,index,size);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_ListEx(out_edge2,index,size);
++              Triangulate_PolygonEx(out_edge1,vertex4,in_edge2,
++                                                vertex4,size-1,index,output,fp,reversed,face_id,where);
++              memcpy(index,temp,sizeof(int)*size);
++              /*      Lastly do the triangle that comes out the output
++                      edge.
++              */
++              Output_TriEx(vertex4,out_edge1,out_edge2,output,-1,-1,where);
++              return;
++      }
++
++      /*      These are the 5 cases that we can have for the output edge */
++      
++      /*  Are they consecutive so that we form a triangle to
++              peel off that comes out the correct output edge, 
++              but we cannot use the whole polygon?
++      */
++      if (in_edge2 == out_edge1) 
++      {
++              /*      Output the triangle that comes out the correct
++                      edge last. First recursively do the rest of the
++                      polygon.
++              */
++              /*      Do the rest of the polygon without the triangle. 
++                      We will be doing a fan triangulation.
++              */
++              /*      Get the vertex adjacent to in_edge1, but is not
++                      in_edge2.
++              */
++              vertex4 = AdjacentEx(in_edge2,in_edge1,index,size);
++              Output_TriEx(in_edge1,in_edge2,vertex4,output,-1,-1,where);
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++          Delete_From_ListEx(in_edge1,index,size);
++              Triangulate_PolygonEx(out_edge1,out_edge2,in_edge2,
++                                                vertex4,size-1,index,output,fp,!reversed,face_id,where);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++
++      /*      Next case is where it is again consecutive, but the triangle
++              formed by the consecutive edges do not come out of the
++              correct output edge. For this case, we can not do much to
++              keep it sequential. Try and do the fan.
++      */
++      else if (in_edge1 == out_edge1)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              vertex4 = AdjacentEx(in_edge1,in_edge2,index,size);
++              Output_TriEx(in_edge1,in_edge2,vertex4,fp,-1,-1,where);
++              /*      Since that triangle goes out of the polygon (the
++                      output edge of it), we can make our new input edge
++                      anything we like, so we will try to make it good for
++                      the strip. (This will be like starting a new strip,
++                      all so that we can go out the correct output edge.)
++              */
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_ListEx(in_edge2,index,size);
++              Triangulate_PolygonEx(out_edge1,out_edge2,in_edge1,
++                                                vertex4,size-1,index,output,fp,reversed,face_id,where);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++      /*      Consecutive cases again, but with the output edge reversed */
++      else if (in_edge1 == out_edge2)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              vertex4 = AdjacentEx(in_edge1,in_edge2,index,size);
++              Output_TriEx(in_edge2,in_edge1,vertex4,fp,-1,-1,where);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_ListEx(in_edge2,index,size);
++          Triangulate_PolygonEx(out_edge1,out_edge2,in_edge1,
++                                     vertex4,size-1,index,output,fp,reversed,face_id,where);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++      else if (in_edge2 == out_edge2)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              vertex4 = AdjacentEx(in_edge2,in_edge1,index,size);
++              Output_TriEx(in_edge1,in_edge2,vertex4,fp,-1,-1,where);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_ListEx(in_edge1,index,size);
++          Triangulate_PolygonEx(out_edge1,out_edge2,vertex4,
++                                                in_edge2,size-1,index,output,fp,reversed,face_id,where);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++
++      /*      Else the edge is not consecutive, and it is sufficiently
++              far away, for us not to make a conclusion at this time.
++              So we can take off a triangle and recursively call this
++              function.
++      */
++      else
++      {
++                      vertex4 = AdjacentEx(in_edge2,in_edge1,index,size);
++                      Output_TriEx(in_edge1,in_edge2,vertex4,fp,-1,-1,where);
++                      temp = (int *) malloc(sizeof(int) * size);
++                      memcpy(temp,index,sizeof(int)*size);
++                      Delete_From_ListEx(in_edge1,index,size);
++               Triangulate_PolygonEx(out_edge1,out_edge2,in_edge2,
++                                                     vertex4,size-1,index,output,fp,!reversed,face_id,where);
++                      memcpy(index,temp,sizeof(int)*size);
++                   return;
++      }
++}
++
++void TriangulateEx(int out_edge1,int out_edge2,int in_edge1,
++                               int in_edge2,int size,int *index,
++                               FILE *fp,FILE *output,int reversed,int face_id, int where)
++{
++      /*      We have the info we need to triangulate a polygon */
++
++      if (size == 4)
++              Triangulate_QuadEx(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                    index,fp,output,reversed,face_id,where);
++      else
++              Triangulate_PolygonEx(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                       index,fp,output,reversed,face_id,where);
++}
++
++void Non_Blind_TriangulateEx(int size,int *index, FILE *fp,
++                                               FILE *output,int next_face_id,int face_id,int where)
++{
++      int id1,id2,id3;
++      int nedge1,nedge2;
++      int reversed;
++      /*      We have a polygon that has to be triangulated and we cannot
++              do it blindly, ie we will try to come out on the edge that
++              has the least number of adjacencies
++      */
++
++      Last_Edge(&id1,&id2,&id3,0);
++      /*      Find the edge that is adjacent to the new face ,
++              also return whether the orientation is reversed in the
++              face of the input edge, which is id2 and id3.
++      */
++      if (next_face_id == -1)
++    {
++        printf("The face is -1 and the size is %d\n",size);
++        exit(0);
++    }
++    
++    reversed = Get_EdgeEx(&nedge1,&nedge2,index,next_face_id,size,id2,id3);
++      /*      Do the triangulation */
++      
++      /*      If reversed is -1, the input edge is not in the polygon, therefore we can have the
++              input edge to be anything we like, since we are at the beginning
++              of a strip
++      */
++      TriangulateEx(nedge1,nedge2,id2,id3,size,index,fp,output,reversed,
++                       face_id, where);
++}
++
++void Rearrange_IndexEx(int *index, int size)
++{
++      /*      If we are in the middle of a strip we must find the
++              edge to start on, which is the last edge that we had
++              transmitted.
++      */
++      int x,f,y,e1,e2,e3;
++      int increment = 1;
++     int *temp;
++
++      /*      Find where the input edge is in the input list */
++      Last_Edge(&e1,&e2,&e3,0);
++      for (y = 0; y < size; y++)
++      {
++              if (*(index+y) == e2)
++              {
++                      if ((y != (size - 1)) && (*(index+y+1) == e3))
++                              break;
++                      else if ((y == (size - 1)) && (*(index) == e3))
++                              break;
++               else if ((y != 0) && (*(index+y-1) == e3))
++               {
++                   increment = -1;
++                   break;
++               }
++               else if ((y==0) && (*(index+size-1) == e3))
++               {
++                   increment = -1;
++                   break;
++               }
++              }
++              if (*(index+y) == e3)
++              {
++                      if ((y != (size - 1)) && (*(index+y+1) == e2))
++                              break;
++                      else if ((y == (size - 1)) && (*(index) == e2))
++                              break;
++               else if ((y != 0) && (*(index+y-1) == e2))
++               {
++                   increment = -1;
++                   break;
++               }
++               else if ((y==0) && (*(index+size-1) == e2))
++               {
++                   increment = -1;
++                   break;
++               }
++              }
++              /*      Edge is not here, we are at the beginning */
++              if ((y == (size-1)) && (increment != -1))
++                      return;
++      }
++      
++      /*      Now put the list into a new list, starting with the
++              input edge. Increment tells us whether we have to go 
++              forward or backward.
++      */
++      /*      Was in good position already */
++      if ((y == 0) && (increment == 1)) 
++              return;
++      
++                  
++    temp = (int *) malloc(sizeof(int) * size);
++    memcpy(temp,index,sizeof(int)*size);
++
++      if (increment == 1)
++      {
++              x=0;
++              for (f = y ; f< size; f++)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++              /*      Finish the rest of the list */  
++              for(f = 0; f < y ; f++)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++      }
++      else
++      {
++              x=0;
++              for (f = y ; f >= 0; f--)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++              /*      Finish the rest of the list */  
++              for(f = (size - 1); f > y ; f--)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++      }
++}
++
++void Blind_TriangulateEx(int size, int *index, FILE *fp,
++                                               FILE *output, BOOL begin, int where )
++{
++      /*      save sides in temp array, we need it so we know
++              about swaps.
++      */
++      int mode, decreasing,increasing,e1,e2,e3;
++      int x = 0;
++      BOOL flag = FALSE;
++
++      /*      Rearrange the index list so that the input edge is first
++      */
++      if (!begin)
++              Rearrange_IndexEx(index,size);
++      
++      /*      We are given a polygon of more than 3 sides
++              and want to triangulate it. We will output the
++              triangles to the output file.
++      */
++      
++    /*        Find where the input edge is in the input list */
++      Last_Edge(&e1,&e2,&e3,0);
++     if (( (!begin) && (*(index) == e2) ) || (begin))
++     {
++          Output_TriEx(*(index+0),*(index+1),*(index+size-1),fp,-1,-1,where);
++        /*    If we have a quad, (chances are yes), then we know that
++              we can just add one diagonal and be done. (divide the
++              quad into 2 triangles.
++        */
++        if (size == 4)
++        {
++                  Output_TriEx(*(index+1),*(index+size-1),*(index+2),fp,-1,-1,where);
++              return;
++        }
++        increasing = 1;
++        mode = 1;
++
++    }
++    else if (!begin)
++    {
++        Output_TriEx(*(index+1),*(index+0),*(index+size-1),fp,-1,-1,where);
++        if (size == 4)
++        {
++            Output_TriEx(*(index+0),*(index+size-1),*(index+2),fp,-1,-1,where);
++            return;
++        }
++        Output_TriEx(*(index+0),*(index+size-1),*(index+2),fp,-1,-1,where);
++        increasing = 2;
++        mode = 0;
++    }
++      if (size != 4)
++      {
++              /*      We do not have a quad, we have something bigger. */
++              decreasing = size - 1;
++              
++              do
++              {
++                      /*      Will be alternating diagonals, so we will be increasing
++                              and decreasing around the polygon.
++                      */
++                      if (mode)
++                      {
++                              Output_TriEx(*(index+increasing),*(index+decreasing),*(index+increasing+1),fp,-1,-1,where);
++                              increasing++;
++                      }
++                      else
++                      {
++                              Output_TriEx(*(index+decreasing),*(index+increasing),*(index+decreasing-1),fp,-1,-1,where);
++                    decreasing--;
++               }
++                      mode = !mode;
++              } while ((decreasing - increasing) >= 2);
++
++      }
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f822b1da7ce1e69a7f43c472671395da35a376e5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,549 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: struct.c
++     Contains routines that update structures, and micellaneous routines.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdlib.h>
++#include <string.h>
++#include "polverts.h"
++#include "ties.h"
++#include "output.h"
++#include "triangulate.h"
++#include "sturcts.h"
++#include "options.h"
++#include "common.h"
++#include "util.h"
++
++int out1 = -1;
++int out2 = -1;
++
++int Get_Edge(int *edge1,int *edge2,int *index,int face_id,
++              int size, int id1, int id2)
++{
++      /*      Put the edge that is adjacent to face_id into edge1
++              and edge2. For each edge see if it is adjacent to
++              face_id. Id1 and id2 is the input edge, so see if 
++              the orientation is reversed, and save it in reversed.
++      */
++      register int x;
++      int reversed = -1;
++      BOOL set = FALSE;
++    
++     for (x=0; x< size; x++)
++      {
++              if (x == (size-1))
++              {
++                      if ((*(index) == id1) && (*(index+size-1)==id2))
++                      {
++                              if (set)
++                         return 1;
++                              reversed = 1;
++                      }
++                      else if ((*(index) == id2) && (*(index+size-1)==id1))
++                      {
++                              if (set)
++                         return 0;
++                              reversed = 0;
++                      }
++                              
++                      if (Look_Up(*(index),*(index+size-1),face_id))
++                      {
++                              if ( (out1 != -1) && ( (out1 == *(index)) || (out1 == *(index+size-1)) ) &&
++                       ( (out2 == *(index)) || (out2 == *(index+size-1)) ))
++                    {
++                         set = TRUE;
++                         *edge1 = *(index);
++                         *edge2 = *(index+size-1);
++                    }
++                              else if (out1 == -1)
++                    {
++                         set = TRUE;
++                         *edge1 = *(index);
++                         *edge2 = *(index+size-1);
++                    }
++                              if ((reversed != -1) && (set))  
++                                      return reversed;
++                      }
++              }               
++              else
++              {
++                      if ((*(index+x) == id1) && (*(index+x+1)==id2))
++                      {
++                              if (set)
++                         return 0;
++                              reversed = 0;
++                      }
++                      else if ((*(index+x) == id2) && (*(index+x+1)==id1))
++                      {
++                              if (set)
++                                      return 1;
++                              reversed = 1;
++                      }
++
++                      if (Look_Up(*(index+x),*(index+x+1),face_id))
++                      {
++                              if ( (out1 != -1) && ( (out1 == *(index+x)) || (out1 == *(index+x+1)) ) &&
++                         ((out2 == *(index+x)) || (out2 == *(index+x+1))))
++                    {
++                         set = TRUE;
++                         *edge1 = *(index+x);
++                         *edge2 = *(index+x+1);
++                    }
++                              else if (out1 == -1)
++                    {
++                         set = TRUE;
++                         *edge1 = *(index+x);
++                                   *edge2 = *(index+x + 1);
++                    }
++                              if ((reversed != -1) && (set))
++                         return reversed;
++                      }
++              }
++      }                       
++      if ((x == size) && (reversed != -1))
++      {
++              /*      Could not find the output edge */
++              printf("Error in the Lookup %d %d %d %d %d %d %d %d\n",face_id,id1,id2,reversed,*edge1,*edge2,out1,out2);
++              exit(0);
++      }
++      return reversed;
++}
++
++
++void Update_Face(int *next_bucket, int *min_face, int face_id, int *e1,
++                               int *e2,int temp1,int temp2,int *ties)
++{
++      /*      We have a face id that needs to be decremented.
++              We have to determine where it is in the structure,
++              so that we can decrement it.
++      */
++      /*      The number of adjacencies may have changed, so to locate
++              it may be a little tricky. However we know that the number
++              of adjacencies is less than or equal to the original number
++              of adjacencies,
++      */
++      int y,size,tally=0;
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++      PLISTINFO lpListInfo;
++      static int each_poly = 0;
++      BOOL there = FALSE;
++
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      /*      Check each edge of the face and tally the number of adjacent
++              polygons to this face. 
++      */                      
++      if ( temp != NULL )
++      {
++              /*      Size of the polygon */
++        size = temp->nPolSize;
++        /*  We did it already */
++        if (size == 1)
++            return;
++        for (y = 0; y< size; y++)
++         {
++                      /*      If we are doing partial triangulation, we must check
++                              to see whether the edge is still there in the polygon,
++                              since we might have done a portion of the polygon
++                              and saved the rest for later.
++                      */
++            if (y != (size-1))
++                {
++                              if( ((temp1 == *(temp->pPolygon+y)) && (temp2 ==*(temp->pPolygon+y+1)))
++                                      || ((temp2 == *(temp->pPolygon+y)) && (temp1 ==*(temp->pPolygon+y+1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                }
++                else
++                {
++                              if( ((temp1 == *(temp->pPolygon)) && (temp2 == *(temp->pPolygon+size-1)))
++                                      || ((temp2 == *(temp->pPolygon)) && (temp1 ==*(temp->pPolygon+size-1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                }
++       }
++              
++      if (!there)
++              /*      Original edge was already used, we cannot use this polygon */
++                      return;
++              
++      /*      We have a starting point to start our search to locate
++              this polygon. 
++      */
++
++      /*      Check to see if this polygon was done */
++      lpListInfo = Done(face_id,59,&y);
++
++      if (lpListInfo == NULL)
++              return;
++
++     /*  Was not done, but there is an error in the adjacency calculations */
++     if (y == 0)
++     {
++            printf("There is an error in finding the adjacencies\n");
++            exit(0);
++     }
++
++     /*       Now put the face in the proper bucket depending on tally. */
++      /*      First add it to the new bucket, then remove it from the old */
++      Add_Sgi_Adj(y-1,face_id);
++      RemoveList(array[y],lpListInfo);
++        
++     /*       Save it if it was the smallest seen so far since then
++              it will be the next face 
++              Here we will have different options depending on
++              what we want for resolving ties:
++                      1) First one we see we will use
++                      2) Random resolving
++                      3) Look ahead
++                      4) Alternating direction
++      */
++      /*      At a new strip */
++      if (*next_bucket == 60)
++              *ties = *ties + each_poly;
++      /*      Have a tie */
++      if (*next_bucket == (y-1))
++      {
++              Add_Ties(face_id);
++              each_poly++;
++      }
++      /*      At a new minimum */
++      if (*next_bucket > (y-1))
++      {
++              *next_bucket = y-1;
++              *min_face = face_id;
++              *e1 = temp1;
++              *e2 = temp2;
++              each_poly = 0;
++              Clear_Ties();
++              Add_Ties(face_id);
++      }
++     }
++}
++
++
++void Delete_Adj(int id1, int id2,int *next_bucket,int *min_face, 
++                       int current_face,int *e1,int *e2,int *ties)
++{
++      /*      Find the face that is adjacent to the edge and is not the
++              current face. Delete one adjacency from it. Save the min
++              adjacency seen so far.
++      */
++      register int count=0;
++      PF_EDGES temp = NULL;
++      ListHead *pListHead;
++      int next_face;
++
++      /*      Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++      /*      It could be a new edge that we created. So we can
++              exit, since there is not a face adjacent to it.
++      */
++              return;
++      while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          if (temp == NULL)
++                      /*      Was a new edge that was created and therefore
++                              does not have anything adjacent to it
++                      */
++                      return;
++     }
++      /*      Was not adjacent to anything else except itself */
++      if (temp->edge[2] == -1)
++              return;
++
++      /*      Was adjacent to something */
++      else
++      {
++              if (temp->edge[2] == current_face)
++                      next_face =  temp->edge[1];
++              else 
++                      next_face = temp->edge[2];
++      }
++      /*      We have the other face adjacent to this edge, it is 
++              next_face. Now we need to decrement this faces' adjacencies.
++      */
++      Update_Face(next_bucket, min_face, next_face,e1,e2,id1,id2,ties);
++}
++
++
++int Change_Face(int face_id,int in1,int in2,
++                               ListHead *pListHead, P_ADJACENCIES temp, BOOL no_check)
++{
++      /*      We are doing a partial triangulation and we need to
++              put the new face of triangle into the correct bucket
++      */
++      int input_adj,y;
++      
++      /*      Find the old number of adjacencies to this face,
++              so we know where to delete it from
++      */
++      y = Old_Adj(face_id);
++      
++      /*      Do we need to change the adjacency? Maybe the edge on the triangle
++              that was outputted was not adjacent to anything. We know if we
++              have to check by "check". We came out on the output edge
++              that we needed, then we know that the adjacencies will decrease
++              by exactly one.
++      */
++      if (!no_check)
++      {
++              input_adj = Number_Adj(in1,in2,face_id);
++              /*      If there weren't any then don't do anything */
++              if (input_adj == 0)
++                      return y;
++      }
++
++      RemoveList(pListHead,(PLISTINFO)temp);
++      /*      Before we had a quad with y adjacencies. The in edge
++              did not have an adjacency, since it was just deleted,
++              since we came in on it. The outedge must have an adjacency
++              otherwise we would have a bucket 0, and would not be in this
++              routine. Therefore the new adjacency must be y-1
++      */
++    
++    Add_Sgi_Adj(y-1,face_id);
++    return (y-1);
++}
++
++int Update_Adjacencies(int face_id, int *next_bucket, int *e1, int *e2,
++                                         int *ties)
++{
++      /*      Give the face with id face_id, we want to decrement
++              all the faces that are adjacent to it, since we will
++              be deleting face_id from the data structure.
++              We will return the face that has the least number
++              of adjacencies.
++      */
++      PF_FACES temp = NULL;
++      ListHead *pListHead;
++      int size,y,min_face = -1;
++      
++     *next_bucket = 60;
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      
++      if ( temp == NULL )
++      {
++              printf("The face was already deleted, there is an error\n");
++              exit(0);
++      }
++      
++      /*      Size of the polygon */
++      size = temp->nPolSize;
++      for (y = 0; y< size; y++)
++      {
++              if (y != (size-1))
++                      Delete_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),
++                              next_bucket,&min_face,face_id,e1,e2,ties);
++              else
++                      Delete_Adj(*(temp->pPolygon),*(temp->pPolygon+(size-1)),
++                              next_bucket,&min_face,face_id,e1,e2,ties);
++      }
++      return (min_face);
++}
++
++
++void Find_Adj_Tally(int id1, int id2,int *next_bucket,int *min_face, 
++                              int current_face,int *ties)
++{
++      /*      Find the face that is adjacent to the edge and is not the
++              current face. Save the min adjacency seen so far.
++      */
++      int size,each_poly=0,y,tally=0,count=0;
++      PF_EDGES temp = NULL;
++      PF_FACES temp2 = NULL;
++      ListHead *pListHead;
++      int next_face;
++      BOOL there = FALSE;
++
++    
++    /*        Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++     /*       This was a new edge that was created, so it is
++              adjacent to nothing.
++      */
++              return;
++
++      while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          if (temp == NULL)
++                      /*      This was a new edge that we created */
++                      return;
++     }
++      /*      Was not adjacent to anything else except itself */
++      if (temp->edge[2] == -1)
++              return;
++      else
++      {
++              if (temp->edge[2] == current_face)
++                      next_face =  temp->edge[1];
++              else 
++                      next_face = temp->edge[2];
++      }
++      /*      We have the other face adjacent to this edge, it is 
++              next_face. Find how many faces it is adjacent to.
++      */
++      pListHead = PolFaces[next_face];
++      temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      /*      Check each edge of the face and tally the number of adjacent 
++              polygons to this face. This will be the original number of
++              polygons adjacent to this polygon, we must then see if this
++              number has been decremented
++      */                      
++      if ( temp2 != NULL )
++      {
++              /*      Size of the polygon */
++              size = temp2->nPolSize;
++              /*  We did it already */
++          if (size == 1)
++            return;
++          for (y = 0; y< size; y++)
++              {
++                      /*      Make sure that the edge is still in the
++                              polygon and was not deleted, because if the edge was
++                              deleted, then we used it already.
++                      */
++                      if (y != (size-1))
++                      {
++                              if( ((id1 == *(temp2->pPolygon+y)) && (id2 ==*(temp2->pPolygon+y+1)))
++                                      || ((id2 == *(temp2->pPolygon+y)) && (id1 ==*(temp2->pPolygon+y+1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++                      else
++                      {               
++                              if( ((id1 == *(temp2->pPolygon)) && (id2 ==*(temp2->pPolygon+size-1)))
++                                      || ((id2 == *(temp2->pPolygon)) && (id1 ==*(temp2->pPolygon+size-1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++              }
++              
++              if (!there)
++                      /*      Edge already used and deleted from the polygon*/
++                      return;
++              
++              /*      See if the face was already deleted, and where
++                      it is if it was not
++              */
++              if (Done(next_face,size,&y) == NULL)
++                      return;
++              
++              /*      Save it if it was the smallest seen so far since then
++                      it will be the next face 
++                      Here we will have different options depending on
++                      what we want for resolving ties:
++                      1) First one we see we will use
++                      2) Random resolving
++                      3) Look ahead
++                      4) Alternating direction
++              */
++              
++              /*      At a new strip */
++              if (*next_bucket == 60)
++                      *ties = *ties + each_poly;
++              /*      Have a tie */
++              if (*next_bucket == (y-1))
++              {
++                      Add_Ties(next_face);
++                      each_poly++;
++              }
++              /*      At a new minimum */
++              if (*next_bucket > (y-1))
++              {
++                      *next_bucket = y-1;
++                      *min_face = next_face;
++                      each_poly = 0;
++                      Clear_Ties();
++                      Add_Ties(next_face);
++              }
++      }
++}
++
++
++int Min_Face_Adj(int face_id, int *next_bucket, int *ties)
++{
++      /*      Used for the Partial triangulation to find the next
++              face. It will return the minimum adjacency face id
++              found at this face.
++      */
++      PF_FACES temp = NULL;
++      ListHead *pListHead;
++      int size,y,min_face,test_face;
++      
++      *next_bucket = 60;
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      
++      if ( temp == NULL )
++      {
++              printf("The face was already deleted, there is an error\n");
++              exit(0);
++      }
++      
++      /*      Size of the polygon */
++      size = temp->nPolSize;
++      for (y = 0; y< size; y++)
++      {
++              if (y != (size-1))
++                      Find_Adj_Tally(*(temp->pPolygon+y),*(temp->pPolygon+y+1),
++                              next_bucket,&min_face,face_id,ties);
++              else
++                      Find_Adj_Tally(*(temp->pPolygon),*(temp->pPolygon+(size-1)),
++                              next_bucket,&min_face,face_id,ties);
++      }
++      /*    Maybe we can do better by triangulating the face, because
++          by triangulating the face we will go to a polygon of lesser
++          adjacencies
++    */
++    if (size == 4)
++    {
++         /*    Checking for a quad whether to do the whole polygon will
++               result in better performance because the triangles in the polygon
++               have less adjacencies
++         */
++         Check_In_Quad(face_id,&test_face);
++         if (*next_bucket > test_face)
++              /*    We can do better by going through the polygon */
++              min_face = face_id;
++    }
++
++    /*  We have a polygon with greater than 4 sides, check to see if going
++        inside is better than going outside the polygon for the output edge.
++    */
++    else
++    {
++        Check_In_Polygon(face_id,&test_face,size);
++        if (*next_bucket > test_face)
++            /*  We can do better by going through the polygon */
++            min_face = face_id;
++    }
++    
++    return (min_face);
++}
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6eb036cb403e61ffaa03ac8fea74280d4f576be0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++
++struct vert_struct {
++      VRDATA  x, y, z;        /* point coordinates */
++};
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..06adba7b5b4d1f77a0be1b73fcb80dbb5b3a0473
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,553 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: structex.c
++     This file contains routines that are used for various functions in
++     the local algorithm.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdlib.h>
++#include <string.h>
++#include "polverts.h"
++#include "ties.h"
++#include "outputex.h"
++#include "triangulatex.h"
++#include "sturctsex.h"
++#include "options.h"
++#include "common.h"
++#include "util.h"
++
++int out1Ex = -1;
++int out2Ex = -1;
++
++int Get_EdgeEx(int *edge1,int *edge2,int *index,int face_id,
++                      int size, int id1, int id2)
++{
++      /*      Put the edge that is adjacent to face_id into edge1
++              and edge2. For each edge see if it is adjacent to
++              face_id. Id1 and id2 is the input edge, so see if 
++              the orientation is reversed, and save it in reversed.
++      */
++      int x;
++      int reversed = -1;
++      BOOL set = FALSE;
++
++     for (x=0; x< size; x++)
++      {
++              if (x == (size-1))
++              {
++                      if ((*(index) == id1) && (*(index+size-1)==id2))
++                      {
++                              if (set)
++                         return 1;
++                              reversed = 1;
++                      }
++                      else if ((*(index) == id2) && (*(index+size-1)==id1))
++                      {
++                              if (set)
++                         return 0;
++                              reversed = 0;
++                      }
++                              
++                      if (Look_Up(*(index),*(index+size-1),face_id))
++                      {
++                              if ( (out1Ex != -1) && ( (out1Ex == *(index)) || (out1Ex == *(index+size-1)) ) &&
++                       ( (out2Ex == *(index)) || (out2Ex == *(index+size-1)) ))
++                    {
++                         set = TRUE;
++                         *edge1 = *(index);
++                         *edge2 = *(index+size-1);
++                    }
++                              else if (out1Ex == -1)
++                    {
++                         set = TRUE;
++                         *edge1 = *(index);
++                         *edge2 = *(index+size-1);
++                    }
++                              if ((reversed != -1) && (set))  
++                                      return reversed;
++                      }
++              }               
++              else
++              {
++                      if ((*(index+x) == id1) && (*(index+x+1)==id2))
++                      {
++                              if (set)
++                         return 0;
++                              reversed = 0;
++                      }
++                      else if ((*(index+x) == id2) && (*(index+x+1)==id1))
++                      {
++                              if (set)
++                                      return 1;
++                              reversed = 1;
++                      }
++
++                      if (Look_Up(*(index+x),*(index+x+1),face_id))
++                      {
++                              if ( (out1Ex != -1) && ( (out1Ex == *(index+x)) || (out1Ex == *(index+x+1)) ) &&
++                        ((out2Ex == *(index+x)) || (out2Ex == *(index+x+1))))
++                    {
++                         set = TRUE;
++                         *edge1 = *(index+x);
++                         *edge2 = *(index+x+1);
++                    }
++                              else if (out1Ex == -1)
++                    {
++                         set = TRUE;
++                         *edge1 = *(index+x);
++                                   *edge2 = *(index+x + 1);
++                    }
++                              if ((reversed != -1) && (set))
++                         return reversed;
++                      }
++              }
++      }                       
++      if ((x == size) && (reversed != -1))
++      {
++              /*      Could not find the output edge */
++              printf("Error in the Lookup %d %d %d %d %d %d %d %d\n",face_id,id1,id2,reversed,*edge1,*edge2,out1Ex,out2Ex);
++              exit(0);
++      }
++      return reversed;
++}
++
++
++void Update_FaceEx(int *next_bucket, int *min_face, int face_id, int *e1,
++                          int *e2,int temp1,int temp2,int *ties)
++{
++      /*      We have a face id that needs to be decremented.
++              We have to determine where it is in the structure,
++              so that we can decrement it.
++      */
++      /*      The number of adjacencies may have changed, so to locate
++              it may be a little tricky. However we know that the number
++              of adjacencies is less than or equal to the original number
++              of adjacencies,
++      */
++      int y,size,tally=0;
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++      PLISTINFO lpListInfo;
++      static int each_poly = 0;
++      BOOL there = FALSE;
++
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      /*      Check each edge of the face and tally the number of adjacent
++              polygons to this face. 
++      */                      
++      if ( temp != NULL )
++      {
++              /*      Size of the polygon */
++        size = temp->nPolSize;
++        for (y = 0; y< size; y++)
++              {
++                      /*      If we are doing partial triangulation, we must check
++                              to see whether the edge is still there in the polygon,
++                              since we might have done a portion of the polygon
++                              and saved the rest for later.
++                      */
++               if (y != (size-1))
++                      {
++                              if( ((temp1 == *(temp->pPolygon+y)) && (temp2 ==*(temp->pPolygon+y+1)))
++                                      || ((temp2 == *(temp->pPolygon+y)) && (temp1 ==*(temp->pPolygon+y+1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++                      else
++                      {
++                              if( ((temp1 == *(temp->pPolygon)) && (temp2 == *(temp->pPolygon+size-1)))
++                                      || ((temp2 == *(temp->pPolygon)) && (temp1 ==*(temp->pPolygon+size-1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++              }
++              
++          if (!there)
++              /*      Original edge was already used, we cannot use this polygon */
++                      return;
++              
++              /*      We have a starting point to start our search to locate
++                      this polygon. 
++              */
++
++              /*      Check to see if this polygon was done */
++              lpListInfo = Done(face_id,59,&y);
++
++              if (lpListInfo == NULL)
++                      return;
++
++          /*  Was not done, but there is an error in the adjacency calculations */
++          /*     If more than one edge is adj to it then maybe it was not updated */
++          if (y == 0)
++            return;
++                      
++              /*      Now put the face in the proper bucket depending on tally. */
++              /*      First add it to the new bucket, then remove it from the old */
++              Add_Sgi_Adj(y-1,face_id);
++              RemoveList(array[y],lpListInfo);
++        
++          /*  Save it if it was the smallest seen so far since then
++                      it will be the next face 
++                      Here we will have different options depending on
++                      what we want for resolving ties:
++                      1) First one we see we will use
++                      2) Random resolving
++                      3) Look ahead
++                      4) Alternating direction
++              */
++              /*      At a new strip */
++              if (*next_bucket == 60)
++                      *ties = *ties + each_poly;
++              /*      Have a tie */
++              if (*next_bucket == (y-1))
++              {
++                      Add_Ties(face_id);
++                      each_poly++;
++              }
++              /*      At a new minimum */
++              if (*next_bucket > (y-1))
++              {
++                      *next_bucket = y-1;
++                      *min_face = face_id;
++                      *e1 = temp1;
++                      *e2 = temp2;
++                      each_poly = 0;
++                      Clear_Ties();
++                      Add_Ties(face_id);
++              }
++      }
++}
++
++
++void Delete_AdjEx(int id1, int id2,int *next_bucket,int *min_face, 
++                              int current_face,int *e1,int *e2,int *ties)
++{
++      /*      Find the face that is adjacent to the edge and is not the
++              current face. Delete one adjacency from it. Save the min
++              adjacency seen so far.
++      */
++      register int count=0;
++      PF_EDGES temp = NULL;
++      ListHead *pListHead;
++      int next_face;
++
++      /*      Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++      /*      It could be a new edge that we created. So we can
++              exit, since there is not a face adjacent to it.
++      */
++              return;
++     while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          if (temp == NULL)
++                      /*      Was a new edge that was created and therefore
++                              does not have anything adjacent to it
++                      */
++                      return;
++    }
++      /*      Was not adjacent to anything else except itself */
++    if (temp->edge[2] == -1)
++              return;
++
++    /*        Was adjacent to something */
++    else
++    {
++              if (temp->edge[2] == current_face)
++                      next_face =  temp->edge[1];
++              else 
++                      next_face = temp->edge[2];
++      }
++      /*      We have the other face adjacent to this edge, it is 
++              next_face. Now we need to decrement this faces' adjacencies.
++      */
++      Update_FaceEx(next_bucket, min_face, next_face,e1,e2,id1,id2,ties);
++}
++
++int Change_FaceEx(int face_id,int in1,int in2,
++                               ListHead *pListHead, P_ADJACENCIES temp, BOOL no_check)
++{
++      /*      We are doing a partial triangulation and we need to
++              put the new face of triangle into the correct bucket
++      */
++      int input_adj,y;
++     P_ADJACENCIES pfNode,lpListInfo;
++      
++     /*       Find the old number of adjacencies to this face,
++              so we know where to delete it from
++      */
++      y = Old_Adj(face_id);
++      pListHead = array[y];
++
++     pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++      if ( pfNode )
++              pfNode->face_id = face_id;
++      lpListInfo = (P_ADJACENCIES) (SearchList(array[y], pfNode,
++                  (int (*)(void *,void *)) (Compare)));
++      if (lpListInfo == NULL)
++      {
++              printf("There is an error finding the next polygon3 %d\n",face_id);
++              exit(0);
++      }
++
++     /*       Do we need to change the adjacency? Maybe the edge on the triangle
++              that was outputted was not adjacent to anything. We know if we
++              have to check by "check". We came out on the output edge
++              that we needed, then we know that the adjacencies will decrease
++              by exactly one.
++      */
++      if (!no_check)
++      {
++              input_adj = Number_Adj(in1,in2,face_id);
++              /*      If there weren't any then don't do anything */
++              if (input_adj == 0)
++                      return y;
++      }
++     
++      RemoveList(pListHead,(PLISTINFO)/*(temp*/lpListInfo);
++      /*      Before we had a quad with y adjacencies. The in edge
++              did not have an adjacency, since it was just deleted,
++              since we came in on it. The outedge must have an adjacency
++              otherwise we would have a bucket 0, and would not be in this
++              routine. Therefore the new adjacency must be y-1
++      */
++    
++    Add_Sgi_Adj(y-1,face_id);
++    return (y-1);
++}
++
++int Update_AdjacenciesEx(int face_id, int *next_bucket, int *e1, int *e2,
++                                      int *ties)
++{
++      /*      Give the face with id face_id, we want to decrement
++              all the faces that are adjacent to it, since we will
++              be deleting face_id from the data structure.
++              We will return the face that has the least number
++              of adjacencies.
++      */
++      PF_FACES temp = NULL;
++      ListHead *pListHead;
++      int size,y,min_face = -1;
++      
++     *next_bucket = 60;
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      
++      if ( temp == NULL )
++      {
++              printf("The face was already deleted, there is an error\n");
++              exit(0);
++      }
++      
++      /*      Size of the polygon */
++      size = temp->nPolSize;
++      for (y = 0; y< size; y++)
++      {
++              if (y != (size-1))
++                      Delete_AdjEx(*(temp->pPolygon+y),*(temp->pPolygon+y+1),
++                              next_bucket,&min_face,face_id,e1,e2,ties);
++              else
++                      Delete_AdjEx(*(temp->pPolygon),*(temp->pPolygon+(size-1)),
++                              next_bucket,&min_face,face_id,e1,e2,ties);
++      }
++      return (min_face);
++}
++
++
++
++void Find_Adj_TallyEx(int id1, int id2,int *next_bucket,int *min_face, 
++                             int current_face,int *ties)
++{
++      /*      Find the face that is adjacent to the edge and is not the
++              current face. Save the min adjacency seen so far.
++      */
++      int size,each_poly=0,y,tally=0,count=0;
++      PF_EDGES temp = NULL;
++      PF_FACES temp2 = NULL;
++      ListHead *pListHead;
++      int next_face;
++      BOOL there = FALSE;
++
++    
++    /*        Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++     /*       This was a new edge that was created, so it is
++              adjacent to nothing.
++      */
++              return;
++      while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          if (temp == NULL)
++                      /*      This was a new edge that we created */
++                      return;
++     }
++      /*      Was not adjacent to anything else except itself */
++      if (temp->edge[2] == -1)
++              return;
++      else
++      {
++              if (temp->edge[2] == current_face)
++                      next_face =  temp->edge[1];
++              else 
++                      next_face = temp->edge[2];
++      }
++      /*      We have the other face adjacent to this edge, it is 
++              next_face. Find how many faces it is adjacent to.
++      */
++      pListHead = PolFaces[next_face];
++      temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      /*      Check each edge of the face and tally the number of adjacent 
++              polygons to this face. This will be the original number of
++              polygons adjacent to this polygon, we must then see if this
++              number has been decremented
++      */                      
++      if ( temp2 != NULL )
++      {
++              /*      Size of the polygon */
++              size = temp2->nPolSize;
++              for (y = 0; y< size; y++)
++              {
++                      /*      Make sure that the edge is still in the
++                              polygon and was not deleted, because if the edge was
++                              deleted, then we used it already.
++                      */
++                      if (y != (size-1))
++                      {
++                              if( ((id1 == *(temp2->pPolygon+y)) && (id2 ==*(temp2->pPolygon+y+1)))
++                                      || ((id2 == *(temp2->pPolygon+y)) && (id1 ==*(temp2->pPolygon+y+1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++                      else
++                      {               
++                              if( ((id1 == *(temp2->pPolygon)) && (id2 ==*(temp2->pPolygon+size-1)))
++                                      || ((id2 == *(temp2->pPolygon)) && (id1 ==*(temp2->pPolygon+size-1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++              }
++              
++              if (!there)
++                      /*      Edge already used and deleted from the polygon*/
++                      return;
++              
++              /*      See if the face was already deleted, and where
++                      it is if it was not
++              */
++              if (Done(next_face,size,&y) == NULL)
++                      return;
++              
++              /*      Save it if it was the smallest seen so far since then
++                      it will be the next face 
++                      Here we will have different options depending on
++                      what we want for resolving ties:
++                      1) First one we see we will use
++                      2) Random resolving
++                      3) Look ahead
++                      4) Alternating direction
++              */
++                                      
++              /*      At a new strip */
++              if (*next_bucket == 60)
++                      *ties = *ties + each_poly;
++              /*      Have a tie */
++              if (*next_bucket == (y-1))
++              {
++                      Add_Ties(next_face);
++                      each_poly++;
++              }
++              /*      At a new minimum */
++              if (*next_bucket > (y-1))
++              {
++                      *next_bucket = y-1;
++                      *min_face = next_face;
++                      each_poly = 0;
++                      Clear_Ties();
++                      Add_Ties(next_face);
++              }
++      }
++}
++
++
++int Min_Face_AdjEx(int face_id, int *next_bucket, int *ties)
++{
++      /*      Used for the Partial triangulation to find the next
++              face. It will return the minimum adjacency face id
++              found at this face.
++      */
++      PF_FACES temp = NULL;
++      ListHead *pListHead;
++      int size,y,min_face,test_face;
++      
++      *next_bucket = 60;
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      
++      if ( temp == NULL )
++      {
++              printf("The face was already deleted, there is an error\n");
++              exit(0);
++      }
++      
++      /*      Size of the polygon */
++      size = temp->nPolSize;
++      for (y = 0; y< size; y++)
++      {
++              if (y != (size-1))
++                      Find_Adj_TallyEx(*(temp->pPolygon+y),*(temp->pPolygon+y+1),
++                              next_bucket,&min_face,face_id,ties);
++              else
++                      Find_Adj_TallyEx(*(temp->pPolygon),*(temp->pPolygon+(size-1)),
++                              next_bucket,&min_face,face_id,ties);
++      }
++      /*    Maybe we can do better by triangulating the face, because
++          by triangulating the face we will go to a polygon of lesser
++          adjacencies
++    */
++    if (size == 4)
++    {
++         /*    Checking for a quad whether to do the whole polygon will
++               result in better performance because the triangles in the polygon
++               have less adjacencies
++         */
++         Check_In_Quad(face_id,&test_face);
++         if (*next_bucket > test_face)
++              /*    We can do better by going through the polygon */
++              min_face = face_id;
++    }
++
++    /*  We have a polygon with greater than 4 sides, check to see if going
++        inside is better than going outside the polygon for the output edge.
++    */
++    else
++    {
++        Check_In_Polygon(face_id,&test_face,size);
++        if (*next_bucket > test_face)
++            /*  We can do better by going through the polygon */
++            min_face = face_id;
++    }
++    
++    return (min_face);
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..07a2bbf976e1587fa20b05d0d5d0a5807c2ae5e5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,31 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: sturcts.h
++-----------------------------------------------------------------------*/
++
++#define EVEN(x) (((x) & 1) == 0)
++
++BOOL Get_Edge();
++void add_vert_id();
++void Update_Face();
++int Min_Adj();
++int Min_Face_Adj();
++int Change_Face();
++void Delete_Adj();
++int Update_Adjacencies();
++int Get_Output_Edge();
++int Find_Face();
++
++
++
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5502283061b41307d181930718e0427c9adcef58
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,28 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE:sturctsex.h
++-----------------------------------------------------------------------*/
++
++#define EVEN(x) (((x) & 1) == 0)
++
++BOOL Get_EdgeEx();
++void add_vert_idEx();
++void Update_FaceEx();
++int Min_Face_AdjEx();
++int Change_FaceEx();
++void Delete_AdjEx();
++int Number_AdjEx();
++int Update_AdjacenciesEx();
++
++
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e1a64545c600efe929dd72bcfe460db6ede6ab16
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,304 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*    STRIPE: ties.c
++     This file will contain all the routines used to determine the next face if there
++      is a tie
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdlib.h>
++#include "polverts.h"
++#include "ties.h"
++#include "sturctsex.h"
++#include "triangulatex.h"
++#include "options.h"
++#include "common.h"
++#include "util.h"
++
++#define MAX_TIE 60
++int ties_array[60];
++int last = 0;
++
++void Clear_Ties()
++{
++      /*      Clear the buffer, because we do not have the tie
++              any more that we had before */
++      last = 0;
++}
++
++void Add_Ties(int id)
++{
++      /*      We have a tie to add to the buffer */
++      ties_array[last++] = id;
++}
++
++int Alternate_Tie()
++{
++      /*      Alternate in what we choose to break the tie 
++              We are just alternating between the first and
++              second thing that we found
++      */
++      static int x = 0;
++      register int t;
++      
++      t = ties_array[x];
++      x++;
++      if (x == 2)
++              x = 0;
++      return t;
++}
++
++int Random_Tie()
++{
++      /*      Randomly choose the next face with which
++              to break the tie
++      */
++      register int num;
++
++      num = rand();
++      while (num >= last)
++              num = num/20;
++      return (ties_array[num]);
++}
++
++int Look_Ahead(int id)
++{
++      /*      Look ahead at this face and save the minimum
++              adjacency of all the faces that are adjacent to
++              this face.
++      */
++      return Min_Adj(id);
++}
++
++int Random_Look(int id[],int count)
++{
++      /*      We had a tie within a tie in the lookahead, 
++              break it randomly 
++      */
++      register int num;
++
++      num = rand();
++      while (num >= count)
++              num = num/20;
++      return (id[num]);
++}
++
++
++int Look_Ahead_Tie()
++{
++      /*      Look ahead and find the face to go to that
++              will give the least number of adjacencies
++      */
++      int id[60],t,x,f=0,min = 60;
++
++      for (x = 0; x < last; x++)
++      {
++              t = Look_Ahead(ties_array[x]);
++              /*      We have a tie */
++              if (t == min)
++                      id[f++] = ties_array[x];
++              if (t < min)
++              {
++                      f = 0;
++                      min = t;
++                      id[f++] = ties_array[x];
++              }
++      }
++      /*      No tie within the tie */
++      if ( f == 1)
++              return id[0];
++      /*      Or ties, but we are at the end of strips */
++      if (min == 0)
++              return id[0];
++      return (Random_Look(id,f));
++}
++
++
++int Sequential_Tri(int *index)
++{
++    /*  We have a triangle and need to break the ties at it.
++        We will choose the edge that is sequential. There
++        is definitely one since we know we have a triangle
++        and that there is a tie and there are only 2 edges
++        for the tie.
++    */
++    int reversed, e1,e2,e3,output1,output2,output3,output4;
++
++    /*  e2 and e3 are the input edge to the triangle */
++    Last_Edge(&e1,&e2,&e3,0);
++    
++    if ((e2 == 0) && (e3 == 0))
++        /*  Starting the strip, don't need to do this */
++        return ties_array[0];
++
++    /*  For the 2 ties find the edge adjacent to face id */
++    reversed = Get_EdgeEx(&output1,&output2,index,ties_array[0],3,0,0);
++    reversed = Get_EdgeEx(&output3,&output4,index,ties_array[1],3,0,0);
++
++    if ((output1 == e3) || (output2 == e3))
++        return ties_array[0];
++    if ((output3 == e3) || (output4 == e3))
++        return ties_array[1];
++    printf("There is an error trying to break sequential triangle \n");
++}
++
++int Sequential_Quad(int *index,       int triangulate)
++{
++    /*  We have a quad that need to break its ties, we will try
++        and choose a side that is sequential, otherwise use lookahead
++    */
++    int reversed,output1,output2,x,e1,e2,e3;
++
++    /*  e2 and e3 are the input edge to the quad */
++    Last_Edge(&e1,&e2,&e3,0);
++
++    /*  No input edge */
++    if ((e2 == 0) && (e3 == 0))
++        return ties_array[0];
++
++      /*  Go through the ties and see if there is a sequential one */
++    for (x = 0; x < last; x++)
++      {
++        reversed = Get_EdgeEx(&output1,&output2,index,ties_array[x],4,0,0);
++        /*  Partial and whole triangulation will have different requirements */
++        if (((output1 == e3) || (output2 == e3)) && (triangulate == PARTIAL))
++            return ties_array[x];
++        if (((output1 != e3) && (output1 != e2) &&
++                (output2 != e3) && (output2 != e2)))
++            return ties_array[x];
++    }
++    /*  There was not a tie that was sequential */
++      return Look_Ahead_Tie();
++}
++
++void Whole_Output(int in1,int in2, int *index, int size, int *out1, int *out2)
++{
++    /*  Used to sequentially break ties in the whole triangulation for polygons
++        greater than 4 sides. We will find the output edge that is good
++        for sequential triangulation.
++    */
++
++    int half;
++    
++    /*  Put the input edge first in the list */
++    Rearrange_IndexEx(index,size);
++
++    if (!(EVEN(size)))
++    {
++        if (*(index) == in1)
++            half = size/2 ;
++        else
++            half = size/2 +1;
++    }
++    else
++        half = size/2;
++
++    *out1 = *(index+half);
++    *out2 = *(index+half+1);
++}
++
++int Sequential_Poly(int size, int *index, int triangulate)
++{
++    /*  We have a polygon of greater than 4 sides and wish to break the
++        tie in the most sequential manner.
++    */
++
++    int x,reversed,output1,output2,e1,e2,e3,saved1=-1,saved2=-1,output3,output4;
++    
++    /*  e2 and e3 are the input edge to the quad */
++    Last_Edge(&e1,&e2,&e3,0);
++
++    /*  If we are using whole, find the output edge that is sequential */
++    if (triangulate == WHOLE)
++        Whole_Output(e2,e3,index,size,&output3,&output4);
++
++    /*  No input edge */
++    if ((e2 == 0) && (e3 == 0))
++        return ties_array[0];
++    
++    for (x = 0; x < last ; x++)
++    {
++        reversed = Get_EdgeEx(&output1,&output2,index,ties_array[x],size,0,0);
++        /*  Partial that can be removed in just one triangle */
++        if (((output1 == e3) || (output2 == e3)) && (triangulate == PARTIAL))
++            saved1 = ties_array[x];
++        /*  Partial removed in more than one triangle */
++        if ((output1 != e3) && (output1 != e2) && (output2 != e3) && (output2 != e2) &&
++            (triangulate == PARTIAL) && (saved2 != -1))
++            saved2 = ties_array[x];
++        /*  Whole is not so easy, since the whole polygon must be done. Given
++            an input edge there is only one way to come out, approximately half
++            way around the polygon.
++        */
++        if (((output1 == output3) && (output2 == output4)) ||
++            ((output1 == output4) && (output2 == output3)) &&
++            (triangulate == WHOLE))
++            return ties_array[x];
++    }
++    
++    if (saved1 != -1)
++        return saved1;
++    if (saved2 != -1)
++        return saved2;
++    
++    /*  There was not a tie that was sequential */
++    return Look_Ahead_Tie();
++}
++
++int Sequential_Tie(int face_id,int triangulate)
++{
++    /*  Break the tie by choosing the face that will
++        not give us a swap and is sequential. If there
++        is not one, then do the lookahead to break the
++        tie.
++    */
++    /*  Separate into 3 cases for simplicity, if the current
++        polygon has 3 sides, 4 sides or if the sides were 
++        greater. We can do the smaller cases faster, so that
++        is why I separated the cases.
++    */
++
++     ListHead *pListFace;
++      PF_FACES face;
++
++    /*        Get the polygon with id face_id */
++      pListFace  = PolFaces[face_id];
++      face = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
++
++     if (face->nPolSize == 3)
++        return(Sequential_Tri(face->pPolygon));
++     if (face->nPolSize == 4)
++        return(Sequential_Quad(face->pPolygon,triangulate));
++     else
++        return(Sequential_Poly(face->nPolSize,face->pPolygon,triangulate));
++
++}
++
++int Get_Next_Face(int t, int face_id, int triangulate)
++{
++      /*      Get the next face depending on what
++              the user specified
++      */
++      
++      /*      Did not have a tie, don't do anything */
++      if (last == 1)
++              return(ties_array[0]);
++      if (t == RANDOM)
++              return Random_Tie();
++      if (t == ALTERNATE)
++              return Alternate_Tie();
++      if (t == LOOK)
++              return Look_Ahead_Tie();
++     if (t == SEQUENTIAL)
++        return Sequential_Tie(face_id,triangulate);
++
++      printf("Illegal option specified for ties, using first \n");
++     return (ties_array[0]);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..97e05176598c01842a16347e5b3a407dcefde789
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: ties.h
++-----------------------------------------------------------------------*/
++
++void Clear_Ties();
++void Add_Ties();
++int Get_Next_Face();
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..de612119fedddc61e84dd3bd453742d6de032220
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,23 @@@
++
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: triangulate.h
++-----------------------------------------------------------------------*/
++
++void Blind_Triangulate();
++void Non_Blind_Triangulate();
++int Adjacent();
++void Delete_From_List();
++void Triangulate_Polygon();
++void Rearrange_Index();
++void Find_Local_Strips();
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1710f0182efaa168372863c892e0e64f147187da
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,23 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: triangulatex.h
++-----------------------------------------------------------------------*/
++
++enum swap_type
++{ ON, OFF};
++
++void SGI_StripEx();
++void Blind_TriangulateEx();
++void Non_Blind_TriangulateEx();
++int AdjacentEx();
++void Delete_From_ListEx();
++void Triangulate_PolygonEx();
++void Rearrange_IndexEx();
++void Find_StripsEx();
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f17fe5f7cd64e08c94975499833d7bcd81a2e914
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,272 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: util.c
++     This file contains routines that are used for various functions
++*/
++/*---------------------------------------------------------------------*/
++
++
++#include <stdlib.h>
++#include "polverts.h"
++
++void switch_lower (int *x, int *y)
++{
++      register int temp;
++      
++      /*      Put lower value in x */
++      if (*y < *x)
++      {
++              temp = *x;
++              *x = *y;
++              *y = temp;
++      }
++}
++
++BOOL member(int x , int id1, int id2, int id3)
++{
++    /*  Is x in the triangle specified by id1,id2,id3 */
++    if ((x != id1) && (x != id2) && (x != id3))
++      return FALSE;
++    return TRUE;
++}
++
++
++int Compare (P_ADJACENCIES node1, P_ADJACENCIES node2)
++{
++      /*      This will only return whether 2 adjacency nodes
++              are equivalent.                                                           
++      */
++      if (node1->face_id == node2->face_id)
++              return TRUE;
++      else
++              return FALSE;
++}
++
++
++BOOL Exist(int face_id, int id1, int id2)
++{
++      /*      Does the edge specified by id1 and id2 exist in this
++              face currently? Maybe we deleted in partial triangulation
++      */
++      ListHead *pListHead;
++      PF_FACES temp;
++      register int x,size;
++      BOOL a=FALSE,b =FALSE; 
++
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      size = temp->nPolSize;
++      for (x=0; x<size; x++)
++      {
++              if (*(temp->pPolygon+x) == id1)
++                      a = TRUE;
++              if (*(temp->pPolygon+x) == id2)
++                      b = TRUE;
++              if (a && b)
++                      return TRUE;
++      }
++      return FALSE;
++}
++
++int Get_Next_Id(int *index,int e3, int size)
++{
++    /*  Return the id following e3 in the list of vertices */
++
++    register int x;
++
++    for (x = 0; x< size; x++)
++    {
++        if ((*(index+x) == e3) && (x != (size-1)))
++            return *(index+x+1);
++        else if (*(index+x) == e3)
++            return *(index);
++    }
++    printf("There is an error in the next id\n");
++    exit(0);
++}
++
++int Different (int id1,int id2,int id3,int id4,int id5, int id6, int *x, int *y)
++{
++    /*    Find the vertex in the first 3 numbers that does not exist in 
++           the last three numbers
++    */
++    if ((id1 != id4) && (id1 != id5) && (id1 != id6))
++    {
++      *x = id2;
++      *y = id3;
++      return id1;
++    }
++    if ((id2 != id4) && (id2 != id5) && (id2 != id6))
++    {
++      *x = id1;
++      *y = id3;
++      return id2;
++    }
++    if ((id3 != id4) && (id3 != id5) && (id3 != id6))
++    {
++      *x = id1;
++      *y = id2;
++      return id3;
++    }
++    
++    /*  Because there are degeneracies in the data, this might occur */
++    *x = id5;
++    *y = id6;
++    return id4;
++}
++
++int Return_Other(int *index,int e1,int e2)
++{
++      /*   We have a triangle and want to know the third vertex of it */
++      register int x;
++
++      for (x=0;x<3;x++)
++      {
++              if ((*(index+x) != e1) && (*(index+x) != e2))
++                      return *(index+x);
++      }
++     /*   If there is a degenerate triangle return arbitrary */
++     return e1;
++}
++
++int Get_Other_Vertex(int id1,int id2,int id3,int *index)
++{
++      /*      We have a list index of 4 numbers and we wish to
++          return the number that is not id1,id2 or id3
++      */
++      register int x;
++
++      for (x=0; x<4; x++)
++      {
++              if ((*(index+x) != id1) && (*(index+x) != id2) &&
++                      (*(index+x) != id3))
++                      return *(index+x);
++      }
++      /*   If there is some sort of degeneracy this might occur,
++          return arbitrary 
++     */
++     if (x==4)
++          return id1;
++}
++
++
++PLISTINFO Done(int face_id, int size, int *bucket)
++{
++      /*      Check to see whether the polygon with face_id was used
++              already, return NULL if it was, otherwise return a pointer to the face.
++      */
++      P_ADJACENCIES pfNode;
++      register int y;
++      PLISTINFO lpListInfo;
++      
++      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++      if ( pfNode )
++              pfNode->face_id = face_id;
++              
++      for (y=size; ; y--)
++      {
++              lpListInfo = SearchList(array[y], pfNode,
++                      (int (*)(void *,void *)) (Compare));
++              if (lpListInfo != NULL)
++              {
++                      *bucket = y;
++                      return lpListInfo;
++              }
++              if (y == 0)
++              /*      This adjacent face was done already */
++                      return lpListInfo;
++      }
++      free (pfNode);
++}
++
++void Output_Edge(int *index,int e2,int e3,int *output1,int *output2)
++{
++    /*  Given a quad and an input edge return the other 2 vertices of the
++        quad.
++    */
++    
++    *output1 = -1;
++    *output2 = -1;
++
++    if ((*(index) != e2) && (*(index) != e3))
++        *output1 = *(index);
++
++    if ((*(index+1) != e2) && (*(index+1) != e3))
++    {
++        if (*output1 == -1)
++            *output1 = *(index+1);
++        else
++        {
++            *output2 = *(index+1);
++            return;
++        }
++    }
++
++    if ((*(index+2) != e2) && (*(index+2) != e3))
++    {
++        if (*output1 == -1)
++            *output1 = *(index+2);
++        else
++        {
++            *output2 = *(index+2);
++            return;
++        }
++    }
++
++    *output2 = *(index+3);
++}
++
++
++void First_Edge(int *id1,int *id2, int *id3)
++{
++    /*  Get the first triangle in the strip we just found, we will use this to
++         try to extend backwards in the strip
++    */
++
++    ListHead *pListHead;
++    register int num;
++    P_STRIPS temp1,temp2,temp3;
++       
++    pListHead = strips[0];
++    num = NumOnList(pListHead);
++     
++    /*    Did not have a strip */
++    if (num < 3)
++         return;
++        
++    temp1 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 0);
++    temp2 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 1);
++    temp3 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 2);
++    *id1 = temp1->face_id;
++    *id2 = temp2->face_id;
++    *id3 = temp3->face_id;
++ 
++}
++
++void Last_Edge(int *id1, int *id2, int *id3, BOOL save)
++{
++      /*   We need the last edge that we had  */
++      static int v1, v2, v3;
++
++      if (save)
++      {
++              v1 = *id1;
++              v2 = *id2;
++              v3 = *id3;
++      }
++      else
++      {
++              *id1 = v1;
++              *id2 = v2;
++              *id3 = v3;
++      }
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2b43a4d35b26a8432a5f820da84e68029af1ff35
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,24 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: util.h
++-----------------------------------------------------------------------*/
++
++void switch_lower ();
++int Compare ();
++BOOL Exist();
++int Get_Next_Id();
++int Different();
++int Return_Other();
++int Get_Other_Vertex();
++PLISTINFO Done();
++void Output_Edge();
++void Last_Edge();
++void First_Edge();
++BOOL member();
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ac0280b8a0583771998c908407abae236394f50c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,27 @@@
++bin_PROGRAMS = strips
++
++strips_SOURCES = \
++      add.c add.h \
++      bands.c \
++      common.c common.h \
++      extend.h \
++      free.c free.h \
++      global.h \
++      init.c init.h \
++      local.c local.h \
++      newpolve.c \
++      options.c options.h \
++      output.c output.h \
++      outputex.c outputex.h \
++      partial.c partial.h \
++      polverts.h polyvertsex.h \
++      queue.c queue.h \
++      sgi_triang.c sgi_triangex.c \
++      struct.c \
++      structex.c \
++      sturcts.h sturctsex.h \
++      ties.c ties.h \
++      triangulate.h triangulatex.h \
++      util.c util.h
++
++strips_LDADD = $(base_LIBS)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ef6e673d81ad34790aaaa6830d0ebddb82871e85
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,384 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: add.c
++     This file contains the procedure code that will add information
++     to our data structures.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++#include <string.h>
++#include "global.h"
++#include "queue.h"
++#include "polverts.h"
++#include "triangulate.h"
++#include "ties.h"
++#include "outputex.h"
++#include "options.h"
++#include "local.h"
++
++BOOL new_vertex(double difference, int id1,int id2,
++                struct vert_struct *n)
++{
++  /*   Is the difference between id1 and id2 (2 normal vertices that
++       mapped to the same vertex) greater than the
++       threshold that was specified?
++  */
++  struct vert_struct *pn1,*pn2;
++  double dot_product;
++  double distance1, distance2,distance;
++  double rad;
++  char arg1[100];
++  char arg2[100];
++
++  pn1 = n + id1;
++  pn2 = n + id2;
++ 
++  dot_product = ((pn1->x) * (pn2->x)) +
++                ((pn1->y) * (pn2->y)) +
++                ((pn1->z) * (pn2->z));
++  /*   Get the absolute value */
++  if (dot_product < 0)
++    dot_product = dot_product * -1;
++
++  distance1 = sqrt( (pn1->x * pn1->x) +
++                    (pn1->y * pn1->y) +
++                    (pn1->z * pn1->z) );
++  distance2 = sqrt( (pn2->x * pn2->x) +
++                    (pn2->y * pn2->y) +
++                    (pn2->z * pn2->z) );
++  distance = distance1 * distance2;
++
++  rad = acos((double)dot_product/(double)distance);
++  /* convert to degrees */
++  rad = (180 * rad)/PI;
++    
++  if ( rad <= difference)
++    return FALSE;
++     
++  /*   double checking because of imprecision with floating
++       point acos function
++  */
++  sprintf( arg1,"%.5f", rad );
++  sprintf( arg2,"%.5f", difference );
++  if ( strcmp( arg1, arg2 ) <=0 )
++    return( FALSE );
++  if ( rad <= difference)
++    return FALSE;
++  else 
++    return TRUE;
++}
++
++BOOL Check_VN(int vertex,int normal, struct vert_added *added)
++{
++  /*   Check to see if we already added this vertex and normal */
++  register int x,n;
++
++  n = (added+vertex)->num;
++  for (x = 0; x < n; x++)
++  {
++    if (*((added+vertex)->normal+x) == normal)
++      return TRUE;
++  }
++  return FALSE;
++}
++
++BOOL norm_array(int id, int vertex, double normal_difference,
++                struct vert_struct *n, int num_vert)
++{
++  static int last;
++  static struct vert_added *added;
++  register int x;
++  static BOOL first = TRUE;
++
++  if (first)
++  {
++    /*   This is the first time that we are in here, so we will allocate
++         a structure that will save the vertices that we added, so that we
++         do not add the same thing twice
++    */
++    first = FALSE;
++    added = (struct vert_added *) malloc (sizeof (struct vert_added ) * num_vert);
++    /*   The number of vertices added for each vertex must be initialized to
++         zero
++    */
++    for (x = 0; x < num_vert; x++)
++      (added+x)->num = 0;
++  }
++
++  if (vertex)
++    /*   Set the pointer to the vertex, we will be calling again with the
++         normal to fill it with
++    */
++    last = id;
++  else
++  {    
++    /*   Fill the pointer with the id of the normal */
++    if (*(vert_norms + last) == 0)
++      *(vert_norms + last) = id;
++    else if ((*(vert_norms + last) != id) && ((int)normal_difference != 360))
++    {
++      /*   difference is big enough, we need to create a new vertex */
++      if (new_vertex(normal_difference,id,*(vert_norms + last),n))
++      {
++        /*   First check to see if we added this vertex and normal already */
++        if (Check_VN(last,id,added))
++          return FALSE;
++        /*   OK, create the new vertex, and have its id = the number of vertices
++             and its normal what we have here
++        */
++        vert_norms = realloc(vert_norms, sizeof(int) * (num_vert + 1));
++        if (!vert_norms)
++        {
++          printf("Allocation error - aborting\n");
++          exit(1);
++        }
++        *(vert_norms + num_vert) = id;
++        /*   We created a new vertex, now put it in our added structure so
++             we do not add the same thing twice
++        */
++        (added+last)->num = (added+last)->num + 1;
++        if ((added+last)->num == 1)
++        {
++          /*   First time */
++          (added+last)->normal =  (int *) malloc (sizeof (int ) * 1);
++          *((added+last)->normal) =  id;
++        }
++        else
++        {
++          /*   Not the first time, reallocate space */
++          (added+last)->normal = realloc((added+last)->normal,sizeof(int) * (added+last)->num);
++          *((added+last)->normal+((added+last)->num-1)) = id;
++        }
++        return TRUE;
++      }
++    }
++  }
++  return FALSE;
++}
++
++void add_texture(int id,BOOL vertex)
++{
++  /*   Save the texture with its vertex for future use when outputting */
++  static int last;
++
++  if (vertex)
++    last = id;
++  else
++    *(vert_texture+last) = id;
++}
++
++int   add_vert_id(int id, int index_count)
++{
++  register int x;
++
++  /*   Test if degenerate, if so do not add degenerate vertex */
++  for (x = 1; x < index_count ; x++)
++  {
++    if (ids[x] == id)
++      return 0;
++  }
++  ids[index_count] = id;
++  return 1;
++}
++
++void  add_norm_id(int id, int index_count)
++{
++      norms[index_count] = id;
++}
++
++void AddNewFace(int ids[STRIP_MAX], int vert_count, int face_id, 
++              int norms[STRIP_MAX])
++{
++  PF_FACES pfNode;
++  int *pTempInt;
++  int *pnorms;
++  F_EDGES **pTempVertptr;
++  int *pTempmarked, *pTempwalked;
++  register int        y,count = 0;
++      
++      /*   Add a new face into our face data structure */
++
++  pfNode = (PF_FACES) malloc(sizeof(F_FACES) );
++  if ( pfNode )
++  {
++    pfNode->pPolygon = (int*) malloc(sizeof(int) * (vert_count) );
++    pfNode->pNorms = (int*) malloc(sizeof(int) * (vert_count) );
++    pfNode->VertandId = (F_EDGES**)malloc(sizeof(F_EDGES*) * (vert_count)); 
++              pfNode->marked  = (int*)malloc(sizeof(int) * (vert_count));
++              pfNode->walked = (int*)malloc(sizeof(int) * (vert_count));
++      }
++      pTempInt =pfNode->pPolygon;
++      pnorms = pfNode->pNorms;
++  pTempmarked = pfNode->marked;
++      pTempwalked = pfNode->walked;
++      pTempVertptr = pfNode->VertandId;
++      pfNode->nPolSize = vert_count;
++      pfNode->seen = -1;
++  pfNode->seen2 = -1;
++      for (y=1;y<=vert_count;y++)
++      {
++              *(pTempInt + count) = ids[y];
++              *(pnorms + count) = norms[y];
++    *(pTempmarked + count) = FALSE;
++        *(pTempwalked + count) =  -1;
++              *(pTempVertptr+count) = NULL;
++              count++;
++      }
++      AddHead(PolFaces[face_id-1],(PLISTINFO) pfNode);
++}     
++
++      
++void CopyFace(int ids[STRIP_MAX], int vert_count, int face_id, 
++            int norms[STRIP_MAX])
++{
++  PF_FACES pfNode;
++  int *pTempInt;
++  int *pnorms;
++  F_EDGES **pTempVertptr;
++  int *pTempmarked, *pTempwalked;
++  register int        y,count = 0;
++      
++      /*   Copy a face node into a new node, used after the global algorithm
++       is run, so that we can save whatever is left into a new structure
++  */
++     
++  pfNode = (PF_FACES) malloc(sizeof(F_FACES) );
++  if ( pfNode )
++  {
++    pfNode->pPolygon = (int*) malloc(sizeof(int) * (vert_count) );
++    pfNode->pNorms = (int*) malloc(sizeof(int) * (vert_count) );
++    pfNode->VertandId = (F_EDGES**)malloc(sizeof(F_EDGES*) * (vert_count)); 
++              pfNode->marked  = (int*)malloc(sizeof(int) * (vert_count));
++              pfNode->walked = (int*)malloc(sizeof(int) * (vert_count));
++      }
++      pTempInt =pfNode->pPolygon;
++      pnorms = pfNode->pNorms;
++  pTempmarked = pfNode->marked;
++      pTempwalked = pfNode->walked;
++      pTempVertptr = pfNode->VertandId;
++      pfNode->nPolSize = vert_count;
++      pfNode->seen = -1;
++  pfNode->seen2 = -1;
++      for (y=0;y<vert_count;y++)
++      {
++              *(pTempInt + count) = ids[y];
++              *(pnorms + count) = norms[y];
++    *(pTempmarked + count) = FALSE;
++              *(pTempwalked + count) =  -1;
++              *(pTempVertptr+count) = NULL;
++              count++;
++      }
++      AddHead(PolFaces[face_id-1],(PLISTINFO) pfNode);
++}     
++      
++void Add_Edge(int v1,int v2)
++{
++  PF_EDGES temp  = NULL;
++  ListHead *pListHead;
++  BOOL flag = TRUE;
++  register int t,count = 0;
++      
++      /*   Add a new edge into the edge data structure */
++  if (v1 > v2)
++      {
++              t  = v1;
++              v1 = v2;
++              v2 = t;
++      }
++      
++  pListHead = PolEdges[v1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++      if (temp == NULL)
++  {
++    printf("Have the wrong edge \n:");
++    exit(1);
++  }
++      
++      while (flag)
++      {
++              if (v2 == temp->edge[0])
++      return;
++    else
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,++count);
++      }                       
++}
++
++void Add_AdjEdge(int v1,int v2,int fnum,int index1 )
++{
++  PF_EDGES temp  = NULL;
++  PF_FACES temp2 = NULL;
++  PF_EDGES pfNode;
++  ListHead *pListHead;
++  ListHead *pListFace;
++  BOOL        flag = TRUE;
++  register int        count = 0;
++  register int        t,v3 = -1;
++      
++      if (v1 > v2)
++      {
++              t  = v1;
++              v1 = v2;
++              v2 = t;
++      }
++      pListFace  = PolFaces[fnum];
++      temp2 = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
++      pListHead = PolEdges[v1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++      if (temp == NULL)
++              flag = FALSE;
++      count++;
++      while (flag)
++      {
++              if (v2 == temp->edge[0])
++              {
++      /*   If greater than 2 polygons adjacent to an edge, then we will
++           only save the first 2 that we found. We will have a small performance
++           hit, but this does not happen often.
++      */
++      if (temp->edge[2] == -1)
++        temp->edge[2] = fnum;
++      else
++        v3 = temp->edge[2];
++      flag = FALSE;
++              }
++              else
++              {
++                      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++                      count++;
++                      if (temp == NULL)
++                              flag = FALSE;
++              }
++      }
++                
++      /*   Did not find it */
++  if (temp == NULL)
++      {
++              pfNode = (PF_EDGES) malloc(sizeof(F_EDGES) );
++    if ( pfNode )
++    {
++      pfNode->edge[0] = v2;
++                      pfNode->edge[1] = fnum;
++          pfNode->edge[2] =  v3;
++                      AddTail( PolEdges[v1], (PLISTINFO) pfNode );
++    }
++              else
++    {
++      printf("Out of memory!\n");
++      exit(1);
++    }
++              
++    *(temp2->VertandId+index1) = pfNode;
++      }
++      else
++        *(temp2->VertandId+index1) =  temp;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fb37f729adfb417c0124fb39e52e5eed6c4054c6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,31 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: add.h
++-----------------------------------------------------------------------*/
++
++#include "global.h"
++
++BOOL new_vertex(double difference, int id1,int id2,
++                struct vert_struct *n);
++BOOL Check_VN(int vertex,int normal, struct vert_added *added);
++BOOL norm_array(int id, int vertex, double normal_difference,
++                struct vert_struct *n, int num_vert);
++void add_texture(int id,BOOL vertex);
++int   add_vert_id(int id, int index_count);
++void  add_norm_id(int id, int index_count);
++void AddNewFace(int ids[STRIP_MAX], int vert_count, int face_id, 
++              int norms[STRIP_MAX]);
++void CopyFace(int ids[STRIP_MAX], int vert_count, int face_id, 
++            int norms[STRIP_MAX]);
++void Add_Edge(int v1,int v2);
++void Add_AdjEdge(int v1,int v2,int fnum,int index1 );
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..161e8ccde8d4b6772e51bba17aac9f3eb521649a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,569 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: bands.c
++     This file contains the main procedure code that will read in the
++     object and then call the routines that produce the triangle strips.
++*/
++/*---------------------------------------------------------------------*/
++
++
++#ifdef HAVE_CONFIG_H
++#  include <config.h>
++#endif
++  
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++#include <string.h>
++#include "global.h"
++#include "polverts.h"
++#include "triangulate.h"
++#include "ties.h"
++#include "outputex.h"
++#include "options.h"
++#include "local.h"
++#include "init.h"
++#include "free.h"
++#include "add.h"
++
++/*   TIMING for Windows */
++#ifdef WIN32
++#  include <sys/timeb.h>
++#  include <time.h>
++/*   TIMING for UNIX */
++#else
++#  include <sys/types.h>
++#  include <sys/param.h>
++#  include <sys/times.h>
++#  if defined(__FreeBSD__)
++#    ifndef HZ
++#      include <time.h>
++#      define HZ CLK_TCK
++#    endif /* HZ */
++#  else
++     extern long times( );
++#  endif /* __FreeBSD__ */
++  long elapsed()
++{
++  static long total = 0;
++  long cpu_time, dummy;
++  struct tms buffer;
++  times(&buffer);
++  dummy    = buffer.tms_utime  + buffer.tms_stime +
++             buffer.tms_cutime + buffer.tms_cstime;
++  cpu_time = ((dummy - total) * 1000) / HZ;
++  total    = dummy;
++  return(cpu_time);
++}
++#endif /* WIN32 */
++
++
++int     norms[STRIP_MAX];
++int     *vert_norms;
++int     *vert_texture;
++
++
++void get_time()
++{
++  /*   For timing */
++#ifdef WIN32
++  struct timeb timebuffer;
++  char *timeline;
++#else
++  long timer;
++#endif
++
++
++#ifdef WIN32
++  ftime( &timebuffer );
++  timeline = ctime( & ( timebuffer.time ) );
++  printf( "The time is %.19s.%hu %s", timeline, timebuffer.millitm, &timeline[20] );
++#else
++  timer = elapsed();
++  printf("The time is %ld\n",timer);
++#endif
++}
++
++/*
++** 
++     Here the main program begins. It will start by loading in a .obj file
++     then it will convert the polygonal model into triangle strips.
++**  
++*/
++
++int main (int argc,char *argv[])
++{
++  char        *fname, *oname, *all,buff[255], *ptr, *ptr2;
++      FILE    *file, *bands;
++      int face_id=0;
++  int vert_count=0;
++  int loop=0;
++  int num=0;
++  int num2=0;
++
++      float center[3];
++  int temp[STRIP_MAX],vertex,strips, swaps,tempi,cost,triangles;
++  int f,t,tr,g;
++  char *file_open;
++      int     num_vert        = 0,
++              num_faces       = 0,
++              num_nvert       = 0,
++              num_edges       = 0,
++    num_texture = 0,
++    num_tris = 0;
++  double fra = 0.0;
++  BOOL texture, normal, normal_and_texture,quads = FALSE;
++
++  /*   Options variables */
++  double norm_difference;
++
++      /*   Structures for the object */
++  struct vert_struct  *vertices       = NULL,
++    *nvertices        = NULL,
++              *pvertices      = NULL,
++              *pnvertices     = NULL;
++
++  get_time();
++
++  /*
++    Scan the file once to find out the number of vertices,
++    vertice normals, and faces so we can set up some memory
++    structures 
++    */
++  /* Interpret the options specified */
++  norm_difference = get_options(argc,argv,&f,&t,&tr,&g);
++  if (f == BINARY)
++      file_open = "rb";
++  else
++      file_open = "r";
++  
++  fname = argv[argc-2];
++  oname = argv[argc-1];
++  
++  printf ("Input file: %s  Output file: %s\n", fname, oname);
++  printf ("Scanning...%s ",file_open);
++
++          
++  /*   File that will contain the triangle strip data */
++  
++  bands = fopen(oname, "w");
++
++  /*   File can be in binary for faster reading */
++  if (file = fopen (fname,file_open))
++      {
++        while (!feof (file))
++              {
++                      /*   Read a line */
++      if (f == BINARY)
++        fread (buff,sizeof(char) * 255,1, file);
++                      else
++        fgets (buff, sizeof(char) * 255, file);
++      num++;
++      
++      printf("%d\r",num);
++
++      
++      /*   At a vertex */
++      if (*buff == 'v')
++                      {
++                              /*   At a normal */
++        if (*(buff+1)=='n')
++                                      num_nvert++;
++                              else if (*(buff+1)=='t')
++          num_texture++;
++        /*   At a regular vertex */
++        else
++                                num_vert++;
++                      }
++                      /*   At a face */
++      else if (*buff == 'f')
++                      {  
++        num_faces++;
++                        strtok(buff, " ");
++                        tempi = 0;
++                        while (strtok(NULL, " ") != NULL) tempi++;
++                        num_tris += tempi - 2;
++      }
++              }
++              fclose (file);
++  }
++      else
++  {
++    printf("Error in the file name\n");
++    exit(1);
++  }
++      
++  printf("%s pass 1\n",fname);
++      
++      /* Allocate structures for the information */
++      Start_Face_Struct(num_faces);
++      vertices = (struct vert_struct *)
++                      malloc (sizeof (struct vert_struct) * num_vert);
++
++      if (num_nvert > 0) {
++    nvertices = (struct vert_struct *)
++              malloc (sizeof (struct vert_struct) * num_nvert);
++    vert_norms = (int *) malloc (sizeof (int) * num_vert);
++    /*   
++    Initialize entries to zero, in case there are 2 hits
++    to the same vertex we will know it - used for determining
++    the normal difference
++    */
++    init_vert_norms(num_vert);
++  } else {
++              nvertices = NULL;
++  }
++
++  if (num_texture > 0) {
++    vert_texture = (int *) malloc (sizeof(int) * num_vert);
++    init_vert_texture(num_vert);
++  }
++     
++      /*
++  Set up the temporary 'p' pointers 
++  */
++      pvertices = vertices;
++      pnvertices = nvertices;
++
++      /* Load the object into memory */
++      /*printf (" Loading...");*/
++ 
++   fprintf(bands,"#%s: a triangle strip representation created by STRIPE.\n#This is a .objf file\n#by Francine Evans\n",fname);
++ 
++  /*  File will be put in a list for faster execution if file is in binary */   
++  if (file = fopen(fname,file_open)) {
++    if (f == BINARY) {
++      all = (char *) malloc (sizeof(char) * 255 * num);
++      fread(all,sizeof(char) * 255 * num, 1, file);
++      ptr = all;
++    } else {
++      ptr = (char *) malloc (sizeof(char) * 255 * num);
++    }
++  }
++
++   
++  while (num > 0) {
++    num--;
++
++    printf("%d\r",num);
++
++              if (f == ASCII) {
++      fgets (ptr, sizeof(char) * 255, file);
++    } else {
++      ptr = ptr + 255;
++    }
++
++    /* Load in vertices/normals */
++              if (*ptr == 'v') {
++                      if (*(ptr+1)=='n') {
++                              sscanf (ptr+3,"%lf%lf%lf",
++                                      &(pnvertices->x),
++                                      &(pnvertices->y),
++                                      &(pnvertices->z));
++                              fprintf(bands,"vn %f %f %f\n",
++                                      pnvertices->x,pnvertices->y,pnvertices->z); 
++                      ++pnvertices;
++                      } else if (*(ptr+1)=='t') {
++                              sscanf (ptr+3,"%f%f%f",&center[0],&center[1],&center[2]);
++                      fprintf(bands,"vt %f %f %f\n",center[0],center[1],center[2]); 
++      } else {
++                              sscanf (ptr+2,"%lf%lf%lf",
++                                      &(pvertices->x), 
++                                      &(pvertices->y), 
++                                      &(pvertices->z));
++                      fprintf(bands,"v %f %f %f\n",
++                                      pvertices->x,pvertices->y,pvertices->z); 
++                              ++pvertices;
++      }
++              } else if (*ptr == 'f') {
++                      /* Read in faces */
++                      num2 = 0;
++                      face_id++;
++      ptr2 = ptr+1;
++      normal = FALSE; texture = FALSE, normal_and_texture = FALSE;
++      while (*ptr2) {
++                        if (*ptr2 >='0' && *ptr2 <='9') {
++                                num2++;
++                                ++ptr2;
++                                while (*ptr2 && (*ptr2!=' ' && *ptr2!='/')) {
++                                        ptr2++;
++          }
++          /*   There are normals in this line */
++          if (*ptr2 == '/') {
++            if (*(ptr2+1) == '/') {
++              normal = TRUE;
++            } else {
++              texture = TRUE;
++            }
++                          } else if (*ptr2 == ' ') {
++            if ((num2 == 3) && (texture)) {
++              normal_and_texture = TRUE;
++            }
++          }
++        } else {
++                                ++ptr2;
++        }
++                      }
++
++      ptr2 = ptr+1;
++                      
++      /* 
++      loop on the number of numbers in this line of face data 
++      */
++                      vert_count = 0;
++                                                              
++                      for (loop=0;loop<num2;loop++) {
++                              /* skip the whitespace */
++                              while (*ptr2<'0' || *ptr2>'9') {
++          if (*ptr2 == '-') {
++            break;
++          }
++          ptr2++;
++        }
++                              vertex = atoi(ptr2)-1;
++        if (vertex < 0) {
++          vertex = num_vert + vertex;
++          *ptr2 = ' ';
++          ptr2++;
++        }
++        /*
++        If there are either normals or textures with the vertices
++        in this file, the data alternates so we must read it this way 
++        */
++                              if ( (normal) && (!normal_and_texture)) {
++                                      if (loop%2) {
++            add_norm_id(vertex,vert_count);
++            /*
++            Test here to see if we added a new vertex, since the
++            vertex has more than one normal and the 2 normals are greater
++            than the threshold specified
++            */
++            if (norm_array(vertex,0,norm_difference,nvertices,num_vert)) {
++              /*
++              Add a new vertex and change the
++              id of the vertex that we just read to the id of the new
++              vertex that we just added
++              */
++              /*
++              Put it in the output file, note the added vertices will
++              be after the normals and separated from the rest of the 
++              vertices. Will not affect our viewer
++              */
++              fprintf(bands,"v %f %f %f\n",
++                (vertices + temp[vert_count - 1])->x,
++                (vertices + temp[vert_count - 1])->y,
++                (vertices + temp[vert_count - 1])->z); 
++              num_vert++;
++              temp[vert_count - 1] = num_vert - 1;
++              if (!(add_vert_id(num_vert - 1,vert_count))) {
++                vert_count--;
++              }
++            }
++          } else {
++                                        /* the vertex */
++                                              temp[vert_count] = vertex ;
++                                              vert_count++;
++            if (!(add_vert_id(vertex,vert_count))) {
++                vert_count--;
++            }
++            norm_array(vertex,1,norm_difference,nvertices,num_vert);
++                                      }
++        } else if (normal_and_texture) {                      
++          /* Else there are vertices and textures with the data */
++          if( !((loop+1)%3)) {
++            add_norm_id(vertex,vert_count);
++            /*
++            Test here to see if we added a new vertex, since the
++            vertex has more than one normal and the 2 normals are greater
++            than the threshold specified
++            */
++            if (norm_array(vertex,0,norm_difference,nvertices,num_vert)) {
++              /*
++              Add a new vertex and change the
++              id of the vertex that we just read to the id of the new
++              vertex that we just added
++              */
++              /*
++              Put it in the output file, note the added vertices will
++              be after the normals and separated from the rest of the 
++              vertices. Will not affect our viewer
++              */
++              fprintf(bands,"v %f %f %f\n",
++                (vertices + temp[vert_count - 1])->x,
++                (vertices + temp[vert_count - 1])->y,
++                (vertices + temp[vert_count - 1])->z); 
++              num_vert++;
++              temp[vert_count - 1] = num_vert - 1;
++              if (!(add_vert_id(num_vert - 1,vert_count))) {
++                vert_count--;
++              }
++            }
++          } else if ((loop == 0) || (*(ptr2-1) == ' ')) {
++            /*   the vertex */
++            temp[vert_count] = vertex ;
++            vert_count++;
++            if (vert_count == 4) {
++              quads = TRUE;
++            }
++            if (!(add_vert_id(vertex,vert_count))) {
++              vert_count--;
++            }
++            add_texture(vertex,TRUE);
++            norm_array(vertex,1,norm_difference,nvertices,num_vert);
++                                      } else {
++            /*   The texture */
++            add_texture(vertex,FALSE);
++          }
++        } else if ( texture ) {
++                                      /*   the vertex */
++          if (!(loop%2)) {
++                                              temp[vert_count] = vertex ;
++                                              vert_count++;
++            if (vert_count == 4)
++              quads = TRUE;
++            add_texture(vertex,TRUE);
++            if (!(add_vert_id(vertex,vert_count)))
++              vert_count--;
++            norm_array(vertex,1,norm_difference,nvertices,num_vert);
++                                      } else {
++            /*   texture */
++            add_texture(vertex,FALSE);
++          }
++        } else {
++                                /*** no nvertices ***/
++                                      temp[vert_count] = vertex ;
++                                      vert_count++;
++          if (vert_count == 4)
++            quads = TRUE;
++          if (!(add_vert_id(vertex,vert_count)))
++            vert_count--;
++                              }
++                              while (*ptr2>='0' && *ptr2<='9')
++                                      ptr2++;
++      }
++                      /* Done with the polygon */
++                      num_edges += vert_count;
++                      /* add it to face structure */
++                      if (vert_count >= 3)
++        AddNewFace(ids,vert_count,face_id,norms);
++      else
++        face_id--;
++      if (vert_count == 4)
++        quads = TRUE;
++    }
++    else if ((g == TRUE) && (face_id > 0)
++         && ((*ptr == 'g') || (*ptr  == 's') || (*ptr == 'm') || (*ptr == 'o')))
++    {
++      /*
++      The user specified that the strips will be contained in each group
++      from the data file, so we just finished a group and will find the
++      triangle strips in it.
++      */
++      Start_Edge_Struct(num_vert);
++          Find_Adjacencies(face_id);
++          if (quads)
++      {
++        Init_Table_SGI();
++            Build_SGI_Table(num_vert,face_id);
++        /* Code for lengths of walks in each direction */
++            /* Save_Walks(face_id,TRUE); */
++            Save_Walks(face_id);
++
++        /* Code for finding the bands */
++            Find_Bands(face_id,bands,&swaps,&strips,&cost,&triangles,num_nvert,vert_norms,num_texture,vert_texture);
++
++        /*
++        Remove the faces that we did  so that we can
++        run the strip code on the rest of the faces that are left
++        */
++        if (cost != 0)
++        {
++          printf("Total %d triangles with %d cost\n",triangles,cost);
++          Save_Rest(&face_id);
++          printf("We saved %d .... now doing the local algorithm\n",face_id);
++          fprintf(bands,"\n#local\n");
++              End_Edge_Struct(num_vert);
++          Start_Edge_Struct(num_vert);
++              Find_Adjacencies(face_id);
++        }
++      }
++             
++      SGI_Strip(num_vert,face_id,bands,t,tr);
++
++      /* Get the total cost */
++      Output_TriEx(-1,-2,-3,NULL,-1,-20,cost);
++
++      End_Face_Struct(num_faces);
++      End_Edge_Struct(num_vert);
++      cost = 0;
++      face_id = 0;
++      quads = FALSE;
++      Start_Face_Struct(num_faces-face_id);
++      num_faces = num_faces - face_id;
++      Free_Strips();
++    }
++  }
++               
++  /*   Done reading in all the information into data structures */
++  num_faces = face_id;
++  fclose (file);
++  
++  printf("Input Done.\n\n");
++
++  free(vertices);
++  free(nvertices);
++
++  printf ("Vertices:  %d\nNormals:    %d\nFaces:              %d\n",num_vert,num_nvert,num_faces);
++
++  Start_Edge_Struct(num_vert);
++  Find_Adjacencies(num_faces);
++
++  /* Initialize it */
++  Init_Table_SGI();
++  /* Build it */
++  Build_SGI_Table(num_vert,num_faces);
++
++  InitStripTable();
++
++  if (quads) {
++    /* Code for lengths of walks in each direction */
++          /* Save_Walks(num_faces,TRUE); */
++        Save_Walks(num_faces);
++        
++    /* Code for finding the bands */
++        Find_Bands(num_faces,bands,&swaps,&strips,&cost,&triangles,num_nvert,vert_norms,num_texture,vert_texture);
++    /*printf("Total %d triangles with %d cost\n",triangles,cost);*/
++
++    /*  
++    Remove the faces that we did  so that we can
++    run the strip code on the rest of the faces that are left
++    */
++    Save_Rest(&num_faces);
++    /*printf("We saved %d .... now doing the local algorithm\n",num_faces);*/
++    fprintf(bands,"\n#local\n");
++        End_Edge_Struct(num_vert);
++    Start_Edge_Struct(num_vert);
++        Find_Adjacencies(num_faces);
++  }
++             
++  SGI_Strip(num_vert,num_faces,bands,t,tr);
++
++  /*   Get the total cost */
++  Output_TriEx(-1,-2,-3,NULL,-1,-20,cost);
++
++  End_Face_Struct(num_faces);
++  End_Edge_Struct(num_vert);
++  fclose(bands);
++
++  get_time();
++
++  return(0);
++}
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ca836e19fbc20cf69be3839fc7319e407d434d1b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,810 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: common.c
++     This file contains common code used in both the local and global algorithm
++*/
++/*---------------------------------------------------------------------*/
++
++
++#include <stdlib.h>
++#include "polverts.h"
++#include "extend.h"
++#include "output.h"
++#include "triangulate.h"
++#include "util.h"
++#include "add.h"
++
++int  Old_Adj(int face_id)
++{
++      /*      Find the bucket that the face_id is currently in,
++              because maybe we will be deleting it. 
++      */
++      PF_FACES temp = NULL;
++      ListHead *pListHead;
++      int size,y;
++      
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      if ( temp == NULL )
++      {
++              printf("The face was already deleted, there is an error\n");
++              exit(0);
++      }
++      
++      size = temp->nPolSize;
++      if (Done(face_id,size,&y) == NULL)
++      {
++              printf("There is an error in finding the face\n");
++              exit(0);
++      }
++      return y;
++}
++
++int Number_Adj(int id1, int id2, int curr_id)
++{
++      /*      Given edge whose endpoints are specified by id1 and id2,
++              determine how many polygons share this edge and return that
++              number minus one (since we do not want to include the polygon
++              that the caller has already).
++      */
++
++      int size,y,count=0;
++      PF_EDGES temp = NULL;
++      PF_FACES temp2 = NULL;
++      ListHead *pListHead;
++      BOOL there= FALSE;
++
++      /*      Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++     /*       new edge that was created might not be here */
++              return 0;
++      while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          if (temp == NULL)
++                      /*      This edge was not there in the original, which
++                              mean that we created it in the partial triangulation.
++                              So it is adjacent to nothing.
++                      */
++                      return 0;
++      }
++      /*      Was not adjacent to anything else except itself */
++      if (temp->edge[2] == -1)
++              return 0;
++      else
++      {
++              /*      It was adjacent to another polygon, but maybe we did this
++                      polygon already, and it was done partially so that this edge
++                      could have been done
++              */
++              if (curr_id != temp->edge[1])
++              {
++                      /*      Did we use this polygon already?and it was deleted
++                              completely from the structure
++                      */
++                      pListHead = PolFaces[temp->edge[1]];
++                      temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++                      if (Done(temp->edge[1],temp2->nPolSize,&size) == NULL)
++                              return 0;
++              }
++              else
++              {
++                      pListHead = PolFaces[temp->edge[2]];
++                      temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++                      if (Done(temp->edge[2],temp2->nPolSize,&size)== NULL)
++                              return 0;
++              }
++
++              /*      Now we have to check whether it was partially done, before
++                      we can say definitely if it is adjacent.
++                      Check each edge of the face and tally the number of adjacent
++                      polygons to this face. 
++              */                      
++              if ( temp2 != NULL )
++              {
++                      /*      Size of the polygon */
++                      size = temp2->nPolSize;
++                      for (y = 0; y< size; y++)
++                      {
++                              /*      If we are doing partial triangulation, we must check
++                                      to see whether the edge is still there in the polygon,
++                                      since we might have done a portion of the polygon
++                                      and saved the rest for later.
++                              */
++                              if (y != (size-1))
++                              {
++                                      if( ((id1 == *(temp2->pPolygon+y)) && (id2 ==*(temp2->pPolygon+y+1)))
++                                              || ((id2 == *(temp2->pPolygon+y)) && (id1 ==*(temp2->pPolygon+y+1))))
++                                              /*      edge is still there we are ok */
++                                              there = TRUE;
++                              }
++                              else
++                              {
++                                      if( ((id1 == *(temp2->pPolygon)) && (id2 == *(temp2->pPolygon+size-1)))
++                                      || ((id2 == *(temp2->pPolygon)) && (id1 ==*(temp2->pPolygon+size-1))))
++                                      /*      edge is still there we are ok */
++                                              there = TRUE;
++                              }
++                      }
++              }
++              
++              if (there )
++                      return 1;
++              return 0;
++      }
++}
++
++int Min_Adj(int id)
++{
++      /*      Used for the lookahead to break ties. It will
++              return the minimum adjacency found at this face.
++      */
++      int y,numverts,t,x=60;
++      PF_FACES temp=NULL;
++      ListHead *pListHead;
++
++      /*      If polygon was used then we can't use this face */
++      if (Done(id,59,&y) == NULL)
++              return 60;
++              
++      /*      It was not used already */
++      pListHead = PolFaces[id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++     if ( temp != NULL )
++      {
++              numverts = temp->nPolSize;
++              for (y = 0; y< numverts; y++)
++              {
++                      if (y != (numverts-1))
++                              t = Number_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),id);
++                      else
++                              t = Number_Adj(*(temp->pPolygon),*(temp->pPolygon+(numverts-1)),id);
++                      if (t < x)
++                              x = t;
++              }
++      }
++      if (x == -1)
++      {
++              printf("Error in the look\n");
++              exit(0);
++      }
++      return x;
++}
++
++
++
++void Edge_Least(int *index,int *new1,int *new2,int face_id,int size)
++{
++    /*   We had a polygon without an input edge and now we re going to pick one
++         of the edges with the least number of adjacencies to be the input
++         edge
++    */
++    register int x,value,smallest=60;
++
++    for (x = 0; x<size; x++)
++    {
++        if (x != (size -1) )
++            value = Number_Adj(*(index+x),*(index+x+1),face_id);
++        else 
++            value = Number_Adj(*(index),*(index+size-1),face_id);
++        if (value < smallest)
++        {
++            smallest = value;
++            if (x != (size -1))
++            {
++                *new1 = *(index+x);
++                *new2 = *(index+x+1);
++            }
++            else
++            {
++                *new1 = *(index);
++                *new2 = *(index+size-1);
++            }
++        }
++    }
++    if ((smallest == 60) || (smallest < 0))
++    {
++        printf("There is an error in getting the least edge\n");
++        exit(0);
++    }
++}
++
++
++void Check_In_Polygon(int face_id, int *min, int size)
++{
++    /*  Check to see the adjacencies by going into a polygon that has
++        greater than 4 sides.
++    */
++    
++    ListHead *pListHead;
++    PF_FACES temp;
++    int y,id1,id2,id3,x=0,z=0;
++    int saved[2];
++    int big_saved[60];
++
++    pListHead = PolFaces[face_id];
++    temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++
++    /*   Get the input edge that we came in on */
++    Last_Edge(&id1,&id2,&id3,0);
++
++    /*  Find the number of adjacencies to the edges that are adjacent
++        to the input edge.
++    */
++    for (y=0; y< size; y++)
++    {
++        if (y != (size-1))
++        {
++            if (((*(temp->pPolygon+y) == id2) && (*(temp->pPolygon+y+1) != id3))
++                || ((*(temp->pPolygon+y) == id3) && (*(temp->pPolygon+y+1) != id2)))
++            {
++                saved[x++] = Number_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),face_id);
++                big_saved[z++] = saved[x-1];
++            }
++            else
++                big_saved[z++] = Number_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),face_id);
++        }
++        else
++        {
++            if (((*(temp->pPolygon) == id2) && (*(temp->pPolygon+size-1) != id3))
++                || ((*(temp->pPolygon) == id3) && (*(temp->pPolygon+size-1) != id2)))
++            {
++                saved[x++] = Number_Adj(*(temp->pPolygon),*(temp->pPolygon+size-1),face_id);
++                big_saved[z++] = saved[x-1];
++            }
++            else
++                big_saved[z++] = Number_Adj(*(temp->pPolygon),*(temp->pPolygon+size-1),face_id);
++        }
++    }
++    /*  There was an input edge */
++    if (x == 2)
++    {
++        if (saved[0] < saved[1])
++            /*  Count the polygon that we will be cutting as another adjacency*/
++            *min = saved[0] + 1;
++        else
++            *min = saved[1] + 1;
++    }
++    /*  There was not an input edge */
++    else
++    {
++        if (z != size)
++        {
++            printf("There is an error with the z %d %d\n",size,z);
++            exit(0);
++        }
++        *min = 60;
++        for (x = 0; x < size; x++)
++        {
++            if (*min > big_saved[x])
++                *min = big_saved[x];
++        }
++    }
++}
++
++
++void New_Face (int face_id, int v1, int v2, int v3)
++{
++      /*      We want to change the face that was face_id, we will
++              change it to a triangle, since the rest of the polygon
++              was already outputtted
++      */
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++
++      pListHead = PolFaces[face_id];
++     temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0);
++      /*      Check each edge of the face and tally the number of adjacent
++              polygons to this face. 
++      */                      
++      if ( temp != NULL )
++      {
++              /*      Size of the polygon */
++              if (temp->nPolSize != 4)
++              {
++                      printf("There is a miscalculation in the partial\n");
++                      exit (0);
++              }
++              temp->nPolSize = 3;
++              *(temp->pPolygon) = v1;
++              *(temp->pPolygon+1) = v2;
++              *(temp->pPolygon+2) = v3;
++      }
++}
++
++void New_Size_Face (int face_id)
++{
++      /*      We want to change the face that was face_id, we will
++              change it to a triangle, since the rest of the polygon
++              was already outputtted
++      */
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      /*      Check each edge of the face and tally the number of adjacent
++              polygons to this face. 
++      */                      
++      if ( temp != NULL )
++              (temp->nPolSize)--;
++      else
++              printf("There is an error in updating the size\n");
++}
++
++
++
++void  Check_In_Quad(int face_id,int *min)
++{
++     /*   Check to see what the adjacencies are for the polygons that
++          are inside the quad, ie the 2 triangles that we can form.
++     */
++    ListHead *pListHead;
++    int y,id1,id2,id3,x=0;
++    int saved[4];
++    PF_FACES temp;
++    register int size = 4;
++
++    pListHead = PolFaces[face_id];
++    temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      
++     /*   Get the input edge that we came in on */
++    Last_Edge(&id1,&id2,&id3,0);
++      
++    /*    Now find the adjacencies for the inside triangles */
++    for (y = 0; y< size; y++)
++      {
++         /*     Will not do this if the edge is the input edge */
++         if (y != (size-1))
++         {
++              if ((((*(temp->pPolygon+y) == id2) && (*(temp->pPolygon+y+1) == id3))) ||
++             (((*(temp->pPolygon+y) == id3) && (*(temp->pPolygon+y+1) == id2))))
++                    saved[x++] = -1;
++              else
++              {
++                   if (x == 4)
++                   {
++                        printf("There is an error in the check in quad \n");
++                        exit(0);
++                   }
++                   /*    Save the number of Adjacent Polygons to this edge */
++                   saved[x++] = Number_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),face_id);
++              }
++         }
++              else if ((((*(temp->pPolygon) == id2) && (*(temp->pPolygon+size-1) == id3))) ||
++             (((*(temp->pPolygon) == id3) && (*(temp->pPolygon+size-1) == id2))) )
++             saved[x++] = -1;
++        else
++        {
++               if (x == 4)
++               {
++                    printf("There is an error in the check in quad \n");
++                    exit(0);
++               }
++               /*    Save the number of Adjacent Polygons to this edge */
++               saved[x++] = Number_Adj(*(temp->pPolygon),*(temp->pPolygon+size-1),face_id);
++
++        }
++    }
++    if (x != 4)
++    {
++         printf("Did not enter all the values %d \n",x);
++         exit(0);
++    }
++    
++    *min = 10;
++    for (x=0; x<4; x++)
++    {
++         if (x!= 3)
++         {
++              if ((saved[x] != -1) && (saved[x+1] != -1) && 
++                   ((saved[x] + saved[x+1]) < *min))
++                   *min = saved[x] + saved[x+1];
++         }
++         else
++         {
++              if ((saved[0] != -1) && (saved[x] != -1) &&
++                   ((saved[x] + saved[0]) < *min))
++                   *min = saved[0] + saved[x];
++         }
++    }
++}
++
++
++
++int Get_Output_Edge(int face_id, int size, int *index,int id2,int id3)
++{
++    /*  Return the vertex adjacent to either input1 or input2 that
++        is adjacent to the least number of polygons on the edge that
++        is shared with either input1 or input2.
++    */
++    register int x=0,y;
++    int saved[2];
++    int edges[2][1];
++
++    for (y = 0; y < size; y++)
++    {
++        if (y != (size-1))
++        {
++            if (((*(index+y) == id2) && (*(index+y+1) != id3))
++                || ((*(index+y) == id3) && (*(index+y+1) != id2)))
++            {
++                saved[x++] = Number_Adj(*(index+y),*(index+y+1),face_id);
++                edges[x-1][0] = *(index+y+1);
++            }
++            else if (y != 0)
++            {
++                if (( (*(index+y) == id2) && (*(index+y-1) != id3) ) ||
++                    ( (*(index+y) == id3) && (*(index+y-1) != id2)) )
++                {
++                    saved[x++] = Number_Adj(*(index+y),*(index+y-1),face_id);
++                    edges[x-1][0] = *(index+y-1);
++                }
++            }
++            else if (y == 0)
++            {
++                if (( (*(index) == id2) && (*(index+size-1) != id3) ) ||
++                    ( (*(index) == id3) && (*(index+size-1) != id2)) )
++                {
++                    saved[x++] = Number_Adj(*(index),*(index+size-1),face_id);
++                    edges[x-1][0] = *(index+size-1);
++                }
++            }
++
++        }
++        else
++        {
++            if (((*(index+size-1) == id2) && (*(index) != id3))
++                || ((*(index+size-1) == id3) && (*(index) != id2)))
++            {
++                saved[x++] = Number_Adj(*(index),*(index+size-1),face_id);
++                edges[x-1][0] = *(index);
++            }
++
++            if (( (*(index+size-1) == id2) && (*(index+y-1) != id3) ) ||
++                    ( (*(index+size-1) == id3) && (*(index+y-1) != id2)) )
++                {
++                    saved[x++] = Number_Adj(*(index+size-1),*(index+y-1),face_id);
++                    edges[x-1][0] = *(index+y-1);
++                }
++        }
++    }
++    if ((x != 2))
++    {
++        printf("There is an error in getting the input edge %d \n",x);
++        exit(0);
++    }
++    if (saved[0] < saved[1])
++        return edges[0][0];
++    else
++        return edges[1][0];
++
++}
++
++void Get_Input_Edge(int *index,int id1,int id2,int id3,int *new1,int *new2,int size,
++                    int face_id)
++{
++    /*  We had a polygon without an input edge and now we are going to pick one
++        as the input edge. The last triangle was id1,id2,id3, we will try to
++        get an edge to have something in common with one of those vertices, otherwise
++        we will pick the edge with the least number of adjacencies.
++    */
++
++    register int x;
++    int saved[3];
++
++    saved[0] = -1;
++    saved[1] = -1;
++    saved[2] = -1;
++    
++    /*  Go through the edges to see if there is one in common with one
++        of the vertices of the last triangle that we had, preferably id2 or
++        id3 since those are the last 2 things in the stack of size 2.
++    */
++    for (x=0; x< size; x++)
++    {
++        if (*(index+x) == id1)
++        {
++            if (x != (size-1))
++                saved[0] = *(index+x+1);
++            else
++                saved[0] = *(index);
++        }
++
++        if (*(index+x) == id2)
++        {
++            if (x != (size-1))
++                saved[1] = *(index+x+1);
++            else
++                saved[1] = *(index);
++        }
++        
++        if (*(index+x) == id3)
++        {
++            if (x != (size -1))
++                saved[2] = *(index+x+1);
++            else
++                saved[2] = *(index);
++        }
++    }
++    /*  Now see what we saved */
++    if (saved[2] != -1)
++    {
++        *new1 = id3;
++        *new2 = saved[2];
++        return;
++    }
++    else if (saved[1] != -1)
++    {
++        *new1 = id2;
++        *new2 = saved[1];
++        return;
++    }
++    else if (saved[0] != -1)
++    {
++        *new1 = id1;
++        *new2 = saved[0];
++        return;
++    }
++    /*  We did not find anything so get the edge with the least number of adjacencies */
++    Edge_Least(index,new1,new2,face_id,size);
++
++}
++
++int Find_Face(int current_face, int id1, int id2, int *bucket)
++{
++      /*      Find the face that is adjacent to the edge and is not the
++              current face.
++      */
++      register int size,y,count=0;
++      PF_EDGES temp = NULL;
++      PF_FACES temp2 = NULL;
++      ListHead *pListHead;
++      int next_face;
++      BOOL there = FALSE;
++
++    
++    /*        Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     /*  The input edge was a new edge */
++     if (temp == NULL)
++        return -1;
++        
++     while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          /*  The input edge was a new edge */
++          if (temp == NULL)
++            return -1;
++     }
++      /*      Was not adjacent to anything else except itself */
++      if (temp->edge[2] == -1)
++              return -1;
++      else
++      {
++              if (temp->edge[2] == current_face)
++                      next_face =  temp->edge[1];
++              else 
++                      next_face = temp->edge[2];
++      }
++      /*      We have the other face adjacent to this edge, it is 
++              next_face. 
++      */
++      pListHead = PolFaces[next_face];
++      temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++              
++     /*       See if the face was already deleted, and where
++              it is if it was not
++     */
++              
++     if (Done(next_face,59,bucket) == NULL)
++        return -1;
++
++     /*  Make sure the edge is still in this polygon, and that it is not
++         done
++     */
++              /*      Size of the polygon */
++              size = temp2->nPolSize;
++              for (y = 0; y< size; y++)
++              {
++                      /*      Make sure that the edge is still in the
++                              polygon and was not deleted, because if the edge was
++                              deleted, then we used it already.
++                      */
++                      if (y != (size-1))
++                      {
++                              if( ((id1 == *(temp2->pPolygon+y)) && (id2 ==*(temp2->pPolygon+y+1)))
++                                      || ((id2 == *(temp2->pPolygon+y)) && (id1 ==*(temp2->pPolygon+y+1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++                      else
++                      {               
++                              if( ((id1 == *(temp2->pPolygon)) && (id2 ==*(temp2->pPolygon+size-1)))
++                                      || ((id2 == *(temp2->pPolygon)) && (id1 ==*(temp2->pPolygon+size-1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++              }
++              
++              if (!there)
++                      /*      Edge already used and deleted from the polygon*/
++                      return -1;
++         else
++            return next_face;
++}
++
++BOOL Look_Up(int id1,int id2,int face_id)
++{
++      /*      See if the endpoints of the edge specified by id1 and id2
++              are adjacent to the face with face_id 
++      */
++      register int count = 0;
++      PF_EDGES temp  = NULL;
++      ListHead *pListHead;
++              
++      /*      Always want smaller id first */
++      switch_lower(&id1,&id2);
++
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++     /*       Was a new edge that we created */
++              return 0;
++      
++      while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          if (temp == NULL)
++                      /*      Was a new edge that we created */
++                      return 0;
++     }
++      /*      Was not adjacent to anything else except itself */
++      if ((temp->edge[2] == face_id) || (temp->edge[1] == face_id))
++      {
++              /*      Edge was adjacent to face, make sure that edge is 
++                      still there
++              */
++              if (Exist(face_id,id1,id2))
++                      return 1;
++              else
++                      return 0;
++      }
++      else
++              return 0;
++}
++
++
++void Add_Id_Strips(int id, int where)
++{
++     /*    Just save the triangle for later  */
++     P_STRIPS pfNode;
++
++      pfNode = (P_STRIPS) malloc(sizeof(Strips) );
++      if ( pfNode )
++      {
++           pfNode->face_id = id;
++           if (where == 1)
++               AddTail(strips[0],(PLISTINFO) pfNode);
++           /* We are backtracking in the strip */
++           else
++               AddHead(strips[0],(PLISTINFO) pfNode);
++      }
++      else
++      {
++           printf("There is not enough memory to allocate for the strips\n");
++           exit(0);
++      }
++}
++
++
++int Num_Adj(int id1, int id2)
++{
++      /*   Given edge whose endpoints are specified by id1 and id2,
++              determine how many polygons share this edge and return that
++              number minus one (since we do not want to include the polygon
++              that the caller has already).
++      */
++
++      PF_EDGES temp = NULL;
++      ListHead *pListHead;
++      register count=-1;
++
++      /*      Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++      {
++              printf("There is an error in the creation of the table \n");
++              exit(0);
++      }
++      while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++           if (temp == NULL)
++              {
++                      printf("There is an error in the creation of the table\n");
++                      exit(0);
++              }
++      }
++      /*      Was not adjacent to anything else except itself */
++      if (temp->edge[2] == -1)
++              return 0;
++      return 1;
++}
++
++
++void Add_Sgi_Adj(int bucket,int face_id)
++{
++      /*   This routine will add the face to the proper bucket,
++              depending on how many faces are adjacent to it (what the
++              value bucket should be).
++      */
++      P_ADJACENCIES pfNode;
++
++      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++     if ( pfNode )
++     {
++              pfNode->face_id = face_id;
++           AddHead(array[bucket],(PLISTINFO) pfNode);
++      }
++      else
++      {
++              printf("Out of memory for the SGI adj list!\n");
++              exit(0);
++      }
++}
++
++void Find_Adjacencies(int num_faces)
++{
++     register int     x,y;
++     register int     numverts;
++     PF_FACES temp=NULL;
++     ListHead *pListHead;
++
++      /*   Fill in the adjacencies data structure for all the faces */
++     for (x=0;x<num_faces;x++)
++      {
++              pListHead = PolFaces[x];
++              temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      if ( temp != NULL )
++              {
++                      numverts = temp->nPolSize;
++                      if (numverts != 1)
++               {
++                    for (y = 0; y< numverts; y++)
++                           {
++                                   if (y != (numverts-1))
++                                           Add_AdjEdge(*(temp->pPolygon+y),*(temp->pPolygon+y+1),x,y);
++                      
++                                   else 
++                                           Add_AdjEdge(*(temp->pPolygon),*(temp->pPolygon+(numverts-1)),x,numverts-1);
++                      
++                    }
++               }
++                      temp = NULL;
++              }
++      }
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..aca19824be584e877ec261224bd227e38f843393
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,42 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: common.h
++-----------------------------------------------------------------------*/
++
++void Add_AdjEdge(int v1,int v2,int fnum,int index1 );
++void Find_Adjacencies(int num_faces);
++void Add_Sgi_Adj(int bucket,int face_id);
++int Num_Adj(int id1, int id2);
++void Add_Id_Strips(int id, int where);
++BOOL Look_Up(int id1,int id2,int face_id);
++int Number_Adj(int id1, int id2, int curr_id);
++int  Old_Adj(int face_id);
++int Min_Adj(int id);
++int Find_Face(int current_face, int id1, int id2, int *bucket);
++void Edge_Least(int *index,int *new1,int *new2,int face_id,int size);
++void Get_Input_Edge(int *index,int id1,int id2,int id3,int *new1,int *new2,
++                  int size, int face_id);
++int Get_Output_Edge(int face_id, int size, int *index,int id2,int id3);
++void Check_In_Polygon(int face_id, int *min, int size);
++void  Check_In_Quad(int face_id,int *min);
++void New_Size_Face (int face_id);
++void New_Face (int face_id, int v1, int v2, int v3);
++
++
++
++
++
++
++
++
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..78c135e3a308e9d841c89dae89350cca0388d66e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: extend.h
++-----------------------------------------------------------------------*/
++
++int Bottom_Left();
++int Top_Left();
++void Start_Edge();
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ad655fcf7caa071962d6f2bfac198f31821e11b8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,112 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: free.c
++     This file contains the code used to free the data structures.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "polverts.h"
++
++ListHead *array[60];
++int     id_array[60];
++ListHead *strips[1];
++ListHead *all_strips[100000]; /*  Assume max 100000 strips */
++
++void ParseAndFreeList( ListHead *pListHead )
++{
++    register int c,num;
++        
++    /*    Freeing a linked list */
++    num = NumOnList(pListHead);
++    for (c = 0; c< num; c++)
++           RemHead(pListHead);
++} 
++
++void FreePolygonNode( PF_VERTS pfVerts)
++{
++      /*   Free a vertex node */
++     if ( pfVerts->pPolygon )
++              free( pfVerts->pPolygon );
++      free( pfVerts );
++
++}
++ 
++void Free_Strips()
++{
++    /*    Free strips data structure */
++    if (strips[0] == NULL)
++         return;
++    else
++         ParseAndFreeList(strips[0]);
++}
++
++void FreeFaceNode( PF_FACES pfFaces)
++{
++      /*   Free face node */
++     if ( pfFaces->pPolygon )
++                free( pfFaces->pPolygon );
++        free( pfFaces );
++}
++
++
++void FreeFaceTable(int nSize)
++{
++     register int nIndex;
++
++     for ( nIndex=0; nIndex < nSize; nIndex++ )
++     { 
++              if ( PolFaces[nIndex] != NULL ) 
++             ParseAndFreeList( PolFaces[nIndex] );
++     }
++     free( PolFaces );
++}
++
++void FreeEdgeTable(int nSize)
++{
++        register int nIndex;
++
++        for ( nIndex=0; nIndex < nSize; nIndex++ )
++        {
++                if ( PolEdges[nIndex] != NULL )
++                        ParseAndFreeList( PolEdges[nIndex] );
++        }
++        free( PolEdges );
++}
++
++
++void Free_All_Strips()
++{
++
++      ListHead *pListHead;
++      register int y;
++
++      for (y =0; ; y++)
++      {
++              pListHead = all_strips[y];
++              if (pListHead == NULL)
++                      return;
++              else
++                      ParseAndFreeList(all_strips[y]);
++      }
++}
++
++void End_Face_Struct(int numfaces)
++{
++     FreeFaceTable(numfaces);
++}
++
++void End_Edge_Struct(int numverts)
++{
++     FreeEdgeTable(numverts);
++}     
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4c1d055c640e163bad25b219faba4f50d852fb52
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: free.h
++-----------------------------------------------------------------------*/
++
++void Free_All_Strips();
++void ParseAndFreeList( ListHead *pListHead );
++void FreePolygonNode( PF_VERTS pfVerts);
++void Free_Strips();
++void FreeFaceTable(int nSize);
++void FreeEdgeTable(int nSize);
++void End_Face_Struct(int numfaces);
++void End_Edge_Struct(int numverts);
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3538f82f41f03084510259eb493a9f31f23b2552
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,44 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: global.h
++-----------------------------------------------------------------------*/
++
++#ifndef _GLOBAL_H
++#define _GLOBAL_H
++
++
++#define   VRDATA              double
++#define   STRIP_MAX            60
++      
++#define       TRUE            1
++#define       FALSE           0
++
++#ifndef PI
++#define   PI          3.1415926573
++#endif
++
++#define   ATOI(C)        (C -'0')
++#define   X              0
++#define   Y              1
++#define   Z              2
++#define   EVEN(x)       (((x) & 1) == 0)
++#define   MAX_BAND      10000
++
++struct vert_struct {
++      VRDATA  x, y, z;        /* point coordinates */
++};
++
++extern int     ids[STRIP_MAX];
++extern int     norms[STRIP_MAX];
++extern int     *vert_norms;
++extern int     *vert_texture;
++
++
++#endif _GLOBAL_H
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2e0f25885df06164b3d30104e5c57ce324456572
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,217 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: init.c
++     This file contains the initialization of data structures.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "global.h"
++#include "polverts.h"
++
++void init_vert_norms(int num_vert)
++{
++     /*   Initialize vertex/normal array to have all zeros to
++          start with.
++     */
++     register int x;
++
++     for (x = 0; x < num_vert; x++)
++          *(vert_norms + x) = 0;
++}
++
++void init_vert_texture(int num_vert)
++{
++     /*   Initialize vertex/normal array to have all zeros to
++          start with.
++     */
++     register int x;
++
++     for (x = 0; x < num_vert; x++)
++          *(vert_texture + x) = 0;
++}
++
++BOOL InitVertTable( int nSize )
++{
++     register int nIndex;
++
++      /*   Initialize the vertex table */
++     PolVerts = (ListHead**) malloc(sizeof(ListHead*) * nSize ); 
++      if ( PolVerts )
++      {
++              for ( nIndex=0; nIndex < nSize; nIndex++ )
++              {
++                      PolVerts[nIndex] = NULL;
++              }
++              return( TRUE ); 
++      }
++      return( FALSE );
++}  
++
++BOOL InitFaceTable( int nSize )
++{
++        register int nIndex;
++
++        /*     Initialize the face table */
++        PolFaces = (ListHead**) malloc(sizeof(ListHead*) * nSize ); 
++        if ( PolFaces )
++        {
++                for ( nIndex=0; nIndex < nSize; nIndex++ )
++                {
++                        PolFaces[nIndex] = NULL;
++                }
++                return( TRUE );
++        }
++        return( FALSE );
++} 
++
++BOOL InitEdgeTable( int nSize )
++{
++        register int nIndex;
++
++        /*     Initialize the edge table */
++        PolEdges = (ListHead**) malloc(sizeof(ListHead*) * nSize );
++        if ( PolEdges )
++        {
++                for ( nIndex=0; nIndex < nSize; nIndex++ )
++                {
++                        PolEdges[nIndex] = NULL;
++                }
++                return( TRUE );
++        }
++        return( FALSE );
++}
++
++
++void InitStripTable(  )
++{
++
++     PLISTHEAD pListHead;
++
++     /*   Initialize the strip table */
++     pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
++      if ( pListHead )
++     {
++              InitList( pListHead );
++              strips[0] = pListHead;
++      }
++     else
++      {
++           printf("Out of memory !\n");
++              exit(0);
++      }
++
++}
++
++void Init_Table_SGI()
++{
++      PLISTHEAD pListHead;
++      int max_adj = 60;
++      register int x;
++      
++      /*   This routine will initialize the table that will
++              have the faces sorted by the number of adjacent polygons
++              to it.
++      */
++
++      for (x=0; x< max_adj; x++)
++      {
++              /* We are allowing the max number of sides of a polygon
++       to be max_adj.
++              */                      
++              pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
++              if ( pListHead )
++        {
++                InitList( pListHead );
++                      array[x] = pListHead;
++              }
++    else
++              {
++                printf("Out of memory !\n");
++                      exit(0);
++              }
++      }
++}
++
++void BuildVertTable( int nSize )
++{
++  register int nIndex;
++  PLISTHEAD pListHead;
++      
++      for ( nIndex=0; nIndex < nSize; nIndex++ )
++      {
++              pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
++              if ( pListHead )
++    {
++                      InitList( pListHead );
++                      PolVerts[nIndex] = pListHead;
++              }
++    else
++      return; 
++              
++      }
++}
++   
++
++void BuildFaceTable( int nSize )
++{
++        register int nIndex;
++        PLISTHEAD pListHead;
++        
++        for ( nIndex=0; nIndex < nSize; nIndex++ )
++        {
++                pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
++                if ( pListHead )
++                {
++                        InitList( pListHead );
++                        PolFaces[nIndex] = pListHead;
++                }
++                else
++                        return; 
++                
++        }
++}
++   
++void BuildEdgeTable( int nSize )
++{
++        register int nIndex;
++        PLISTHEAD pListHead;
++
++        for ( nIndex=0; nIndex < nSize; nIndex++ )
++        {
++                pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
++                if ( pListHead )
++                {
++                        InitList( pListHead );
++                        PolEdges[nIndex] = pListHead;
++                }
++                else
++                        return;
++        }
++}
++
++void Start_Face_Struct(int numfaces)
++{
++      if (InitFaceTable(numfaces))
++      {
++              BuildFaceTable(numfaces);
++      }
++}
++
++void Start_Edge_Struct(int numverts)
++{
++        if (InitEdgeTable(numverts))
++        {
++                BuildEdgeTable(numverts);
++        }
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fe9a05fd766db067a674a00462c5cc0bad787d24
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,30 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: init.h
++-----------------------------------------------------------------------*/
++
++void init_vert_norms(int num_vert);
++void init_vert_texture(int num_vert);
++BOOL InitVertTable( int nSize );
++BOOL InitFaceTable( int nSize );
++BOOL InitEdgeTable( int nSize );
++void InitStripTable(  );
++void Init_Table_SGI();
++void BuildVertTable( int nSize );
++void BuildFaceTable( int nSize );
++void BuildEdgeTable( int nSize );
++void Start_Face_Struct(int numfaces);
++void Start_Edge_Struct(int numverts);
++
++
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3f3e69da15459be3bed472c3b2669b205151025d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,119 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: local.c
++     This file contains the code that initializes the data structures for
++     the local algorithm, and starts the local algorithm going.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "polverts.h"
++#include "local.h"
++#include "triangulatex.h"
++#include "sturctsex.h"
++#include "common.h"
++#include "outputex.h"
++#include "util.h"
++#include "init.h"
++
++void Find_StripsEx(FILE *output, FILE *strip,int *ties, int tie, 
++                 int triangulate, int swaps, int *next_id)
++{
++      /*      This routine will peel off the strips from the model */
++
++      ListHead *pListHead;
++      P_ADJACENCIES temp = NULL;
++      register int max,bucket=0;
++      BOOL whole_flag = TRUE;
++     int dummy = 0;
++      
++      /* Set the last known input edge to be null */
++  Last_Edge(&dummy,&dummy,&dummy,1);
++    
++  /* Search for lowest adjacency polygon and output strips */
++      while (whole_flag)
++      {
++              bucket = -1;
++              /* Search for polygons in increasing number of adjacencies */
++              while (bucket < 59)
++              {
++                      bucket++;
++                      pListHead = array[bucket];
++                      max = NumOnList(pListHead);
++                      if (max > 0)
++                      {
++                              temp = (P_ADJACENCIES) PeekList(pListHead,LISTHEAD,0);
++                              if (temp == NULL)
++                              {
++                                      printf("Error in the buckets%d %d %d\n",bucket,max,0);
++                                      exit(0);
++                              }
++                              Polygon_OutputEx(temp,temp->face_id,bucket,pListHead,
++                                             output,strip,ties,tie,triangulate,swaps,next_id,1);
++                              /* Try to extend backwards, if the starting polygon in the
++           strip had 2 or more adjacencies to begin with
++        */
++        if (bucket >= 2)
++          Extend_BackwardsEx(temp->face_id,output,strip,ties,tie,triangulate,swaps,next_id);
++        break;  
++                      }
++              }
++              /*      Went through the whole structure, it is empty and we are done.
++              */
++              if ((bucket == 59) && (max == 0))
++                      whole_flag = FALSE;
++        
++    /*  We just finished a strip, send dummy data to signal the end
++        of the strip so that we can output it.
++    */
++    else
++    {
++      Output_TriEx(-1,-2,-3,output,-1,-10,1);
++      Last_Edge(&dummy,&dummy,&dummy,1);
++    }
++  }
++}
++
++
++void SGI_Strip(int num_verts,int num_faces,FILE *output,
++                         int ties,int triangulate)
++               
++{
++      FILE *strip;
++  int next_id = -1,t=0;
++
++  strip = fopen("output.d","w");
++  /* We are going to output and find triangle strips
++       according the the method that SGI uses, ie always
++               choosing as the next triangle in our strip the triangle
++               that has the least number of adjacencies. We do not have
++               all triangles and will be triangulating on the fly those
++               polygons that have more than 3 sides.
++      */
++
++      /*      Build a table that has all the polygons sorted by the number
++              of polygons adjacent to it.
++      */
++      /*      Initialize it */
++      Init_Table_SGI();
++      /*      Build it */
++      Build_SGI_Table(num_verts,num_faces);
++
++      /*    We will have a structure to hold all the strips, until
++        outputted.
++  */
++  InitStripTable();
++  /* Now we have the structure built to find the polygons according
++               to the number of adjacencies. Now use the SGI Method to find
++               strips according to the adjacencies
++      */
++  Find_StripsEx(output,strip,&t,ties,triangulate,ON,&next_id);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..df5256f6ac509dc902f4b254e6689bd4c603115e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,20 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE:local.h
++-----------------------------------------------------------------------*/
++
++void Local_Polygon_Output();
++void Local_Output_Tri();
++int Different();
++void Local_Non_Blind_Triangulate();
++void Local_Blind_Triangulate();
++void Local_Triangulate_Polygon();
++void SGI_Strip(int num_verts,int num_faces,FILE *output,
++             int ties,int triangulate);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6267bbc42fe1a4fde2816b962e1fcccedbe99b34
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1659 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: newpolve.c
++     This routine contains the bulk of the code that will find the
++     patches of quads in the data model
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdlib.h>
++#include "polverts.h"
++#include "extend.h"
++#include "output.h"
++#include "triangulate.h"
++#include "common.h"
++#include "util.h"
++#include "global.h"        
++#include "init.h"
++#include "add.h"
++
++ListHead **PolVerts;
++ListHead **PolFaces;
++ListHead **PolEdges;
++int length;
++BOOL resetting = FALSE;
++int     ids[STRIP_MAX];
++int   added_quad = 0;
++BOOL reversed = FALSE;
++int patch = 0;
++extern int *vn;
++extern int *vt;
++
++int Calculate_Walks(int lastvert,int y, PF_FACES temp2)
++{
++      /* Find the length of the walk */
++      
++      int previous_edge1, previous_edge2;
++      register int nextvert,numverts,counter,walk=0;
++      BOOL flag;
++      F_EDGES *node;
++     ListHead *pListHead;
++     static int seen = 0;
++     
++      /* Find the edge that we are currently on */
++      if (y != 3)
++      {
++              previous_edge1 = *(temp2->pPolygon +y);
++              previous_edge2 = *(temp2->pPolygon + y + 1);
++      }
++      else
++      {
++              previous_edge1 = *(temp2->pPolygon +y);
++              previous_edge2 = *(temp2->pPolygon);
++      }
++
++      temp2->seen = seen;
++     counter = y;
++
++     /*Find the adjacent face to this edge */
++      node = *(temp2->VertandId+y);                   
++      if (node->edge[2] != lastvert)
++        nextvert = node->edge[2];
++     else
++        nextvert = node->edge[1];
++                                      
++      /* Keep walking in this direction until we cannot do so */
++      while ((nextvert != lastvert) && (nextvert != -1))
++      {
++              walk++;
++              pListHead = PolFaces[nextvert];
++              temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++              numverts = temp2->nPolSize;
++              if ((numverts != 4) || (temp2->seen == seen))
++              {
++                      walk--;
++                      nextvert = -1;
++              }
++              else
++              {
++                      temp2->seen = seen;
++               /* Find edge that is not adjacent to the previous one */
++                      counter = 0;
++                      flag = TRUE;
++                      while ((counter < 3) && (flag))
++                      {
++                              if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                                      (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                                      ((*(temp2->pPolygon+counter) == previous_edge2) || 
++                                      (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                                      counter++;              
++                              else
++                                      flag = FALSE;   
++                      }
++              /* Get the IDs of the next edge */
++                   if (counter < 3)
++                   {
++                           previous_edge1 = *(temp2->pPolygon + counter);
++                           previous_edge2 = *(temp2->pPolygon + counter + 1);
++                   }
++                   else
++                   {
++                    previous_edge1 = *(temp2->pPolygon + counter);
++                    previous_edge2 = *(temp2->pPolygon);
++                   }
++      
++                   node = *(temp2->VertandId + counter);
++                   if (node->edge[1] == nextvert)
++                           nextvert = node->edge[2];
++                   else
++                           nextvert = node->edge[1];
++              }
++      }
++     seen++;
++      return walk;
++}
++
++
++BOOL Check_Right(int last_seen,PF_FACES temp2,int y,int face_id)
++{
++      /* Check when we last saw the face to the right of the current
++         one. We want to have seen it just before we started this strip
++      */
++
++      F_EDGES *node;
++      ListHead *pListHead;
++      register int nextvert,oldy;
++      PF_FACES t;
++      
++     oldy = y;
++      if (y != 3)
++              y = y+1;
++      else
++              y = 0;
++      node = *(temp2->VertandId + y);
++      if (face_id == node->edge[1])
++              nextvert = node->edge[2];
++      else
++              nextvert = node->edge[1];
++      
++     if (nextvert == -1)
++          return FALSE;
++     
++     pListHead = PolFaces[nextvert];
++      t = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++      if (t->seen != (last_seen - 1))
++      {
++               /* maybe because of the numbering, we are not
++                  on the right orientation, so we have to check the
++                  opposite one to be sure 
++           */
++              if (oldy != 0)
++                      y = oldy-1;
++              else
++                      y = 3;
++              node = *(temp2->VertandId + y);
++              if (face_id == node->edge[1])
++                      nextvert = node->edge[2];
++              else
++                      nextvert = node->edge[1];
++              if (nextvert == -1)
++               return FALSE;
++          pListHead = PolFaces[nextvert];
++              t = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++              if (t->seen != (last_seen - 1))
++                      return FALSE;
++      }
++      return TRUE;
++}
++
++
++int Update_and_Test(PF_FACES temp2,int y,BOOL first,int distance,int lastvert, int val)
++{
++           
++        static int last_seen = 17;
++        int previous_edge1, previous_edge2;
++        register int original_distance,nextvert,numverts,counter;
++        BOOL flag;
++        F_EDGES *node;
++        ListHead *pListHead;
++                                                        
++        original_distance = distance;
++        /* Find the edge that we are currently on */
++        if (y != 3)
++        {
++                previous_edge1 = *(temp2->pPolygon +y);
++                previous_edge2 = *(temp2->pPolygon + y + 1);
++        }
++        else
++        {
++                previous_edge1 = *(temp2->pPolygon +y);
++                previous_edge2 = *(temp2->pPolygon);
++        }
++
++        temp2->seen = val;
++        temp2->seen2 = val;
++              
++        node = *(temp2->VertandId+y);                   
++        if (lastvert != node->edge[2])
++                      nextvert = node->edge[2];
++         else
++                      nextvert = node->edge[1];
++                                        
++        /* Keep walking in this direction until we cannot do so  or
++              we go to distance */
++        while ((distance > 0)  && (nextvert != lastvert) && (nextvert != -1))
++        {
++                distance--;
++                                 
++                pListHead = PolFaces[nextvert];
++                temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++                temp2->seen = val;
++                              
++                if (temp2->seen2 == val)
++                {
++                     last_seen++;
++                     return (original_distance - distance);
++                }
++                
++                temp2->seen2 = val;
++                
++                numverts = temp2->nPolSize;
++                                
++               if (numverts != 4)
++                   nextvert = -1;
++              
++                else if ((!first) && (!(Check_Right(last_seen,temp2,y,nextvert))))
++                {
++                    last_seen++;
++                    return (original_distance - distance);
++                }
++                    else
++                {
++                        /* Find edge that is not adjacent to the previous one */
++                        counter = 0;
++                        flag = TRUE;
++                        while ((counter < 3) && (flag))
++                        {
++                                if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                                        (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                                        ((*(temp2->pPolygon+counter) == previous_edge2) ||
++                                        (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                                        counter++;
++                                else
++                                        flag = FALSE;
++                        }
++                        /* Get the IDs of the next edge */
++                        if (counter < 3)
++                        {
++                              previous_edge1 = *(temp2->pPolygon + counter);
++                              previous_edge2 = *(temp2->pPolygon + counter + 1);
++                        }
++                        else
++                        {
++                              previous_edge1 = *(temp2->pPolygon + counter);
++                              previous_edge2 = *(temp2->pPolygon);
++                        }
++                        if      ( ((*(temp2->walked+counter) == -1) && 
++                                (*(temp2->walked+counter+2) == -1)))
++                        {
++                                printf("There is an error in the walks!\n");
++                                printf("1Code %d %d \n",*(temp2->walked+counter),*(temp2->walked+counter+2));
++                                exit(0);
++                        }
++                        else
++                        {
++                                if      ((*(temp2->walked+counter) == -1) && 
++                                        (*(temp2->walked+counter-2) ==  -1))
++                                {
++                                        printf("There is an error in the walks!\n");
++                                        printf("2Code %d %d \n",*(temp2->walked+counter),*(temp2->walked+counter-2));
++                                        exit(0);
++                                }
++                        }
++                        node = *(temp2->VertandId + counter);
++                        y = counter;
++                            if (node->edge[1] == nextvert)
++                              nextvert = node->edge[2];
++                        else
++                              nextvert = node->edge[1];
++             }
++    }
++      
++    last_seen++;
++
++    if  (distance != 0)  
++    {
++              if (((nextvert == -1) || (nextvert == lastvert)) && (distance != 1))
++                      return (original_distance - distance);
++    }
++    return original_distance;
++}
++
++
++int Test_Adj(PF_FACES temp2,int x,int north,int distance,int lastvert, int value)
++{
++      /* if first time, then just update the last seen field */
++      if (x==1)
++              return(Update_and_Test(temp2,north,TRUE,distance,lastvert,value));
++      /* else we have to check if we are adjacent to the last strip */
++      else
++              return(Update_and_Test(temp2,north,FALSE,distance,lastvert,value));
++}
++  
++void Get_Band_Walk(PF_FACES temp2,int face_id,int *dir1,int *dir2, 
++                                      int orientation,int cutoff_length)
++{
++      int previous_edge1, previous_edge2;
++      F_EDGES *node;
++      ListHead *pListHead;
++      register int walk = 0, nextvert,numverts,counter;
++      BOOL flag;
++      
++      /*      Get the largest band that will include this face, starting
++              from orientation. Save the values of the largest band
++              (either north and south together, or east and west together)
++              in the direction variables.
++      */
++      /* Find the edge that we are currently on */
++     if (orientation != 3)
++     {
++                previous_edge1 = *(temp2->pPolygon + orientation);
++                previous_edge2 = *(temp2->pPolygon + orientation + 1);
++     }
++     else
++     {
++                previous_edge1 = *(temp2->pPolygon + orientation );
++                previous_edge2 = *(temp2->pPolygon);
++     }
++              
++     if (orientation == 0)
++     {
++                       if (*dir1 > *(temp2->walked + 1))
++                              *dir1 = *(temp2->walked + 1);
++                       if (*dir2 > *(temp2->walked + 3))
++                              *dir2 = *(temp2->walked + 3);
++      }
++      else if (orientation == 3)
++      {
++                      if (*dir1 > *(temp2->walked + orientation - 3))
++                           *dir1 = *(temp2->walked + orientation - 3) ;
++                      if (*dir2 > *(temp2->walked + orientation -1 ))
++                              *dir2 = *(temp2->walked + orientation - 1);
++      }
++      else
++      {
++                      if (*dir1 > *(temp2->walked + orientation - 1))
++                              *dir1 = *(temp2->walked + orientation -1) ;
++                      if (*dir2 > *(temp2->walked+ orientation + 1))
++                              *dir2 = *(temp2->walked + orientation + 1);
++      }
++        
++     /*       if we know already that we can't extend the
++              band from this face, we do not need to do the walk
++     */
++     if ((*dir1 != 0) && (*dir2 != 0))
++     {
++              /* Find the adjacent face to this edge */
++              node = *(temp2->VertandId+orientation);                   
++              if (face_id == node->edge[1])
++                      nextvert = node->edge[2];
++              else 
++                      nextvert = node->edge[1];
++      }
++     else
++              nextvert = -1; /* leave w/o walking */                                
++      
++      /* Keep walking in this direction until we cannot do so */
++     while ((nextvert != face_id) && (nextvert != -1))
++     {
++            walk++;
++            pListHead = PolFaces[nextvert];
++            temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++            numverts = temp2->nPolSize;
++            if ((numverts != 4)       || (walk > cutoff_length))
++                   nextvert = -1;
++            else
++            {
++                        /* Find edge that is not adjacent to the previous one */
++                 counter = 0;
++                 flag = TRUE;
++                 while ((counter < 3) && (flag))
++                 {
++                           if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                                (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                                ((*(temp2->pPolygon+counter) == previous_edge2) ||
++                                (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                                     counter++;
++                           else
++                                flag = FALSE;
++                 }
++                 /* Get the IDs of the next edge */
++                 if (counter < 3)
++                 {
++                        previous_edge1 = *(temp2->pPolygon + counter);
++                        previous_edge2 = *(temp2->pPolygon + counter + 1);
++                 }
++                 else
++                 {
++                        previous_edge1 = *(temp2->pPolygon + counter);
++                        previous_edge2 = *(temp2->pPolygon);
++                 }
++                
++                        /*    find out how far we can extend in the 2 directions
++                                      along this new face in the walk
++                        */
++                        if (counter == 0)
++                        {
++                                      if (*dir1 > *(temp2->walked + 1))
++                                              *dir1 = *(temp2->walked + 1);
++                                      if (*dir2 > *(temp2->walked + 3))
++                                              *dir2 = *(temp2->walked + 3);
++                        }
++                        else if (counter == 3)
++                        {
++                                      if (*dir1 > *(temp2->walked + counter - 3))
++                                              *dir1 = *(temp2->walked + counter - 3) ;
++                                      if (*dir2 > *(temp2->walked + counter -1 ))
++                                              *dir2 = *(temp2->walked + counter -1);
++                        }
++                        else
++                        {
++                                      if (*dir1 > *(temp2->walked + counter - 1))
++                                              *dir1 = *(temp2->walked + counter -1) ;
++                                      if (*dir2 > *(temp2->walked + counter + 1))
++                                              *dir2 = *(temp2->walked + counter + 1);
++                        }
++        
++                    /*        if we know already that we can't extend the
++                      band from this face, we do not need to do the walk
++                    */
++                       if ((*dir1 == 0) || (*dir2 == 0))
++                      nextvert = -1;
++                if (nextvert != -1)
++                {
++                      node = *(temp2->VertandId + counter);
++                      if (node->edge[1] == nextvert)
++                        nextvert = node->edge[2];
++                      else
++                        nextvert = node->edge[1];
++                }
++
++           }
++        }
++}
++
++
++
++
++int Find_Max(PF_FACES temp2,int lastvert,int north,int left,
++                      int *lastminup,int *lastminleft)
++{
++      int temp,walk,counter,minup,x,band_value;
++      int previous_edge1, previous_edge2;
++      F_EDGES *node;
++      ListHead *pListHead;
++      BOOL flag;      
++      static int last_seen = 0;
++      register int smallest_so_far,nextvert,max=-1;
++              
++     *lastminup = MAX_BAND;
++      *lastminleft = 1;
++
++     if (left == 3)
++      {
++          previous_edge1 = *(temp2->pPolygon + left);
++          previous_edge2 = *(temp2->pPolygon);
++      }
++                
++      else
++      {
++          previous_edge1 = *(temp2->pPolygon + left + 1);
++          previous_edge2 = *(temp2->pPolygon + left);
++      }
++
++      temp2->seen = last_seen;
++     walk = *(temp2->walked + left);
++
++     for (x=1;x<=(walk+1); x++)
++      {
++              /*   test to see if we have a true band
++                   that is, are they adjacent to each other
++              */
++        
++         minup = *(temp2->walked + north) + 1;
++
++          /*  if we are at the very first face, then we do not
++                   have to check the adjacent faces going up
++                   and our north distance is the distance of this face's
++                      north direction. 
++          */
++         if (x == 1) 
++          {
++                      *lastminup = minup;
++                      minup = Test_Adj(temp2,x,north,*lastminup,lastvert,last_seen);
++                      *lastminup = minup;
++               smallest_so_far = minup;       
++         }
++              
++      
++          /* find the largest band that we can have */
++          if (minup < (*lastminup))
++          {
++                      /*      see if we really can go up all the way 
++                              temp should by less than our equal to minup
++                              if it is less, then one of the faces was not
++                              adjacent to those next to it and the band height
++                              will be smaller
++                      */
++                      temp = Test_Adj(temp2,x,north,minup,lastvert,last_seen);
++                      if (temp > minup)
++                      {
++                              printf("There is an error in the test adj\n");
++                              exit(0);
++                      }
++                      minup = temp;
++                      band_value = x * minup;
++                      if (minup < smallest_so_far)
++                      {
++                              if (band_value > max)
++                      {
++                                      smallest_so_far = minup;
++                                      *lastminup = minup;
++                                      *lastminleft = x;
++                         max = band_value;
++                    }
++                              else
++                                      smallest_so_far = minup;
++                      }
++                      else
++                      {
++                              band_value = x * smallest_so_far;
++                if (band_value > max)
++                    {
++                           *lastminup = smallest_so_far;
++                         *lastminleft = x;
++                         max = band_value;
++                    }
++                      }
++              }
++              else
++              {
++                      if (x != 1)
++               {
++                    temp = Test_Adj(temp2,x,north,smallest_so_far,lastvert,last_seen);
++                           if (temp > smallest_so_far)
++                           {
++                                  printf("There is an error in the test adj\n");
++                                  exit(0);
++                           }
++                          smallest_so_far = temp;
++               }
++               band_value = x * smallest_so_far; 
++                      if (band_value > max)
++                      {
++                              *lastminup = smallest_so_far;
++                              *lastminleft = x;
++                              max = band_value;
++                      }
++              }
++              if ( x != (walk + 1))
++              {
++                      node = *(temp2->VertandId+left);
++                      if (lastvert == node->edge[1])
++                              nextvert = node->edge[2];
++                      else
++                              nextvert = node->edge[1];
++
++               lastvert = nextvert;
++               
++               if (nextvert == -1)
++                    return max;
++               
++               pListHead = PolFaces[nextvert];
++                      temp2 = (PF_FACES) PeekList(pListHead, LISTHEAD, 0);
++                      
++               /* if we have visited this face before, then there is an error */
++               if (((*(temp2->walked) == -1) && (*(temp2->walked+1) == -1) &&
++                              (*(temp2->walked+2) == -1) && (*(temp2->walked+3) == -1))
++                              || (temp2->nPolSize !=4) || (temp2->seen == last_seen))
++                      {
++
++                    if (lastvert == node->edge[1])
++                         nextvert = node->edge[2];
++                    else
++                         nextvert = node->edge[1];
++                    if (nextvert == -1)
++                         return max;
++                    lastvert = nextvert;
++                    /*   Last attempt to get the face ... */
++                    pListHead = PolFaces[nextvert];
++                      temp2 = (PF_FACES) PeekList(pListHead, LISTHEAD, 0);
++                    if (((*(temp2->walked) == -1) && (*(temp2->walked+1) == -1) &&
++                                   (*(temp2->walked+2) == -1) && (*(temp2->walked+3) == -1))
++                                   || (temp2->nPolSize !=4) || (temp2->seen == last_seen))
++                         return max;    /*   The polygon was not saved with the edge, not
++                                             enough room. We will get the walk when we come
++                                             to that polygon later.
++                                        */
++                      }
++                      /*else
++                      {*/
++                              counter = 0;
++                              flag = TRUE;
++                              temp2->seen = last_seen;
++
++                    while ((counter < 3) && (flag))
++                           {
++
++                         if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                                        (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                                        ((*(temp2->pPolygon+counter) == previous_edge2) ||
++                                        (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                                        counter++;
++                                   else
++                                        flag = FALSE;
++                    }
++               /*}*/
++              
++               /* Get the IDs of the next edge */
++               left = counter;
++                   north = left+1;
++               if (left ==3)
++                           north = 0; 
++                   if (counter < 3)
++               {
++                        previous_edge1 = *(temp2->pPolygon + counter + 1);
++                        previous_edge2 = *(temp2->pPolygon + counter);
++               }
++               else
++               {
++                        previous_edge1 = *(temp2->pPolygon + counter);
++                        previous_edge2 = *(temp2->pPolygon);
++               }
++
++          } 
++
++}
++last_seen++;
++return max;
++}
++
++void Mark_Face(PF_FACES temp2, int color1, int color2,
++                              int color3, FILE *output_file, BOOL end, int *edge1, int *edge2, 
++                    int *face_id, int norms, int texture)
++{
++     static int last_quad[4];
++     int x,y,z=0;
++     int saved[2];
++     static int output1, output2,last_id;
++     BOOL cptexture = FALSE;
++
++     /*   Are we done with the patch? If so return the last edge that
++          we will come out on, and that will be the edge that we will
++          start to extend upon.
++     */
++
++     if (end)
++     {
++          *edge1 = output1;
++          *edge2 = output2;
++          *face_id = last_id;
++          return;
++     }
++
++     cptexture = texture;
++     last_id = *face_id;
++      *(temp2->walked) = -1;
++      *(temp2->walked+1) = -1;
++      *(temp2->walked+2) = -1;
++      *(temp2->walked+3) = -1;
++      added_quad++;
++      temp2->nPolSize = 1;
++
++     if (patch == 0)
++     {
++          /*   At the first quad in the strip -- save it */
++          last_quad[0] = *(temp2->pPolygon);
++          last_quad[1] = *(temp2->pPolygon+1);
++          last_quad[2] = *(temp2->pPolygon+2);
++          last_quad[3] = *(temp2->pPolygon+3);
++          patch++;
++     }
++     else
++     {
++          /*   Now we have a triangle to output, find the edge in common */
++          for (x=0; x < 4 ;x++)
++          {
++              for (y=0; y< 4; y++)
++              {
++                   if (last_quad[x] == *(temp2->pPolygon+y))
++                   {
++                        saved[z++] = last_quad[x];               
++                        if (z > 2)
++                        {
++                             /*    This means that there was a non convex or
++                                   an overlapping polygon
++                             */
++                             z--;
++                             break;
++                        }
++                   }                             
++              }
++          }
++          
++          if (z != 2)
++          {
++               printf("Z is not 2 %d \n",patch);
++               printf("4 %d %d %d %d %d %d %d\n",*(temp2->pPolygon),
++                              *(temp2->pPolygon+1),*(temp2->pPolygon+2),*(temp2->pPolygon+3),
++                              color1,color2,color3);
++               printf("%d %d %d %d\n",last_quad[0],last_quad[1],last_quad[2],last_quad[3]);
++               exit(1);
++          }
++          
++          if (patch == 1)
++          {
++               /*   First one to output, there was no output edge */
++               patch++;
++               x = Adjacent(saved[0],saved[1],last_quad,4);
++               y = Adjacent(saved[1],saved[0],last_quad,4);
++               
++               /*   Data might be mixed and we do not have textures for some of the vertices */
++               if ((texture) && ( ((vt[x]) == 0) || ((vt[y])==0) || ((vt[saved[1]])==0)))
++                    cptexture = FALSE;
++
++               if ((!norms) && (!cptexture))
++               {
++                    fprintf(output_file,"\nt %d %d %d ",x+1,y+1,saved[1]+1);
++                    fprintf(output_file,"%d ",saved[0]+1);
++               }
++               else if ((norms) && (!cptexture))
++               {
++                    fprintf(output_file,"\nt %d//%d %d//%d %d//%d ",x+1,vn[x] +1,
++                                                                    y+1,vn[y] +1,
++                                                                    saved[1]+1,vn[saved[1]]+1);
++                    fprintf(output_file,"%d//%d ",saved[0]+1,vn[saved[0]]+1);
++               }
++               else if ((cptexture) && (!norms))
++               {
++                    fprintf(output_file,"\nt %d/%d %d/%d %d/%d ",x+1,vt[x] +1,
++                                                                    y+1,vt[y] +1,
++                                                                    saved[1]+1,vt[saved[1]]+1);
++                    fprintf(output_file,"%d//%d ",saved[0]+1,vt[saved[0]]+1);
++               }
++               else
++               {
++                    fprintf(output_file,"\nt %d/%d/%d %d/%d/%d %d/%d/%d ",x+1,vt[x]+1,vn[x] +1,
++                                                                    y+1,vt[y]+1,vn[y] +1,
++                                                                    saved[1]+1,vt[saved[1]]+1,vn[saved[1]]+1);
++                    fprintf(output_file,"%d/%d/%d ",saved[0]+1,vt[saved[0]]+1,vn[saved[0]]+1);
++               }
++
++               x = Adjacent(saved[0],saved[1],temp2->pPolygon,4);
++               y = Adjacent(saved[1],saved[0],temp2->pPolygon,4);
++
++               /*   Data might be mixed and we do not have textures for some of the vertices */
++               if ((texture) && ( (vt[x] == 0) || (vt[y]==0)))
++               {
++                    if (cptexture)
++                         fprintf(output_file,"\nq ");
++                    cptexture = FALSE;
++               }
++               if ((!norms) && (!cptexture))
++               {
++                    fprintf(output_file,"%d ",x+1);
++                    fprintf(output_file,"%d ",y+1);
++               }
++               else if ((norms) && (!cptexture))
++               {
++                    fprintf(output_file,"%d//%d ",x+1,vn[x]+1);
++                    fprintf(output_file,"%d//%d ",y+1,vn[y]+1);
++               }
++               else if ((cptexture) && (!norms))
++               {
++                    fprintf(output_file,"%d/%d ",x+1,vt[x]+1);
++                    fprintf(output_file,"%d/%d ",y+1,vt[y]+1);
++               }
++               else
++               {
++                    fprintf(output_file,"%d/%d/%d ",x+1,vt[x]+1,vn[x]+1);
++                    fprintf(output_file,"%d/%d/%d ",y+1,vt[y]+1,vn[y]+1);
++               }
++
++               output1 = x;
++               output2 = y;
++          }
++          
++          else 
++          {
++               x = Adjacent(output2,output1,temp2->pPolygon,4);
++               y = Adjacent(output1,output2,temp2->pPolygon,4);
++               /*   Data might be mixed and we do not have textures for some of the vertices */
++               if ((texture) && ( ((vt[x]) == 0) || ((vt[y])==0) ))
++                    texture = FALSE;
++
++               if ((!norms) && (!texture))
++               {
++                    fprintf(output_file,"\nq %d ",x+1);
++                    fprintf(output_file,"%d ",y+1);
++               }
++               else if ((norms) && (!texture))
++               {
++                    fprintf(output_file,"\nq %d//%d ",x+1,vn[x]+1);
++                    fprintf(output_file,"%d//%d ",y+1,vn[y]+1);
++               }
++               else if ((texture) && (!norms))
++               {
++                    fprintf(output_file,"\nq %d/%d ",x+1,vt[x]+1);
++                    fprintf(output_file,"%d/%d ",y+1,vt[y]+1);
++               }
++               else
++               {
++                    fprintf(output_file,"\nq %d/%d/%d ",x+1,vt[x]+1,vn[x]+1);
++                    fprintf(output_file,"%d/%d/%d ",y+1,vt[y]+1,vn[y]+1);
++               }
++               
++               output1 = x;
++               output2 = y;
++          }
++          
++          last_quad[0] = *(temp2->pPolygon);
++          last_quad[1] = *(temp2->pPolygon+1);
++          last_quad[2] = *(temp2->pPolygon+2);
++          last_quad[3] = *(temp2->pPolygon+3);
++     }
++}
++
++void Fast_Reset(int x)
++{
++      register int y,numverts;
++      register int front_walk, back_walk;
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++
++     pListHead = PolFaces[x];
++      temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++      numverts = temp->nPolSize;
++     
++     front_walk = 0; 
++     back_walk = 0;          
++     resetting = TRUE;
++          
++     /* we are doing this only for quads */
++      if (numverts == 4)
++      {
++                      /*      for each face not seen yet, do North and South together
++                              and East and West together
++                      */
++                      for (y=0;y<2;y++)
++                      {
++                              /* Check if the opposite sides were seen already */
++                      /* Find walk for the first edge */
++                              front_walk = Calculate_Walks(x,y,temp);
++                              /* Find walk in the opposite direction */
++                              back_walk = Calculate_Walks(x,y+2,temp);
++                              /*      Now put into the data structure the numbers that
++                              we have found
++                              */
++                    Assign_Walk(x,temp,front_walk,y,back_walk);
++                              Assign_Walk(x,temp,back_walk,y+2,front_walk);
++                      }
++      }
++     resetting = FALSE;
++}
++
++
++void Reset_Max(PF_FACES temp2,int face_id,int north,int last_north, int orientation,
++              int last_left,FILE *output_file,int color1,int color2,int color3,
++              BOOL start)
++{
++      int previous_edge1,previous_edge2;
++      F_EDGES *node;
++      ListHead *pListHead;
++      int f,t,nextvert,counter;
++     BOOL flag;
++
++ 
++     /*   Reset walks on faces, since we just found a patch */
++     if (orientation !=3)
++     {
++                previous_edge1 = *(temp2->pPolygon + orientation+1);
++                previous_edge2 = *(temp2->pPolygon + orientation );
++     }
++     else
++     {
++                previous_edge1 = *(temp2->pPolygon + orientation );
++                previous_edge2 = *(temp2->pPolygon);
++     }
++
++      /* only if we are going left, otherwise there will be -1 there */
++      /*Find the adjacent face to this edge */
++        
++     for (t = 0; t <=3 ; t++)
++     {
++             node = *(temp2->VertandId+t);
++              
++             if (face_id == node->edge[1])
++                f = node->edge[2];
++             else
++               f = node->edge[1];
++       
++             if (f != -1)
++                  Fast_Reset(f);
++        }
++
++        node = *(temp2->VertandId+orientation);
++        if (face_id == node->edge[1])
++             nextvert = node->edge[2];
++        else
++             nextvert = node->edge[1];
++
++      while ((last_left--) > 1)
++      {
++               
++          if (start)
++               Reset_Max(temp2,face_id,orientation,last_left,north,last_north,output_file,color1,color2,color3,FALSE);                
++        
++          face_id = nextvert;
++          pListHead = PolFaces[nextvert];                
++          temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++          if ((temp2->nPolSize != 4) && (temp2->nPolSize != 1))
++          {
++             /*   There is more than 2 polygons on the edge, and we could have
++                  gotten the wrong one
++             */
++             if (nextvert != node->edge[1])
++                  nextvert = node->edge[1];
++             else
++                  nextvert = node->edge[2];
++             pListHead = PolFaces[nextvert];          
++             temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++             node = *(temp2->VertandId+orientation);
++          }
++
++                
++         if (!start)
++         {
++             for (t = 0; t <=3 ; t++)
++             {
++                    node = *(temp2->VertandId+t);
++              
++                    if (face_id == node->edge[1])
++                         f = node->edge[2];
++                    else
++                         f = node->edge[1];
++          
++                    if (f != -1)
++                         Fast_Reset(f);
++             }
++        }
++
++
++        counter = 0;
++         flag = TRUE;
++         while ((counter < 3) && (flag))
++        {
++             if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                   (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                  ((*(temp2->pPolygon+counter) == previous_edge2) ||
++                   (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                   counter++;
++             else
++                  flag = FALSE;
++        }
++
++        /* Get the IDs of the next edge */
++        if (counter < 3)
++        {
++             previous_edge1 = *(temp2->pPolygon + counter+1);
++             previous_edge2 = *(temp2->pPolygon + counter);
++        }
++        else
++        {
++             previous_edge1 = *(temp2->pPolygon + counter);
++             previous_edge2 = *(temp2->pPolygon);
++        }
++        orientation = counter;
++
++        node = *(temp2->VertandId + counter);
++         if (node->edge[1] == nextvert)
++                      nextvert = node->edge[2];
++         else
++                      nextvert = node->edge[1];
++
++        if (!reversed)
++        {
++               if (counter != 3)
++                           north = counter +1;
++                   else
++                           north = 0;
++        }
++        else
++        {
++               if (counter != 0)
++                    north = counter -1;
++               else
++                    north = 3;
++    
++        }
++     }
++if (start)
++      Reset_Max(temp2,face_id,orientation,last_left,north,last_north,output_file,color1,color2,color3,FALSE);
++else if (nextvert != -1)       
++     Fast_Reset(nextvert);
++
++}
++
++
++int Peel_Max(PF_FACES temp2,int face_id,int north,int last_north, int orientation,
++              int last_left,FILE *output_file,int color1,int color2,int color3,
++              BOOL start, int *swaps_added, int norms, int texture)
++{
++      int end1,end2,last_id,s=0,walk = 0;
++      int previous_edge1,previous_edge2;
++      static int last_seen = 1000;
++      F_EDGES *node;
++      ListHead *pListHead;
++      int nextvert,numverts,counter,dummy,tris=0;
++     BOOL flag;
++
++     /*   Peel the patch from the model.
++          We will try and extend off the end of each strip in the patch. We will return the
++          number of triangles completed by this extension only, and the number of swaps
++          in the extension only.
++     */       
++     patch = 0;
++     
++     if (orientation !=3)
++     {
++                previous_edge1 = *(temp2->pPolygon + orientation+1);
++                previous_edge2 = *(temp2->pPolygon + orientation );
++     }
++     else
++     {
++                previous_edge1 = *(temp2->pPolygon + orientation );
++                previous_edge2 = *(temp2->pPolygon);
++     }
++
++
++     walk = *(temp2->walked + orientation);
++      
++     /* only if we are going left, otherwise there will be -1 there */
++      if ((start) && ((walk+1) < last_left))
++      {
++              printf("There is an error in the left %d %d\n",walk,last_left);
++              exit(0);
++      }
++      
++     /* Find the adjacent face to this edge */
++     node = *(temp2->VertandId+orientation);
++     if (face_id == node->edge[1])
++          nextvert = node->edge[2];
++     else
++          nextvert = node->edge[1];
++      temp2->seen = last_seen;
++
++
++      while ((last_left--) > 1)
++      {
++              if (start)
++             tris += Peel_Max(temp2,face_id,orientation,last_left,north,last_north,output_file,
++                              color1,color2,color3,FALSE,swaps_added,norms,texture);              
++          else
++             Mark_Face(temp2,color1,color2,color3,output_file,FALSE,&dummy,&dummy,&face_id,norms,texture);
++              
++
++          pListHead = PolFaces[nextvert];      
++          temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++          numverts = temp2->nPolSize;
++      
++          if ((numverts != 4) || (temp2->seen == last_seen) 
++                      ||  (nextvert == -1))
++          {
++      
++             /*   There is more than 2 polygons on the edge, and we could have
++                  gotten the wrong one
++             */
++             if (nextvert != node->edge[1])
++                  nextvert = node->edge[1];
++             else
++                  nextvert = node->edge[2];
++             pListHead = PolFaces[nextvert];
++             temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++             numverts = temp2->nPolSize;
++             if ((numverts != 4) || (temp2->seen == last_seen) )
++             {
++                  printf("Peel 2 %d\n",numverts);
++                  exit(1);
++             }
++        }
++
++        face_id = nextvert;
++        temp2->seen = last_seen;
++                
++        counter = 0;
++        flag = TRUE;
++         while ((counter < 3) && (flag))
++        {
++             if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                   (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                  ((*(temp2->pPolygon+counter) == previous_edge2) ||
++                   (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                   counter++;
++             else
++                  flag = FALSE;
++        }
++        /* Get the IDs of the next edge */
++        if (counter < 3)
++        {
++             previous_edge1 = *(temp2->pPolygon + counter+1);
++             previous_edge2 = *(temp2->pPolygon + counter);
++        }
++        else
++        {
++             previous_edge1 = *(temp2->pPolygon + counter);
++             previous_edge2 = *(temp2->pPolygon);
++        }
++        orientation = counter;
++                            
++         node = *(temp2->VertandId + counter);
++         if (node->edge[1] == nextvert)
++                      nextvert = node->edge[2];
++         else
++                      nextvert = node->edge[1];
++
++         if (!reversed)
++        {
++               if (counter != 3)
++                           north = counter +1;
++                   else
++                           north = 0;
++        }
++        else
++        {
++               if (counter != 0)
++                    north = counter -1;
++               else
++                    north = 3;
++        }
++}
++
++if (start)
++      tris += Peel_Max(temp2,face_id,orientation,last_left,north,last_north,output_file,
++                        color1,color2,color3,FALSE,swaps_added,norms,texture);        
++else
++     Mark_Face(temp2,color1,color2,color3,output_file,FALSE,&dummy,&dummy,&face_id,norms,texture);/* do the last face */
++
++last_seen++;
++
++/*    Get the edge that we came out on the last strip of the patch */
++Mark_Face(NULL,0,0,0,output_file,TRUE,&end1,&end2,&last_id,norms,texture);
++tris += Extend_Face(last_id,end1,end2,&s,output_file,color1,color2,color3,vn,norms,vt,texture);
++*swaps_added = *swaps_added + s;
++return tris;
++}
++
++
++
++void Find_Bands(int numfaces, FILE *output_file, int *swaps, int *bands, 
++                int *cost, int *tri, int norms, int *vert_norms, int texture, int *vert_texture)
++{
++
++      register int x,y,max1,max2,numverts,face_id,flag,maximum = 25;
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++      int color1 = 0, color2 = 100, color3 = 255;
++      int larger,smaller;
++      int north_length1,last_north,left_length1,last_left,north_length2,left_length2;
++  int total_tri = 0, total_swaps = 0,last_id;
++  int end1, end2,s=0;
++  register int cutoff = 20;
++    
++  /* Code that will find the patches. "Cutoff" will be
++     the cutoff of the area of the patches that we will be allowing. After
++     we reach this cutoff length, then we will run the local algorithm on the
++     remaining faces.
++  */
++
++      /* For each faces that is left find the largest possible band that we can
++               have with the remaining faces. Note that we will only be finding patches
++     consisting of quads.
++      */
++
++  vn = vert_norms;
++  vt = vert_texture;
++  y=1;
++  *bands = 0;
++
++  while ((maximum >= cutoff))
++  {
++        y++;
++    maximum = -1;
++        for (x=0; x<numfaces; x++)
++        { 
++      /*   Used to produce the triangle strips */
++ 
++      /* for each face, get the face */
++                pListHead = PolFaces[x];
++                temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++                numverts = temp->nPolSize;
++                
++      /* we are doing this only for quads */
++                if (numverts == 4)
++                {
++                        /* We want a face that is has not been used yet,
++           since we know that that face must be part of
++                                 a band. Then we will find the largest band that
++                                 the face may be contained in
++                        */
++                        
++        /*  Doing the north and the left */
++                        if ((*(temp->walked) != -1) && (*(temp->walked+3) != -1))
++                                max1 = Find_Max(temp,x,0,3,&north_length1,&left_length1);
++                        if ((*(temp->walked+1) != -1) && (*(temp->walked+2) != -1))
++                                max2 = Find_Max(temp,x,2,1,&north_length2,&left_length2);
++                        if ((max1 != (north_length1 * left_length1)) ||
++                            (max2 != (north_length2 * left_length2)))
++                        {
++                                printf("Max1 %d, %d %d        Max2 %d, %d %d\n",max1,north_length1,left_length1,max2,north_length2,left_length2);
++                                exit(0);
++                        }
++                
++                    
++        if ((max1 > max2) && (max1 > maximum))
++                        {
++          maximum = max1;
++          face_id = x;
++          flag = 1; 
++          last_north = north_length1;
++          last_left = left_length1;
++          /* so we know we saved max1 */
++                        }
++                        else if ((max2 > maximum) )
++                        {
++          maximum = max2;
++          face_id = x;
++          flag = 2; 
++          last_north = north_length2;
++          last_left = left_length2;
++          /* so we know we saved max2 */
++        }
++      }
++    }
++    if ((maximum < cutoff) && (*bands == 0))
++      return;
++    pListHead = PolFaces[face_id];
++    temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0); 
++    /*   There are no patches that we found in this pass */
++    if (maximum == -1)
++      break;
++    printf("The maximum is  face %d area %d: lengths %d %d\n",face_id,maximum,last_north,last_left);
++    if (maximum == 16)
++      printf("Fran");
++
++    if (last_north > last_left)
++    {
++      larger = last_north;
++      smaller = last_left;
++    }
++    else
++    {
++      larger = last_left;
++      smaller = last_north;
++    }
++
++    length = larger;
++
++    if (flag == 1)
++    {
++          if (last_north > last_left) /*     go north sequentially */
++      {
++        total_tri += Peel_Max(temp,face_id,0,last_north,3,last_left,output_file,color1,color2,color3,TRUE,&s,norms,texture);
++        Reset_Max(temp,face_id,0,last_north,3,last_left,output_file,color1,color2,color3,TRUE);
++        total_swaps += s;
++      }
++      else
++      {
++        reversed = TRUE;
++        total_tri += Peel_Max(temp,face_id,3,last_left,0,last_north,output_file,color1,color2,color3,TRUE,&s,norms,texture);
++        Reset_Max(temp,face_id,3,last_left,0,last_north,output_file,color1,color2,color3,TRUE);
++        reversed = FALSE;
++        total_swaps += s;
++      }
++
++
++      /*    Get the edge that we came out on the last strip of the patch */
++      Mark_Face(NULL,0,0,0,NULL,TRUE,&end1,&end2,&last_id,norms,texture);
++      total_tri += Extend_Face(last_id,end1,end2,&s,output_file,color1,color2,color3,vn,norms,vt,texture);
++      total_swaps += s;
++
++    }
++    else
++    {
++       if (last_north > last_left)
++       {
++            total_tri += Peel_Max(temp,face_id,2,last_north,1,last_left,output_file,color1,color2,color3,TRUE,&s,norms,texture); 
++            Reset_Max(temp,face_id,2,last_north,1,last_left,output_file,color1,color2,color3,TRUE); 
++            total_swaps += s;
++       }
++       else
++       {
++            reversed = TRUE;
++            total_tri += Peel_Max(temp,face_id,1,last_left,2,last_north,output_file,color1,color2,color3,TRUE,&s,norms,texture);
++            Reset_Max(temp,face_id,1,last_left,2,last_north,output_file,color1,color2,color3,TRUE);
++            reversed = FALSE;
++            total_swaps += s;
++       }
++
++       /*    Get the edge that we came out on on the patch */
++      Mark_Face(NULL,0,0,0,NULL,TRUE,&end1,&end2,&last_id,norms,texture);
++      total_tri += Extend_Face(last_id,end1,end2,&s,output_file,color1,color2,color3,vn,norms,vt,texture);
++      total_swaps += s;
++    }
++
++    /* Now compute the cost of transmitting this band, is equal to 
++       going across the larger portion sequentially,
++       and swapping 3 times per other dimension
++    */
++
++    total_tri += (maximum * 2);
++    *bands = *bands + smaller;
++  }
++
++  printf("We transmitted %d triangles,using %d swaps and %d strips\n",total_tri,total_swaps, *bands);
++  printf("COST %d\n",total_tri + total_swaps + *bands + *bands);
++
++  *cost = total_tri + total_swaps + *bands + *bands;
++  *tri = total_tri;
++  added_quad = added_quad * 4;
++  *swaps = total_swaps;
++}
++
++ 
++void Save_Rest(int *numfaces)
++{
++    /*  Put the polygons that are left into a data structure so that we can run the
++        stripping code on it.
++    */
++    register int x,y=0,numverts;
++    ListHead *pListHead;
++    PF_FACES temp=NULL;
++
++    for (x=0; x<*numfaces; x++)
++    { 
++                      /* for each face, get the face */
++                      pListHead = PolFaces[x];
++                      temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++                      numverts = temp->nPolSize;
++               /*  If we did not do the face before add it to data structure with new 
++                   face id number
++               */
++               if (numverts != 1)
++               {
++                   CopyFace(temp->pPolygon,numverts,y+1,temp->pNorms);
++                   y++;
++               }
++               /*   Used it, so remove it */
++               else
++                    RemoveList(pListHead,(PLISTINFO) temp);
++
++    }
++    *numfaces = y;
++}
++
++void Assign_Walk(int lastvert,PF_FACES temp2, int front_walk,int y,
++                              int back_walk)
++{
++/*      Go back and do the walk again, but this time save the lengths inside
++        the data structure.
++        y was the starting edge number for the front_walk length
++        back_walk is the length of the walk along the opposite edge
++ */
++        int previous_edge1, previous_edge2;
++        register int walk = 0,nextvert,numverts,counter;
++        BOOL flag;
++        F_EDGES *node;
++        ListHead *pListHead;
++        static int seen = 0;
++        static BOOL first = TRUE;         
++        BOOL wrap = FALSE, set = FALSE;
++             
++        /*     In the "Fast_Reset" resetting will be true */
++        if ((resetting) && (first))
++        {
++             seen = 0;
++             first = FALSE;
++        }
++
++        seen++;
++        /*     Had a band who could be a cycle  */
++        if (front_walk == back_walk)
++             wrap = TRUE;
++             
++        /* Find the edge that we are currently on */
++        if (y != 3)
++        {
++                previous_edge1 = *(temp2->pPolygon +y);
++                previous_edge2 = *(temp2->pPolygon + y + 1);
++        }
++        else
++        {
++                previous_edge1 = *(temp2->pPolygon +y);
++                previous_edge2 = *(temp2->pPolygon);
++        }
++
++        /* Assign the lengths */
++         if (y < 2) 
++         {
++                *(temp2->walked+y) = front_walk--;
++                       *(temp2->walked+y+2) = back_walk++;
++         }
++         else
++         {                            
++               *(temp2->walked+y) = front_walk--;
++                      *(temp2->walked+y-2) = back_walk++;
++         }
++
++         /*Find the adjacent face to this edge */
++        node = *(temp2->VertandId+y);                   
++
++        if (node->edge[2] != lastvert)
++          nextvert = node->edge[2];
++        else
++          nextvert = node->edge[1];
++                                       
++        temp2->seen3 = seen;
++        
++        /* Keep walking in this direction until we cannot do so */
++        while ((nextvert != lastvert) && (nextvert != -1) && (front_walk >= 0))
++        {
++                   walk++;
++               pListHead = PolFaces[nextvert];
++               
++               temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++               numverts = temp2->nPolSize;
++               if ((numverts != 4))
++               {
++                    nextvert = -1;
++                    /* Don't include this face in the walk */
++                    walk--;
++               }
++               else
++               {
++                    /* Find edge that is not adjacent to the previous one */
++                    counter = 0;
++                    flag = TRUE;
++                    while ((counter < 3) && (flag))
++                    {
++                         if ( ((*(temp2->pPolygon+counter) == previous_edge1) ||
++                               (*(temp2->pPolygon+counter+1) == previous_edge2)) ||
++                              ((*(temp2->pPolygon+counter) == previous_edge2) ||
++                               (*(temp2->pPolygon+counter+1) == previous_edge1)) )
++                              counter++;
++                         else
++                              flag = FALSE;
++                    }
++                    /* Get the IDs of the next edge */
++                    if (counter < 3)
++                    {
++                         previous_edge1 = *(temp2->pPolygon + counter);
++                         previous_edge2 = *(temp2->pPolygon + counter + 1);
++                    }
++                    else
++                    {
++                         previous_edge1 = *(temp2->pPolygon + counter);
++                         previous_edge2 = *(temp2->pPolygon);
++                    }
++               
++
++                        /*      Put in the walk lengths */
++                        if (counter < 2)
++                        {
++                        if (((*(temp2->walked + counter) >= 0)
++                                || (*(temp2->walked +counter + 2) >= 0)))
++                                {
++                                        if ((resetting == FALSE) && ((temp2->seen3) != (seen-1)))
++                                        {
++                                                /*   If there are more than 2 polygons adjacent
++                                        to an edge then we can be trying to assign more than
++                                        once. We will save the smaller one
++                                   */
++                                   temp2->seen3 = seen;
++                                   if ( (*(temp2->walked+counter) <= front_walk) &&
++                                        (*(temp2->walked+counter+2) <= back_walk) )
++                                        return;
++                                   if (*(temp2->walked+counter) > front_walk)
++                                       *(temp2->walked+counter) = front_walk--;
++                                   else
++                                        front_walk--;
++                                   if (*(temp2->walked+counter+2) > back_walk)
++                                       *(temp2->walked+counter+2) = back_walk++;
++                                   else
++                                        back_walk++;
++                                        }
++                                        else if (resetting == FALSE)
++                                        {
++                                                /* if there was a cycle then all lengths are the same */
++                                                walk--;
++                                                back_walk--;
++                                                front_walk++;
++                                   temp2->seen3 = seen;
++                                   *(temp2->walked+counter) = front_walk--;
++                                   *(temp2->walked+counter+2) = back_walk++;
++                              }
++                              else if (((temp2->seen3 == (seen-1))
++                                   && (wrap) && (walk == 1)) || (set))
++                              {
++                                                /* if there was a cycle then all lengths are the same */
++                                                set = TRUE;
++                                   walk--;
++                                                back_walk--;
++                                                front_walk++;
++                                   temp2->seen3 = seen;
++                                   *(temp2->walked+counter) = front_walk--;
++                                   *(temp2->walked+counter+2) = back_walk++;
++                              }
++                              else
++                              {
++                                   temp2->seen3 = seen;
++                                   *(temp2->walked+counter) = front_walk--;
++                                   *(temp2->walked+counter+2) = back_walk++;
++                              }
++                        } /* if was > 0 */    
++                        else
++                        {
++                             temp2->seen3 = seen;
++                             *(temp2->walked+counter) = front_walk--;
++                             *(temp2->walked+counter+2) = back_walk++;
++                        }
++                    }
++              
++               else
++               {
++                    if (((*(temp2->walked + counter) >= 0 )
++                        || (*(temp2->walked +counter - 2) >= 0)) )
++                    {
++                         if ((temp2->seen3 != (seen-1))  && (resetting == FALSE))
++                         {
++                              /*   If there are more than 2 polygons adjacent
++                                   to an edge then we can be trying to assign more than
++                                   once. We will save the smaller one
++                              */
++                              temp2->seen3 = seen;
++                              if ( (*(temp2->walked+counter) <= front_walk) &&
++                                   (*(temp2->walked+counter-2) <= back_walk) )
++                                   return;
++                              if (*(temp2->walked+counter) > front_walk)
++                                   *(temp2->walked+counter) = front_walk--;
++                              else
++                                   front_walk--;
++                              if (*(temp2->walked+counter-2) > back_walk)
++                                   *(temp2->walked+counter-2) = back_walk++;
++                              else
++                                   back_walk++;
++                              }
++                                   else if (resetting == FALSE)
++                              {
++                                      walk--;
++                                      back_walk--;
++                                      front_walk++;
++                               temp2->seen3 = seen;
++                              *(temp2->walked+counter) = front_walk--;
++                              *(temp2->walked+counter-2) = back_walk++;
++                         }
++                         else if (((temp2->seen3 == (seen-1)) && (walk == 1) && (wrap))
++                              || (set))
++                         {
++                                           /* if there was a cycle then all lengths are the same */
++                                           set = TRUE;
++                              walk--;
++                                           back_walk--;
++                                           front_walk++;
++                              temp2->seen3 = seen;
++                              *(temp2->walked+counter) = front_walk--;
++                              *(temp2->walked+counter-2) = back_walk++;
++                         }
++                         else
++                         {
++                              temp2->seen3 = seen;
++                              *(temp2->walked+counter) = front_walk--;
++                              *(temp2->walked+counter-2) = back_walk++;
++                         }
++                      }
++                    else
++                    {
++                         temp2->seen3 = seen;
++                         *(temp2->walked+counter) = front_walk--;
++                         *(temp2->walked+counter-2) = back_walk++;
++                    }
++                              
++                   } 
++                   if (nextvert != -1)
++                   {
++                           node = *(temp2->VertandId + counter);
++                      if (node->edge[1] == nextvert)
++                              nextvert = node->edge[2];
++                      else
++                              nextvert = node->edge[1];
++               }
++              
++     }
++}
++if ((EVEN(seen)) )
++     seen+=2;
++}
++
++void Save_Walks(int numfaces)
++{
++      int x,y,numverts;
++      int front_walk, back_walk;
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++
++      for (x=0; x<numfaces; x++)
++      { 
++              /* for each face, get the face */
++              pListHead = PolFaces[x];
++              temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
++              numverts = temp->nPolSize;
++              front_walk = 0; 
++          back_walk = 0;
++
++          /* we are finding patches only for quads */
++              if (numverts == 4)
++              {
++                      /*      for each face not seen yet, do North and South together
++                              and East and West together
++                      */
++                      for (y=0;y<2;y++)
++                      {
++                              /*   Check if the opposite sides were seen already from another
++                         starting face, if they were then there is no need to do the walk again
++                    */
++
++                              if      ( ((*(temp->walked+y) == -1) &&
++                                      (*(temp->walked+y+2) == -1) ))
++                              {
++                                      /* Find walk for the first edge */
++                                      front_walk = Calculate_Walks(x,y,temp);
++                                      /* Find walk in the opposite direction */
++                                      back_walk = Calculate_Walks(x,y+2,temp);
++                                      /*      Now put into the data structure the numbers that
++                                              we have found
++                                      */
++                         Assign_Walk(x,temp,front_walk,y,back_walk);
++                                      Assign_Walk(x,temp,back_walk,y+2,front_walk);
++                      }
++                      }
++              }
++      }
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7e1243e247c7c60edf4bcd16717816fe473badb6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,181 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: options.c
++     This file contains routines that are used to determine the options
++     that were specified by the user
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "options.h"
++#include "global.h"
++
++int power_10(int power)
++{
++      /*      Raise 10 to the power */
++      register int i,p;
++
++      p = 1;
++      for (i = 1; i <= power; ++i)
++              p = p * 10;
++      return p;
++}
++
++float power_negative(int power)
++{
++     /*   Raise 10 to the negative power */
++
++     register int i;
++     float p;
++     
++     p = (float)1;
++     for (i = 1; i<=power; i++)
++          p = p * (float).1;
++     return p;
++}
++
++float convert_array(int num[],int stack_size)
++{
++      /* Convert an array of characters to an integer */
++      
++      register int counter,c;
++      float temp =(float)0.0;
++
++      for (c=(stack_size-1), counter = 0; c>=0; c--, counter++)
++     {
++          if (num[c] == -1)
++          /*   We are at the decimal point, convert to decimal
++               less than 1
++          */
++          {
++               counter = -1;
++               temp = power_negative(stack_size - c - 1) * temp;
++          }
++          else 
++               temp += power_10(counter) * num[c];
++     }
++                      
++      return(temp);
++}
++
++double get_options(int argc, char **argv, int *f, int *t, int *tr, int *group)
++{
++     char c;
++     int count = 0;
++     int buffer[STRIP_MAX];
++     int next = 0;
++     /*    tie variable */
++     enum tie_options tie = SEQUENTIAL;
++     /*   triangulation variable */
++     enum triangulation_options triangulate = PARTIAL;
++     /*   normal difference variable (in degrees) */
++     float norm_difference = (float)360.0;
++     /*   file-type variable */
++     enum file_options file_type = ASCII;
++
++     /*      User has the wrong number of options */
++      if ((argc > 5) || (argc < 2))
++      {
++              printf("Usage: bands -[file_option][ties_option][triangulation_option][normal_difference] in_file_name out_file_name\n");
++              exit(0);
++      }
++      
++     /* Interpret the options specified */
++      while (--argc > 0 && (*++argv)[0] == '-')
++     {
++          /*   At the next option that was specified */
++          next = 1;
++          while (c = *++argv[0])
++                      switch (c)
++              {
++                              case 'f': 
++                                      /*      Use the first polygon we see. */
++                         tie = FIRST;
++                                      break;
++                              
++                              case 'r':
++                                      /*      Randomly choose the next polygon */
++                         tie = RANDOM;
++                                      break;
++
++                              case 'a':
++                                      /*      Alternate direction in choosing the next polygon */
++                         tie = ALTERNATE;
++                                      break;
++
++                              case 'l':
++                                      /*      Use lookahead to choose the next polygon */
++                         tie = LOOK;
++                                      break;
++
++                              case 'q':
++                                      /*  Try to reduce swaps */
++                         tie = SEQUENTIAL;
++                                      break;
++
++                              case 'p':
++                                      /*      Use partial triangulation of polygons */
++                         triangulate = PARTIAL;
++                                      break;
++
++                              case 'w':
++                                      /*      Use whole triangulation of polygons */
++                         triangulate = WHOLE;
++                                      break;
++
++                    case 'b':
++                         /*      Input file is in binary */
++                         file_type = BINARY;
++                         break;
++
++                    case 'g':
++                         /*   Strips will be grouped according to the groups in 
++                              the data file. We will have to restrict strips to be
++                              in the grouping of the data file.
++                         */
++                         *group = 1;
++                  
++                         /*   Get each the value of the integer */
++                         /*   We have an integer */
++                    default:
++                         if ((c >= '0') && (c <= '9'))
++                         {
++                              /*   More than one normal difference specified, use the last one */
++                              if (next == 1)
++                              {
++                                   count = 0;
++                                   next = 0;
++                              }
++                              buffer[count++] = ATOI(c);
++                         }
++                              /*   At the decimal point */
++                         else if (c == '.')
++                         {
++                              /*   More than one normal difference specified, use the last one */
++                              if (next == 1)
++                              {
++                                   count = 0;
++                                   next = 0;
++                              }
++                              buffer[count++] = -1;
++                         }
++                         else 
++                              break;
++              }
++     }
++     /*   Convert the buffer of characters to a floating pt integer */
++     if (count != 0) 
++          norm_difference = convert_array(buffer,count);
++     *f = file_type;
++     *t = tie;
++     *tr = triangulate;
++     return norm_difference;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..34c10bcc138190b3d7d71d48291e82cdabb0eae6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: options.h
++-----------------------------------------------------------------------*/
++
++double get_options(int argc, char **argv, int *f, int *t, int *tr, int *group);
++enum file_options {ASCII,BINARY};
++enum tie_options {FIRST, RANDOM, ALTERNATE, LOOK, SEQUENTIAL};
++enum triangulation_options {PARTIAL,WHOLE};
++     
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..16eb6abe60193554da3754734fa72aa2402032eb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,579 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: output.c
++     This file contains routines that are finding and outputting the
++     strips from the local algorithm
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "global.h"
++#include "polverts.h"
++#include "triangulate.h"
++#include "partial.h"
++#include "sturcts.h"
++#include "ties.h"
++#include "options.h"
++#include "common.h"
++#include "util.h"
++#include "free.h"
++
++int *vn;
++int *vt;
++int norm;
++int text;
++
++int Finished(int *swap, FILE *output, BOOL global)
++{
++  /* We have finished all the triangles, now is time to output to
++     the data file. In the strips data structure, every three ids
++     is a triangle. Now we see whether we can swap, or make a new strip
++     or continue the strip, and output the data accordingly to the
++     data file. 
++  */
++  int num,x,vertex1,vertex2;
++  ListHead *pListHead;
++  int id[2],other1,other2,index = 0,a,b,c;
++  P_STRIPS temp1,temp2,temp3,temp4,temp5,temp6;
++  BOOL cptexture;
++  *swap =0;
++   
++  cptexture = text;
++  pListHead = strips[0];
++  if (pListHead == NULL)
++    return 0;
++
++  num = NumOnList(pListHead);
++  // WILBUR
++  // printf ("There are %d triangles in the extend\n",num/3);
++
++  /* Go through the list triangle by triangle */
++      temp1 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 0);
++      temp2 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 1);
++      temp3 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 2);
++      
++  /* Next triangle for lookahead */
++  temp4 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 3);
++        
++
++  /*    There is only one polygon in the strip */
++  if (temp4 == NULL)
++  {
++    /* Data might be mixed and we do not have textures for some of the vertices */
++    if ((text) &&  (vt[temp3->face_id] == 0))
++      cptexture = FALSE;
++    if ((norm) && (!cptexture))
++      fprintf(output,"%d//%d %d//%d %d//%d",temp3->face_id+1,vn[temp3->face_id]+1,
++                temp2->face_id+1,vn[temp2->face_id]+1,
++                temp1->face_id+1,vn[temp1->face_id]+1);
++    else if ((cptexture) && (!norm))
++      fprintf(output,"%d/%d %d/%d %d/%d",temp3->face_id+1,vt[temp3->face_id]+1,
++                temp2->face_id+1,vt[temp2->face_id]+1,
++                temp1->face_id+1,vt[temp1->face_id]+1);
++    else if ((cptexture)&& (norm))
++      fprintf(output,"%d/%d/%d %d/%d/%d %d/%d/%d",temp3->face_id+1,vt[temp3->face_id]+1,vn[temp3->face_id]+1,
++                temp2->face_id+1,vt[temp2->face_id]+1,vn[temp2->face_id]+1,
++                temp1->face_id+1,vt[temp1->face_id]+1,vn[temp1->face_id]+1);
++    else 
++      fprintf(output,"%d %d %d",temp3->face_id+1,temp2->face_id+1,temp1->face_id+1);
++    Free_Strips();
++        return 1;
++      }
++        
++      /* We have a real strip */
++      temp5 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 4);
++      temp6 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 5);
++        
++      if ((temp1 == NULL) || (temp2 == NULL) || (temp3 == NULL) || (temp5 == NULL) || (temp6 == NULL))
++      {
++        printf("There is an error in the output of the triangles\n");
++        exit(0);
++      }
++
++      /* Find the vertex in the first triangle that is not in the second */
++      vertex1 = Different(temp1->face_id,temp2->face_id,temp3->face_id,temp4->face_id,temp5->face_id,temp6->face_id,&other1,&other2);
++      /* Find the vertex in the second triangle that is not in the first */
++      vertex2 = Different(temp4->face_id,temp5->face_id,temp6->face_id,temp1->face_id,temp2->face_id,temp3->face_id,&other1,&other2);
++
++      /* Lookahead for the correct order of the 2nd and 3rd vertex of the first triangle */
++  temp1 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 6);
++      temp2 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 7);
++      temp3 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 8);
++       
++  if (temp1 != NULL)
++    other1 = Different(temp3->face_id,temp4->face_id,temp5->face_id,temp1->face_id,temp2->face_id,temp3->face_id,&other1,&a);
++         
++      id[index] = vertex1; index = !index;
++      id[index] = other1; index = !index;
++      id[index] = other2; index = !index;
++
++      a = temp4->face_id; 
++      b = temp5->face_id; 
++      c = temp6->face_id;
++
++  /* If we need to rearrange the first sequence because otherwise
++     there would have been a swap.
++  */
++
++  if ((temp3 != NULL) && (text) && ( vt[temp3->face_id]==0))
++    cptexture = FALSE;
++  if ((norm) && (!cptexture))
++    fprintf(output,"%d//%d %d//%d %d//%d ",vertex1+1,vn[vertex1]+1,
++               other1+1,vn[other1]+1,other2+1,vn[other2]+1);
++  else if ((cptexture) && (!norm))
++    fprintf(output,"%d/%d %d/%d %d/%d ",vertex1+1,vt[vertex1]+1,
++               other1+1,vt[other1]+1,other2+1,vt[other2]+1);
++  else if ((cptexture) && (norm))
++    fprintf(output,"%d/%d/%d %d/%d/%d %d/%d/%d ",vertex1+1,vt[vertex1]+1,vn[vertex1]+1,
++              other1+1,vt[other1]+1,vn[other1]+1,other2+1,vt[other2]+1,vn[other2]+1);
++  else {
++    fprintf(output,"%d %d %d ",vertex1+1,other1+1,other2+1);
++  }
++
++  // original line
++  // for (x = 6; x < num ; x = x+3)
++  // Wilbur modified line
++  for (x = 6; x < num ; x = x+3)
++      {
++    /* Get the next triangle */
++        temp1 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, x);
++        temp2 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, x+1);
++        temp3 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, x+2);
++
++    /* Error checking */
++        if (!(member(id[0],a,b,c)) || !(member(id[1],a,b,c)) || !(member(vertex2,a,b,c)))
++        {
++                /* If we used partial we might have a break in the middle of a strip */
++                fprintf(output,"\nt ");
++          /* Find the vertex in the first triangle that is not in the second */
++          vertex1 = Different(a,b,c,temp1->face_id,temp2->face_id,temp3->face_id,&other1,&other2);
++          /* Find the vertex in the second triangle that is not in the first */
++          vertex2 = Different(temp1->face_id,temp2->face_id,temp3->face_id,a,b,c,&other1,&other2);
++         
++          id[index] = vertex1; index = !index;
++          id[index] = other1; index = !index;
++          id[index] = other2; index = !index;
++        }
++
++        if ((temp1 == NULL ) || (temp2 == NULL) || (temp3 == NULL))
++        {
++                printf("There is an error in the triangle list \n");
++                exit(0);
++        }
++         
++    if ((id[0] == id[1]) || (id[0] == vertex2))
++      continue;
++
++    if ( (member(id[index],temp1->face_id,temp2->face_id,temp3->face_id)) )
++    {
++      if ((text) && ( vt[id[index]]==0)) {
++        cptexture = FALSE;
++      }
++      if ((!norm) && (!cptexture)) {
++        fprintf(output,"%d ",id[index]+1);
++      } else if ((norm) && (!cptexture)) {
++        fprintf(output,"%d//%d ",id[index]+1,vn[id[index]]+1);
++      } else if ((!norm) && (cptexture)) {
++        fprintf(output,"%d/%d ",id[index]+1,vt[id[index]]+1);
++      } else {
++        fprintf(output,"%d/%d/%d ",id[index]+1,vt[id[index]]+1,vn[id[index]]+1);
++      }
++
++      index = !index;
++      *swap = *swap + 1;
++    }
++           
++    if ((text) && ( vt[vertex2]==0))
++      cptexture = FALSE;
++        if ((!norm) && (!cptexture))
++      fprintf(output,"\nq %d ",vertex2+1);
++    else if ((norm) && (!cptexture))
++      fprintf(output,"\nq %d//%d ",vertex2+1,vn[vertex2]+1);
++    else if ((!norm) && (cptexture))
++      fprintf(output,"\nq %d/%d ",vertex2+1,vt[vertex2]+1);
++    else
++      fprintf(output,"\nq %d/%d/%d ",vertex2+1,vt[vertex2]+1,vn[vertex2]+1);
++
++    id[index] = vertex2; index = !index;
++
++        /* Get the next vertex not in common */
++        vertex2 = Different(temp1->face_id,temp2->face_id,temp3->face_id,a,b,c,&other1,&other2);
++        a = temp1->face_id;
++        b = temp2->face_id;
++        c = temp3->face_id;
++      }
++
++  /* Do the last vertex */
++  if ((!norm) && (!cptexture))
++    fprintf(output,"\nq %d ",vertex2+1);
++  else if ((norm) && (!cptexture))
++    fprintf(output,"\nq %d//%d ",vertex2+1,vn[vertex2]+1);
++  else if ((!norm) && (cptexture))
++    fprintf(output,"\nq %d/%d ",vertex2+1,vt[vertex2]+1);
++  else
++    fprintf(output,"\nq %d/%d/%d ",vertex2+1,vt[vertex2]+1,vn[vertex2]+1);
++
++  Free_Strips();
++  return (num/3);
++}
++
++
++
++
++
++void Output_Tri(int id1, int id2, int id3,FILE *bands, int color1, int color2, int color3,BOOL end)
++{
++     /*   We will save everything into a list, rather than output at once,
++           as was done in the old routine. This way for future modifications
++           we can change the strips later on if we want to.
++     */
++
++    int temp1,temp2,temp3;
++    
++    /*  Make sure we do not have an error */
++    /*    There are degeneracies in some of the files */
++      if ( (id1 == id2) || (id1 == id3) || (id2 == id3))
++      {
++              printf("Degenerate triangle %d %d %d\n",id1,id2,id3);
++              exit(0);
++      }
++     else
++     {
++          Last_Edge(&temp1,&temp2,&temp3,0);
++           Add_Id_Strips(id1,end);
++           Add_Id_Strips(id2,end);
++           Add_Id_Strips(id3,end);
++           Last_Edge(&id1,&id2,&id3,1);
++     }
++}
++
++
++int Polygon_Output(P_ADJACENCIES temp,int face_id,int bucket,
++                                      ListHead *pListHead, BOOL first, int *swaps,
++                         FILE *bands,int color1,int color2,int color3,BOOL global, BOOL end)
++{
++      ListHead *pListFace;
++      PF_FACES face;
++      P_ADJACENCIES pfNode;
++      int next_face_id,next_bucket,e1,e2,e3,other1,other2,other3;
++      P_ADJACENCIES lpListInfo; 
++     int ties=0;
++     
++     /* We have a polygon to output, the id is face id, and the number
++         of adjacent polygons to it is bucket. This routine extends the patches from
++        either end to make longer triangle strips.
++      */
++                
++                   
++     /*  Now get the edge */
++     Last_Edge(&e1,&e2,&e3,0);
++    
++     /*  Get the polygon with id face_id */
++      pListFace  = PolFaces[face_id];
++      face = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
++
++     /*  We can't go any more */
++     if ((face->nPolSize == 1) || ((face->nPolSize == 4) && (global))) /* if global, then we are still doing patches */
++     {
++        /*     Remove it from the list so we do not have to waste
++               time visiting it in the future, or winding up in an infinite loop
++               if it is the first on that we are looking at for a possible strip
++        */
++        if (face->nPolSize == 1)
++             RemoveList(pListHead,(PLISTINFO) temp);
++        if (first)
++             return 0;
++        else
++             return (Finished(swaps,bands,global));
++    }
++
++    if (face->nPolSize == 3)
++    {
++              /*      It is already a triangle */
++              if (bucket == 0)
++              {
++                      /*      It is not adjacent to anything so we do not have to
++                                 worry about the order of the sides or updating adjacencies
++                      */
++                          
++                next_face_id = Different(*(face->pPolygon),*(face->pPolygon+1),*(face->pPolygon+2),
++                                            e1,e2,e3,&other1,&other2);  
++                      face->nPolSize = 1;
++                       
++               /* If this is the first triangle in the strip */
++               if ((e2 == 0) && (e3 ==0))
++               {
++                    e2 = other1;
++                    e3 = other2;
++               }
++
++               Output_Tri(e2,e3,next_face_id,bands,color1,color2,color3,end);
++               RemoveList(pListHead,(PLISTINFO) temp);
++               return (Finished(swaps,bands,global));
++          }
++              
++        
++          /*  It is a triangle with adjacencies. This means that we
++                  have to:
++                              1. Update the adjacencies in the list, because we are
++                                      using this polygon and it will be deleted.
++                              2. Get the next polygon.
++              */
++              else
++              {
++                      /*   Return the face_id of the next polygon we will be using,
++                              while updating the adjacency list by decrementing the
++                              adjacencies of everything adjacent to the current triangle.
++                      */
++            
++               next_face_id = Update_Adjacencies(face_id, &next_bucket, &e1,&e2,&ties);
++               /*  Maybe we deleted something in a patch and could not find an adj polygon */
++               if (next_face_id == -1)
++               {
++                       Output_Tri(*(face->pPolygon),*(face->pPolygon+1),*(face->pPolygon+2),bands,color1,
++                                  color2,color3,end);
++                       face->nPolSize = 1;
++                       RemoveList(pListHead,(PLISTINFO) temp);
++                       return (Finished(swaps,bands,global));
++               }
++                
++                   /*      Find the other vertex to transmit in the triangle */
++                   e3 = Return_Other(face->pPolygon,e1,e2);
++                Last_Edge(&other1,&other2,&other3,0);
++          
++                if ((other2 != 0) && (other3 != 0))
++                {
++                    /*   See which vertex in the output edge is not in the input edge */
++                    if ((e1 != other2) && (e1 != other3))
++                          e3 = e1;
++                    else if ((e2 != other2) && (e2 != other3))
++                           e3 = e2;
++                    else
++                    {
++                          printf("There is an error in the tri with adj\n");
++                          exit(0);
++                    }
++
++                    /*   See which vertex of the input edge is not in the output edge */
++                    if ((other2 != e1) && (other2 != e2))
++                    {
++                          other1 = other2;
++                          other2 = other3;
++                    }
++                    else if ((other3 != e1) && (other3 != e2))
++                          other1 = other3;
++                    else
++                    {
++                          printf("There is an error in getting the tri with adj\n");
++                          exit(0);
++                    }
++                    
++                }
++               else
++               {
++                  /*     We are the first triangle in the strip and the starting edge
++                         has not been set yet
++                  */
++                  /*  Maybe we deleted something in a patch and could not find an adj polygon */
++                  if (next_face_id == -1)
++                  {
++                       Output_Tri(*(face->pPolygon),*(face->pPolygon+1),*(face->pPolygon+2),bands,color1,
++                                  color2,color3,end);
++                       face->nPolSize = 1;
++                       RemoveList(pListHead,(PLISTINFO) temp);
++                       return (Finished(swaps,bands,global));
++                  }
++
++                  other1 = e3;
++                  e3 = e2;
++                  other2 = e1;
++               }
++         
++                /*   At this point the adjacencies have been updated  and we
++                              have the next polygon id 
++                */
++
++               Output_Tri(other1,other2,e3,bands,color1,color2,color3,end);
++               face->nPolSize = 1;
++                   RemoveList(pListHead,(PLISTINFO) temp);
++                
++               /*  Maybe we deleted something in a patch and could not find an adj polygon */
++               if (next_face_id == -1)
++                    return (Finished(swaps,bands,global));
++        
++               if (Done(next_face_id,59,&next_bucket) == NULL)
++                   {
++                           printf("We deleted the next face 4%d\n",next_face_id);
++                           exit(0);
++                }
++
++                      pListHead = array[next_bucket];
++                      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                      if ( pfNode )
++                              pfNode->face_id = next_face_id;
++                      lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                              (int (*)(void *,void *)) (Compare)));
++                      if (lpListInfo == NULL)
++                      {
++                              printf("There is an error finding the next polygon3 %d\n",next_face_id);
++                              exit(0);
++                      }
++                      return (Polygon_Output(lpListInfo,next_face_id,next_bucket,
++                                                   pListHead, FALSE, swaps,bands,color1,color2,color3,global,end));
++
++              }
++      }
++
++      else
++      {
++              /*   It is not a triangle, we have to triangulate it .
++                      Since it is not adjacent to anything we can triangulate it
++                      blindly
++              */
++              if (bucket == 0)
++              {
++                        /*   It is the first polygon in the strip, therefore there is no
++                         input edge to start with.
++                    */
++                    if ((e2 == 0) && (e3 ==0))
++                       Blind_Triangulate(face->nPolSize,face->pPolygon,bands,
++                                                TRUE,1,color1,color2,color3);
++
++                    else
++                       Blind_Triangulate(face->nPolSize,face->pPolygon,bands,
++                                                FALSE,1,color1,color2,color3);
++
++                           RemoveList(pListHead,(PLISTINFO) temp);
++                                     
++                    /*      We will be at the beginning of the next strip. */
++                    face->nPolSize = 1;
++                    return (Finished(swaps,bands,global));
++              }
++
++
++              else
++              {
++                      
++             
++               /*  WHOLE triangulation */
++                /*  It is not a triangle and has adjacencies. 
++                              This means that we have to:
++                              1. Triangulate this polygon, not blindly because
++                                      we have an edge that we want to come out on, that
++                                      is the edge that is adjacent to a polygon with the
++                                      least number of adjacencies. Also we must come in
++                                      on the last seen edge.
++                              2. Update the adjacencies in the list, because we are
++                                      using this polygon .
++                              3. Get the next polygon.
++                      */
++                      /*      Return the face_id of the next polygon we will be using,
++                              while updating the adjacency list by decrementing the
++                              adjacencies of everything adjacent to the current polygon.
++                      */
++                              
++               next_face_id = Update_Adjacencies(face_id, &next_bucket, &e1,&e2,&ties);
++          
++               /*  Maybe we deleted something in a patch and could not find an adj polygon */
++               if (next_face_id == -1)
++               {
++ 
++                    /*   If we are at the first polygon in the strip and there is no input
++                         edge, then begin is TRUE
++                    */
++                    if ((e2 == 0) && (e3 == 0))
++                         Blind_Triangulate(face->nPolSize,face->pPolygon,
++                                                  bands,TRUE,1,color1,color2,color3);
++
++                    else
++                         Blind_Triangulate(face->nPolSize,face->pPolygon,
++                                                  bands,FALSE,1,color1,color2,color3);
++
++                        RemoveList(pListHead,(PLISTINFO) temp);
++                            
++                     /*      We will be at the beginning of the next strip. */
++                    face->nPolSize = 1;
++                    return (Finished(swaps,bands,global));
++               }
++
++               if (Done(next_face_id,59,&next_bucket) == NULL)
++                {
++                          printf("We deleted the next face 6 %d %d\n",next_face_id,face_id);
++                          exit(0);
++                   }
++                      
++                      Non_Blind_Triangulate(face->nPolSize,face->pPolygon, 
++                                               bands,next_face_id,face_id,1,color1,color2,color3);
++                                   
++               RemoveList(pListHead,(PLISTINFO) temp);
++               face->nPolSize = 1;
++                      pListHead = array[next_bucket];
++                      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                      if ( pfNode )
++                              pfNode->face_id = next_face_id;
++                      lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                                         (int (*)(void *,void *)) (Compare)));
++                      if (lpListInfo == NULL)
++                   {
++                              printf("There is an error finding the next polygon2 %d %d\n",next_face_id,next_bucket);
++                              exit(0);
++                      }
++                      return (Polygon_Output(lpListInfo,next_face_id,next_bucket,
++                                                   pListHead, FALSE, swaps,bands,color1,color2,color3,global,end));
++              }
++
++      }
++    Last_Edge(&e1,&e2,&e3,0);
++
++}       
++
++
++int Extend_Face(int face_id,int e1,int e2,int *swaps,FILE *bands,
++                int color1,int color2,int color3,int *vert_norm, int normals,
++                int *vert_texture, int texture)
++{
++    int dummy=0,next_bucket;
++    P_ADJACENCIES pfNode,lpListInfo;
++    ListHead *pListHead;
++
++    /*    Try to extend backwards off of the local strip that we just found */
++    
++    vn = vert_norm;
++    vt = vert_texture;
++    norm = normals;
++    text = texture;
++
++    *swaps = 0;
++    /*        Find the face that is adjacent to the edge and is not the
++              current face.
++    */
++    face_id = Find_Face(face_id, e1, e2,&next_bucket);
++    if (face_id == -1)
++          return 0;
++                      
++    pListHead = array[next_bucket];
++    pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++    if ( pfNode )
++              pfNode->face_id = face_id;
++    lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                     (int (*)(void *,void *)) (Compare)));
++    if (lpListInfo == NULL)
++    {
++              printf("There is an error finding the next polygon3 %d\n",face_id);
++              exit(0);
++    }
++    Last_Edge(&dummy,&e1,&e2,1);
++    
++    /*  Find a strip extending from the patch and return the cost */
++    return (Polygon_Output(lpListInfo,face_id,next_bucket,pListHead,TRUE,swaps,bands,color1,color2,color3,TRUE,TRUE));
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fd4b34c276687a5c4236372f154dbda1cc6aa2de
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,34 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: output.h
++-----------------------------------------------------------------------*/
++
++
++#include "polverts.h"
++
++#define TRIANGLE 3
++#define MAGNITUDE 1000000
++
++void Output_Tri(int id1, int id2, int id3,FILE *bands, int color1, 
++              int color2, int color3,BOOL end);
++void Sgi_Test();
++int Polygon_Output(P_ADJACENCIES temp,int face_id,int bucket,
++                 ListHead *pListHead, BOOL first, int *swaps,
++                 FILE *bands,int color1,int color2,int color3,
++                 BOOL global, BOOL end);
++void Last_Edge();
++void Extend_Backwards();
++int Finished(int *swap, FILE *output, BOOL global);
++int Extend_Face(int face_id,int e1,int e2,int *swaps,FILE *bands,
++                int color1,int color2,int color3,int *vert_norm, int normals,
++                int *vert_texture, int texture);
++void Fast_Reset();
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..10bfb741f5f61c53985e64c9e86c93da64e1cbd8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,514 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: outputex.c
++     This file contains routines that are used for various functions in
++     the local algorithm.
++*/
++/*---------------------------------------------------------------------*/
++
++
++#include <stdio.h>
++#include <stdlib.h>
++#include "global.h"
++#include "outputex.h"
++#include "triangulatex.h"
++#include "polverts.h"
++#include "ties.h"
++#include "partial.h"
++#include "sturctsex.h"
++#include "options.h"
++#include "output.h"
++#include "common.h"
++#include "util.h"
++
++
++void Output_TriEx(int id1, int id2, int id3, FILE *output, int next_face, int flag,
++              int where)
++{
++   /* We will save everything into a list, rather than output at once,
++      as was done in the old routine. This way for future modifications
++      we can change the strips later on if we want to.
++   */
++
++  int swap,temp1,temp2,temp3;
++  static int total=0;
++  static int tri=0;
++  static int strips = 0;
++  static int cost = 0;
++
++  if (flag == -20)
++  {
++    cost = cost + where+total+tri+strips+strips;
++    printf("We will need to send %d vertices to the renderer\n",cost);
++    total = 0;
++    tri = 0;
++    strips = 0;
++    return ;
++  }
++
++
++  if (flag == -10) /* We are finished, now is time to output the triangle list */
++  {
++    fprintf(output,"\nt ");
++    tri = tri + Finished(&swap,output,FALSE);
++    total = total + swap;
++    strips++;
++    /*printf("There are %d swaps %d tri %d strips\n",total,tri,strips);*/
++  }
++   
++  else
++  {
++    Last_Edge(&temp1,&temp2,&temp3,0);
++    Add_Id_Strips(id1,where);
++    Add_Id_Strips(id2,where);
++    Add_Id_Strips(id3,where);
++    Last_Edge(&id1,&id2,&id3,1);
++  }
++}
++
++              
++
++
++void Extend_BackwardsEx(int face_id, FILE *output, FILE *strip, int *ties, 
++                      int tie, int triangulate, int swaps, int *next_id)
++{
++    /*  We just made a strip, now we are going to see if we can extend
++         backwards from the starting face, which had 2 or more adjacencies
++         to start with.
++    */
++    int bucket,next_face,num,x,y,z,c,max,f;
++    ListHead *pListFace;
++    PF_FACES face;
++    P_ADJACENCIES temp;
++
++    /*  Get the first triangle that we have saved the the strip data 
++         structure, so we can see if there are any polygons adjacent
++         to this edge or a neighboring one
++    */
++    First_Edge(&x,&y,&z); 
++    
++    pListFace  = PolFaces[face_id];
++    face = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
++
++    num = face->nPolSize;
++
++    /*  Go through the edges to see if there is an adjacency
++         with a vertex in common to the first triangle that was
++         outputted in the strip. (maybe edge was deleted....)
++    */
++    for (c=0; c<num ; c++)
++    {
++         
++      if ( (c != (num-1)) && 
++           (( (*(face->pPolygon+c) == x) && (*(face->pPolygon+c+1) == y)) ||
++              (*(face->pPolygon+c) == y) && (*(face->pPolygon+c+1) == x)))
++      {
++          /*  Input edge is still there see if there is an adjacency */
++          next_face = Find_Face(face_id, x, y, &bucket);
++          if (next_face == -1)
++              /*  Could not find a face adjacent to the edge */
++              break;
++          pListFace = array[bucket];
++          max = NumOnList(pListFace);
++          for (f=0;;f++)
++          {
++                      temp = (P_ADJACENCIES) PeekList(pListFace,LISTHEAD,f);  
++                   if (temp->face_id == next_face)
++                   {
++                        Last_Edge(&z,&y,&x,1);
++                        Polygon_OutputEx(temp,temp->face_id,bucket,pListFace,
++                                                     output,strip,ties,tie,triangulate,swaps,next_id,0);
++                        return;
++                   }
++
++                      if (temp == NULL)
++                      {
++                                      printf("Error in the new buckets%d %d %d\n",bucket,max,0);
++                                      exit(0);
++                      }
++          }
++
++      }
++      else if ( (c == (num -1)) &&
++         ( ((*(face->pPolygon) == x) && (*(face->pPolygon+num-1) == y)) ||
++            (*(face->pPolygon) == y) && (*(face->pPolygon+num-1) == x)))
++      {
++           next_face = Find_Face(face_id,x,y,&bucket);
++           if (next_face == -1)
++              /*  Could not find a face adjacent to the edge */
++                   break;
++              pListFace = array[bucket];
++              max = NumOnList(pListFace);
++              for (f=0;;f++)
++              {
++                      temp = (P_ADJACENCIES) PeekList(pListFace,LISTHEAD,f);
++                   if (temp->face_id == next_face)
++                   {
++                        Last_Edge(&z,&y,&x,1);
++                        Polygon_OutputEx(temp,temp->face_id,bucket,pListFace,
++                                                  output,strip,ties,tie,triangulate,swaps,next_id,0);
++                        return;
++                   }
++
++                      if (temp == NULL)
++                      {
++                                      printf("Error in the new buckets%d %d %d\n",bucket,max,0);
++                                      exit(0);
++                      }
++          }
++      }
++    
++    }
++
++}
++
++void Polygon_OutputEx(P_ADJACENCIES temp,int face_id,int bucket,
++                    ListHead *pListHead, FILE *output, FILE *strips,
++                    int *ties, int tie, int triangulate, int swaps,
++                    int *next_id, int where)
++{
++      ListHead *pListFace;
++      PF_FACES face;
++      P_ADJACENCIES pfNode;
++      static BOOL begin = TRUE;
++      int old_face,next_face_id,next_bucket,e1,e2,e3,other1,other2,other3;
++      P_ADJACENCIES lpListInfo; 
++
++      /*      We have a polygon to output, the id is face id, and the number
++                 of adjacent polygons to it is bucket.
++      */
++
++     Last_Edge(&e1,&e2,&e3,0);
++    
++     /*  Get the polygon with id face_id */
++      pListFace  = PolFaces[face_id];
++      face = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
++
++     if (face->nPolSize == 3)
++      {
++              /*      It is already a triangle */
++              if (bucket == 0)
++              {
++                      /*      It is not adjacent to anything so we do not have to
++                                 worry about the order of the sides or updating adjacencies
++                      */
++                          
++                Last_Edge(&e1,&e2,&e3,0);
++                next_face_id = Different(*(face->pPolygon),*(face->pPolygon+1),*(face->pPolygon+2),
++                                            e1,e2,e3,&other1,&other2);
++                /*  No input edge, at the start */
++                if ((e2 ==0) && (e3 == 0))
++                {
++                        e2 = other1;
++                        e3 = other2;
++                }
++          
++                      Output_TriEx(e2,e3,next_face_id,strips,-1,begin,where);
++                      RemoveList(pListHead,(PLISTINFO) temp);
++                      /*      We will be at the beginning of the next strip. */
++                      begin = TRUE;
++              }
++              /*      It is a triangle with adjacencies. This means that we
++                         have to:
++                              1. Update the adjacencies in the list, because we are
++                                      using this polygon and it will be deleted.
++                              2. Get the next polygon.
++              */
++              else
++              {
++                      /*   Return the face_id of the next polygon we will be using,
++                              while updating the adjacency list by decrementing the
++                              adjacencies of everything adjacent to the current triangle.
++                      */
++            
++               next_face_id = Update_AdjacenciesEx(face_id, &next_bucket, &e1,&e2,ties);
++                      old_face = next_face_id;
++                                      
++              /*  Break the tie,  if there was one */
++                  if (tie != FIRST)
++                              old_face = Get_Next_Face(tie,face_id,triangulate);
++
++              if (next_face_id == -1)
++              {
++                    Polygon_OutputEx(temp,face_id,0,pListHead,output,strips,ties,tie, 
++                          triangulate,swaps,next_id,where);
++                    return;
++              }
++
++
++              /*  We are using a different face */
++              if ((tie != FIRST) && (old_face != next_face_id) && (swaps == ON))
++             {
++                      next_face_id = old_face;
++                      /*  Get the new output edge, since e1 and e2 are for the
++                          original next face that we got.
++                      */
++                  e3 = Get_EdgeEx(&e1,&e2,face->pPolygon,next_face_id,face->nPolSize,0,0);
++              }
++                      
++                 /*      Find the other vertex to transmit in the triangle */
++                 e3 = Return_Other(face->pPolygon,e1,e2);
++              Last_Edge(&other1,&other2,&other3,0);
++          
++              if ((other1 != 0) && (other2 != 0))
++              {
++                     /*   See which vertex in the output edge is not in the input edge */
++                     if ((e1 != other2) && (e1 != other3))
++                             e3 = e1;
++                     else if ((e2 != other2) && (e2 != other3))
++                             e3 = e2;
++                     /* can happen with > 2 polys on an edge  but won't form a good strip so stop
++                       the strip here
++                    */
++                    else
++                     {
++                         Polygon_OutputEx(temp,face_id,0,pListHead,output,strips,ties,tie, 
++                                                 triangulate,swaps,next_id,where);
++                         return;
++             }
++
++             /*   See which vertex of the input edge is not in the output edge */
++             if ((other2 != e1) && (other2 != e2))
++             {
++                        other1 = other2;
++                        other2 = other3;
++             }
++             else if ((other3 != e1) && (other3 != e2))
++                        other1 = other3;
++             else
++             {
++                 /* Degenerate triangle just return*/
++               Output_TriEx(other1,other2,e3,strips,next_face_id,begin,where);
++                      RemoveList(pListHead,(PLISTINFO) temp);
++                      begin = FALSE;
++               return;
++             }
++                    
++         }
++         
++         /*   There was not an input edge, we are the first triangle in a strip */
++         else 
++         {
++             /*   Find the correct order to transmit the triangle, what is
++                     the output edge that we want ?
++             */
++             other1 = e3;
++             e3 = e2;
++             other2 = e1;
++         }
++         
++         /*   At this point the adjacencies have been updated  and we
++                 have the next polygon id 
++         */
++        Output_TriEx(other1,other2,e3,strips,next_face_id,begin,where);
++         RemoveList(pListHead,(PLISTINFO) temp);
++         begin = FALSE;
++
++         if (Done(next_face_id,59,&next_bucket) == NULL)
++              return;
++
++        pListHead = array[next_bucket];
++         pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++         if ( pfNode )
++              pfNode->face_id = next_face_id;
++         lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                               (int (*)(void *,void *)) (Compare)));
++         if (lpListInfo == NULL)
++         {
++                              printf("There is an error finding the next polygon3 %d\n",next_face_id);
++                              exit(0);
++         }
++         Polygon_OutputEx(lpListInfo,next_face_id,next_bucket,
++                                      pListHead, output, strips,ties,tie,triangulate,swaps,next_id,where);
++
++      }
++}
++
++      else
++      {
++              /*      It is not a triangle, we have to triangulate it .
++                         Since it is not adjacent to anything we can triangulate it
++                         blindly
++              */
++              if (bucket == 0)
++              {
++                      /*  Check to see if there is not an input edge */
++                Last_Edge(&other1,&other2,&other3,0);
++                if ((other1 == 0) && (other2 ==0))
++                        Blind_TriangulateEx(face->nPolSize,face->pPolygon, strips,
++                                                        output,TRUE,where);
++                else
++                        Blind_TriangulateEx(face->nPolSize,face->pPolygon,strips,
++                                               output,FALSE,where);
++
++                      RemoveList(pListHead,(PLISTINFO) temp);
++                      /*      We will be at the beginning of the next strip. */
++                      begin = TRUE;
++              }
++
++               /*  If we have specified PARTIAL triangulation then
++                      we will go to special routines that will break the
++                      polygon and update the data structure. Else everything
++                      below will simply triangulate the whole polygon 
++              */
++              else if (triangulate == PARTIAL)
++              {
++          
++                /*  Return the face_id of the next polygon we will be using,
++                      */
++                      next_face_id = Min_Face_AdjEx(face_id,&next_bucket,ties);
++
++              
++                      /* Don't do it partially, because we can go inside and get
++                      less adjacencies, for a quad we can do the whole thing.
++                */
++                if ((face_id == next_face_id) && (face->nPolSize == 4)  && (swaps == ON))
++                {
++                    next_face_id = Update_AdjacenciesEx(face_id, &next_bucket, &e1,&e2,ties);
++                        if (next_face_id == -1)
++                        {
++                             /*  There is no sequential face to go to, end the strip */
++                             Polygon_OutputEx(temp,face_id,0,pListHead,output,strips,ties,tie, 
++                                                       triangulate,swaps,next_id,where);
++                             return;
++                        }
++               
++                    /* Break the tie,  if there was one */
++                        if (tie != FIRST)
++                                next_face_id = Get_Next_Face(tie,face_id,triangulate);
++                        Non_Blind_TriangulateEx(face->nPolSize,face->pPolygon, strips,
++                                                            output,next_face_id,face_id,where);
++                           RemoveList(pListHead,(PLISTINFO) temp);
++                }
++         
++                /*   Was not a quad but we still do not want to do it partially for
++                        now, since we want to only do one triangle at a time
++                */
++                else if ((face_id == next_face_id) && (swaps == ON))
++                     Inside_Polygon(face->nPolSize,face->pPolygon,strips,output,
++                                       next_face_id,face_id,next_id,pListHead,temp,where);
++
++                else
++                {
++                                       if ((tie != FIRST) && (swaps == ON))
++                                               next_face_id = Get_Next_Face(tie,face_id,triangulate);
++                                       Partial_Triangulate(face->nPolSize,face->pPolygon,strips,
++                                                              output,next_face_id,face_id,next_id,pListHead,temp,where);
++                                      /*    Check the next bucket again ,maybe it changed 
++                                               We calculated one less, but that might not be the case
++                                      */
++               }
++
++                      if (Done(next_face_id,59,&next_bucket) == NULL)
++                      {
++                      /*  Check to see if there is not an input edge */
++                     Last_Edge(&other1,&other2,&other3,0);
++                     if ((other1 == 0) && (other2 ==0))
++                             Blind_TriangulateEx(face->nPolSize,face->pPolygon, strips,
++                                                             output,TRUE,where);
++                     else
++                             Blind_TriangulateEx(face->nPolSize,face->pPolygon,strips,
++                                                    output,FALSE,where);
++                    
++                    if (Done(face_id,59,&bucket) != NULL)
++                    {
++                         pListHead = array[bucket];
++                                pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                                if ( pfNode )
++                                        pfNode->face_id = face_id;
++                                lpListInfo = (P_ADJACENCIES) (SearchList(array[bucket], pfNode,
++                                                (int (*)(void *,void *)) (Compare)));
++                                RemoveList(pListHead,(PLISTINFO)lpListInfo);
++                    }
++                    begin = TRUE;
++                              return;
++                      }
++                      
++                      begin = FALSE;
++                      pListHead = array[next_bucket];
++                      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                      if ( pfNode )
++                              pfNode->face_id = next_face_id;
++                      lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                                      (int (*)(void *,void *)) (Compare)));
++                      if (lpListInfo == NULL)
++                      {
++                              printf("There is an error finding the next polygon1 %d %d\n",next_face_id,next_bucket);
++                              exit(0);
++                      }
++                      Polygon_OutputEx(lpListInfo,next_face_id,next_bucket,
++                                          pListHead, output, strips,ties,tie,triangulate,swaps,next_id,where);
++              }
++
++          
++              else
++              {
++                      /*  WHOLE triangulation */
++                /*  It is not a triangle and has adjacencies. 
++                              This means that we have to:
++                              1. TriangulateEx this polygon, not blindly because
++                                      we have an edge that we want to come out on, that
++                                      is the edge that is adjacent to a polygon with the
++                                      least number of adjacencies. Also we must come in
++                                      on the last seen edge.
++                              2. Update the adjacencies in the list, because we are
++                                      using this polygon .
++                              3. Get the next polygon.
++                      */
++                      /*   Return the face_id of the next polygon we will be using,
++                              while updating the adjacency list by decrementing the
++                              adjacencies of everything adjacent to the current polygon.
++                      */
++                              
++               next_face_id = Update_AdjacenciesEx(face_id, &next_bucket, &e1,&e2,ties);
++
++               if (Done(next_face_id,59,&next_bucket) == NULL)
++               {
++                    Polygon_OutputEx(temp,face_id,0,pListHead,output,strips,ties,tie, 
++                                            triangulate,swaps,next_id,where);
++                    /*    Because maybe there was more than 2 polygons on the edge */
++                    return;
++                   }
++
++                   /*      Break the tie,  if there was one */
++                      else if (tie != FIRST)
++                              next_face_id = Get_Next_Face(tie,face_id,triangulate);
++                              
++                      Non_Blind_TriangulateEx(face->nPolSize,face->pPolygon, strips,
++                                                       output,next_face_id,face_id,where);
++                      RemoveList(pListHead,(PLISTINFO) temp);
++                      begin = FALSE;
++                      pListHead = array[next_bucket];
++                      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                      if ( pfNode )
++                              pfNode->face_id = next_face_id;
++                      lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                                         (int (*)(void *,void *)) (Compare)));
++                      if (lpListInfo == NULL)
++                   {
++                                      printf("There is an error finding the next polygon2 %d %d\n",next_face_id,next_bucket);
++                                      exit(0);
++               }
++                      Polygon_OutputEx(lpListInfo,next_face_id,next_bucket,
++                                             pListHead, output, strips,ties,tie,triangulate,swaps,next_id,where);
++              }
++
++      }
++    Last_Edge(&e1,&e2,&e3,0);
++
++}       
++
++
++
++      
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f59f7e75ca3364e24b2775028b56638c8cebf0d0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,31 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: outputex.h
++-----------------------------------------------------------------------*/
++
++
++#include "polverts.h"
++
++
++#define TRIANGLE 3
++#define MAGNITUDE 1000000
++
++void Output_TriEx(int id1, int id2, int id3, FILE *output, int next_face, 
++                int flag, int where);
++void Sgi_Test();
++void Polygon_OutputEx(P_ADJACENCIES temp,int face_id,int bucket,
++                    ListHead *pListHead, FILE *output, FILE *strips,
++                    int *ties, int tie, int triangulate, int swaps,
++                    int *next_id, int where);
++void Extend_BackwardsEx(int face_id, FILE *output, FILE *strip, int *ties, 
++                      int tie, int triangulate, int swaps,int *next_id);
++void FinishedEx();
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..847b40501fc79395bb49bc89f887473b1ee9f347
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,668 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: partial.c
++     This file contains routines that are used partial triangulation of polygons
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include "global.h"
++#include "outputex.h"
++#include "polyvertsex.h"
++#include "triangulatex.h"
++#include "sturctsex.h"
++#include "polverts.h"
++#include "common.h"
++#include "util.h"
++
++void P_Triangulate_Quad(int out_edge1,int out_edge2,int in_edge1,
++                                        int in_edge2,int size,int *index,
++                                        FILE *output,FILE *fp,int reversed,int face_id,
++                                        int *next_id,ListHead *pListHead, 
++                                        P_ADJACENCIES temp,
++                      int where)
++{
++    int vertex4,vertex5,dummy=60;
++      
++    /*        This routine will nonblindly triangulate a quad, meaning
++              that there is a definite input and a definite output
++              edge that we must adhere to. Reversed will tell the orientation
++              of the input edge. (Reversed is -1 is we do not have an input
++              edge, in other words we are at the beginning of a strip.)
++              Out_edge* is the output edge, and in_edge* is the input edge. 
++              Index are the edges of the polygon
++              and size is the size of the polygon. Begin is whether we are
++              at the start of a new strip.
++              Note that we will not necessarily triangulate the whole quad;
++              maybe we will do half and leave the other half (a triangle)
++              for later.
++      */
++      
++
++    /*        If we do not have an input edge, then we can make our input
++              edge whatever we like, therefore it will be easier to come
++              out on the output edge. In this case the whole quad is done.
++      */
++      if (reversed == -1)
++      {
++              vertex4 = AdjacentEx(out_edge1,out_edge2,index,size);
++              vertex5 = Get_Other_Vertex(vertex4,out_edge1,out_edge2,index);
++              Output_TriEx(vertex5,vertex4,out_edge1,output,-1,-1,where);
++              Output_TriEx(vertex4,out_edge1,out_edge2,output,-1,-1,where);
++              dummy = Update_AdjacenciesEx(face_id, &dummy, &dummy,&dummy,&dummy);
++              RemoveList(pListHead,(PLISTINFO) temp);
++              return;
++      }
++      
++      /*      These are the 5 cases that we can have for the output edge */
++      
++      /*  Are they consecutive so that we form a triangle to
++              peel off, but cannot use the whole quad?
++      */
++
++      if (in_edge2 == out_edge1) 
++      {
++              /*      Output the triangle that comes out the correct
++                      edge. Save the other half for later.
++              */
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge2,index);
++          Output_TriEx(in_edge1,in_edge2,out_edge2,output,-1,-1,where);
++              /*      Now we have a triangle used, and a triangle that is
++                      left for later.
++              */
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,
++                              face_id,&dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,in_edge2,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              /*      Put the new face in the proper bucket of adjacencies 
++                      There are 2 edges that need to be checked for the triangle
++                      that was just outputted. For the output edge we definitely
++                      will be decreasing the adjacency, but we must check for the
++                      input edge.
++              */
++
++              dummy = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp,FALSE);
++              dummy = Change_FaceEx(face_id,in_edge2,out_edge2,pListHead,temp,TRUE);
++              
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the triangle as the new face 
++              */
++              New_Face(face_id,in_edge1,out_edge2,vertex4);
++              return;                                                                   
++      }
++      else if (in_edge1 == out_edge1)
++      {
++              /*      We want to output the first triangle (whose output
++                      edge is not the one that we want.
++                      We have to find the vertex that we need, which is
++                      the other vertex which we do not have.
++              */                                              
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge2,index);
++              Output_TriEx(in_edge2,in_edge1,out_edge2,output,-1,-1,where);
++              /*      Now we have a triangle used, and a triangle that is
++                      left for later.
++              */
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              dummy = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp,FALSE);
++              dummy = Change_FaceEx(face_id,in_edge1,out_edge2,pListHead,temp,TRUE);
++              
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the triangle as the new face 
++              */
++              New_Face(face_id,in_edge2,out_edge2,vertex4);
++              return;
++      }
++      
++      /*      Consecutive cases again, but with the output edge reversed */
++      else if (in_edge1 == out_edge2)
++      {
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
++              Output_TriEx(in_edge2,in_edge1,out_edge1,output,-1,-1,where);
++              /*      Now we have a triangle used, and a triangle that is
++                      left for later.
++              */
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              dummy = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp,FALSE);
++              dummy = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp,TRUE);
++              
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the triangle as the new face 
++              */
++              New_Face(face_id,in_edge2,out_edge1,vertex4);
++          return;
++      }
++      else if (in_edge2 == out_edge2)
++      {
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
++              Output_TriEx(in_edge1,in_edge2,out_edge1,output,-1,-1,where);
++              /*      Now we have a triangle used, and a triangle that is
++                      left for later.
++              */
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              dummy = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp,FALSE);
++              dummy = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp,TRUE);
++              
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the triangle as the new face 
++              */
++              New_Face(face_id,in_edge1,out_edge1,vertex4);
++              return;
++      }
++
++      /*      The final case is where we want to come out the opposite
++              edge.
++      */
++      else
++      {
++        if( ((!reversed) && (out_edge1 == (AdjacentEx(in_edge1,in_edge2,index,size)))) ||
++                    ((reversed) && (out_edge2 == (AdjacentEx(in_edge2,in_edge1,index,size)))))
++              {
++                      /*      We need to know the orientation of the input
++                              edge, so we know which way to put the diagonal.
++                And also the output edge, so that we triangulate
++                correctly. Does not need partial.
++             */
++                      Output_TriEx(in_edge1,in_edge2,out_edge2,output,-1,-1,where);
++                      Output_TriEx(in_edge2,out_edge2,out_edge1,output,-1,-1,where);
++                      dummy = Update_AdjacenciesEx(face_id, &dummy, &dummy,&dummy,&dummy);
++                      RemoveList(pListHead,(PLISTINFO) temp);
++              }
++              else
++              {
++                      /*      Input and output orientation was reversed, so diagonal will
++                                      be reversed from above.
++                      */
++                      Output_TriEx(in_edge1,in_edge2,out_edge1,output,-1,-1,where);
++                      Output_TriEx(in_edge2,out_edge1,out_edge2,output,-1,-1,where);
++                      dummy = Update_AdjacenciesEx(face_id, &dummy, &dummy,&dummy,&dummy);
++                      RemoveList(pListHead,(PLISTINFO) temp);
++              }
++              return;
++      }
++}
++
++void P_Triangulate_Polygon(int out_edge1,int out_edge2,int in_edge1,
++                                                 int in_edge2,int size,
++                                                int *index,FILE *output,FILE *fp,
++                                                int reversed,int face_id,int *next_id,
++                                                ListHead *pListHead, P_ADJACENCIES temp2,
++                          int where)
++{
++      /*      We have a polygon greater than 4 sides, which we wish
++              to partially triangulate
++      */
++      int next_bucket,vertex4,dummy = 60;
++      int *temp;
++      P_ADJACENCIES pfNode;
++
++              
++    /*        Since we are calling this recursively, we have to check whether         
++              we are down to the case of the quad.
++      */
++      if (size == 4)
++      {
++              P_Triangulate_Quad(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                                      index,output,fp,reversed,face_id,next_id,
++                                                      pListHead,temp2,where);
++              return;
++      }
++      
++      /*      We do not have a specified input edge, and therefore we
++              can make it anything we like, as long as we still come out 
++              the output edge that we want.
++      */
++      if (reversed  == -1)
++      {
++              /*      Get the vertex for the last triangle, which is
++                      the one coming out the output edge, before we do
++                      any deletions to the list. We will be doing this
++                      bottom up.
++              */
++              vertex4 = AdjacentEx(out_edge1,out_edge2,index,size);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_ListEx(out_edge2,index,size);
++              /*      We do not have to partially triangulate, since
++                      we will do the whole thing, so use the whole routine
++              */
++              /* Triangulate_PolygonEx(vertex4,out_edge1,in_edge2,
++                                    vertex4,size-1,index,output,fp,reversed,
++                                    face_id,next_id,pListHead,temp2,where); */
++              Triangulate_PolygonEx(vertex4,out_edge1,in_edge2,
++                                    vertex4,size-1,index,output,fp,reversed,
++                                    face_id,where);
++              memcpy(index,temp,sizeof(int)*size);
++              /*      Lastly do the triangle that comes out the output
++                      edge.
++              */
++              Output_TriEx(vertex4,out_edge1,out_edge2,output,-1,-1,where);
++              /*      We were able to do the whole polygon, now we
++                      can delete the whole thing from our data structure.
++              */
++              dummy = Update_AdjacenciesEx(face_id, &dummy, &dummy,&dummy,&dummy);
++              RemoveList(pListHead,(PLISTINFO) temp2);
++              return;
++      }         
++
++      /*      These are the 5 cases that we can have for the output edge */
++      
++      /*  Are they consecutive so that we form a triangle to
++              peel off that comes out the correct output edge, 
++              but we cannot use the whole polygon?
++      */
++      if (in_edge2 == out_edge1) 
++      {
++              Output_TriEx(in_edge1,out_edge1,out_edge2,output,-1,-1,where);
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++              next_bucket = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp2,TRUE);
++              
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++          Delete_From_ListEx(in_edge2,index,size);
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the polygon minus the triangle 
++                      as the new face, here we will be decrementing the size
++                      by one.
++              */
++              New_Size_Face(face_id);
++              return;
++      }
++
++      /*      Next case is where it is again consecutive, but the triangle
++              formed by the consecutive edges do not come out of the
++              correct output edge. (the input edge will be reversed in
++              the next triangle)
++      */
++      else if (in_edge1 == out_edge1)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              Output_TriEx(in_edge2,in_edge1,out_edge2,output,-1,-1,where);
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++              next_bucket = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp2,TRUE);
++              
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++          Delete_From_ListEx(in_edge1,index,size);
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the polygon minus the triangle 
++                      as the new face, here we will be decrementing the size
++                      by one.
++              */
++              New_Size_Face(face_id);
++              return;
++      }
++      
++      /*      Consecutive cases again, but with the output edge reversed */
++      else if (in_edge1 == out_edge2)
++      {
++              Output_TriEx(in_edge2,in_edge1,out_edge1,output,-1,-1,where);
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge1,out_edge2,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++              next_bucket = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp2,TRUE);
++              
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++        Delete_From_ListEx(in_edge1,index,size);
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the polygon minus the triangle 
++                      as the new face, here we will be decrementing the size
++                      by one.
++              */
++              New_Size_Face(face_id);
++              return;
++      }
++      else if (in_edge2 == out_edge2)
++      {
++              Output_TriEx(in_edge1,in_edge2,out_edge1,output,-1,-1,where);
++              
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(out_edge2,out_edge1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              
++              /*      Put the new face in the proper bucket of adjacencies */
++              next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++              next_bucket = Change_FaceEx(face_id,out_edge1,out_edge2,pListHead,temp2,TRUE);
++              
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++          Delete_From_ListEx(in_edge2,index,size);
++              /*      Update the face data structure, by deleting the old
++                      face and putting in the polygon minus the triangle 
++                      as the new face, here we will be decrementing the size
++                      by one.
++              */
++              New_Size_Face(face_id);
++              return;
++      }
++
++      /*      Else the edge is not consecutive, and it is sufficiently
++              far away, for us not to make a conclusion at this time.
++              So we can take off a triangle and recursively call this
++              function.
++      */
++      else
++      {
++          if (!reversed)
++              {
++                      vertex4 = AdjacentEx(in_edge2,in_edge1,index,size);
++                      Output_TriEx(in_edge1,in_edge2,vertex4,output,-1,-1,where);
++                      
++                      /*      Now delete the adjacencies by one for all the faces
++                              that are adjacent to the triangle that we just outputted.
++                      */
++                      Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++                      Delete_AdjEx(in_edge1,vertex4,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++                      
++                      /*      Put the new face in the proper bucket of adjacencies */
++                      next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++                      next_bucket = Change_FaceEx(face_id,in_edge1,vertex4,pListHead,temp2,FALSE);
++                      
++                      /*      Create a new edgelist without the triangle that
++                              was just outputted.
++                      */
++                      Delete_From_ListEx(in_edge1,index,size);
++                      /*      Update the face data structure, by deleting the old
++                              face and putting in the polygon minus the triangle 
++                              as the new face, here we will be decrementing the size
++                              by one.
++                      */
++                      New_Size_Face(face_id);
++
++                      /*      Save the info for the new bucket, we will need it on
++                              the next pass for the variables, pListHead and temp 
++                      */
++                      pListHead = array[next_bucket];
++                      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                      if ( pfNode )
++                              pfNode->face_id = face_id;
++                      temp2 = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                              (int (*)(void *,void *)) (Compare)));
++                      if (temp2 == NULL)
++                      {
++                              printf("There is an error finding the next polygon10 %d %d\n",next_bucket,face_id);
++                              exit(0);
++                      }
++
++                      P_Triangulate_Polygon(out_edge1,out_edge2,in_edge2,
++                                               vertex4,size-1,index,output,fp,!reversed,
++                                               face_id,next_id,pListHead,temp2,where);
++              }
++              else
++              {
++                      vertex4 = AdjacentEx(in_edge1,in_edge2,index,size);
++                      Output_TriEx(in_edge2,in_edge1,vertex4,output,-1,-1,where);
++
++                      /*      Now delete the adjacencies by one for all the faces
++                              that are adjacent to the triangle that we just outputted.
++                      */
++                      Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++                      Delete_AdjEx(in_edge2,vertex4,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++                      
++                      /*      Put the new face in the proper bucket of adjacencies */
++                      next_bucket = Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++                      next_bucket = Change_FaceEx(face_id,in_edge2,vertex4,pListHead,temp2,FALSE);
++                      
++                      /*      Create a new edgelist without the triangle that
++                              was just outputted.
++                      */
++                      Delete_From_ListEx(in_edge2,index,size);
++                      
++                      /*      Update the face data structure, by deleting the old
++                              face and putting in the polygon minus the triangle 
++                              as the new face, here we will be decrementing the size
++                              by one.
++                      */
++                      New_Size_Face(face_id);
++                      
++                      /*      Save the info for the new bucket, we will need it on
++                              the next pass for the variables, pListHead and temp 
++                      */
++                      pListHead = array[next_bucket];
++                      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++                      if ( pfNode )
++                              pfNode->face_id = face_id;
++                      temp2 = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
++                              (int (*)(void *,void *)) (Compare)));
++                      if (temp2 == NULL)
++                      {
++                              printf("There is an error finding the next polygon11 %d %d\n",face_id,next_bucket);
++                              exit(0);
++                      }
++
++                      P_Triangulate_Polygon(out_edge1,out_edge2,vertex4,
++                                                     in_edge1,size-1,index,output,fp,!reversed,
++                                                     face_id,next_id,pListHead,temp2,where);
++              }
++              return;
++      }
++}
++
++void P_Triangulate(int out_edge1,int out_edge2,int in_edge1,
++                               int in_edge2,int size,int *index,
++                               FILE *fp,FILE *output,int reversed,int face_id,
++                               int *next_id,ListHead *pListHead, 
++                               P_ADJACENCIES temp,int where)
++{
++              
++      if (size == 4)
++              P_Triangulate_Quad(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                    index,fp,output,reversed,face_id,next_id,pListHead, temp,where);
++      else
++              P_Triangulate_Polygon(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                       index,fp,output,reversed,face_id,next_id,pListHead,temp,where);
++}
++
++ void Partial_Triangulate(int size,int *index, FILE *fp,
++                                               FILE *output,int next_face_id,int face_id,
++                                               int *next_id,ListHead *pListHead,
++                                               P_ADJACENCIES temp, int where)
++{
++      int id1,id2,id3;
++      int nedge1,nedge2;
++      int reversed;
++
++      /*      We have a polygon that has to be triangulated and we cannot
++              do it blindly, ie we will try to come out on the edge that
++              has the least number of adjacencies, But also we do not
++              want to triangulate the whole polygon now, so that means 
++              we will output the least number of triangles that we can
++              and then update the data structures, with the polygon
++              that is left after we are done.
++      */
++      Last_Edge(&id1,&id2,&id3,0);
++      
++      /*      Find the edge that is adjacent to the new face ,
++              also return whether the orientation is reversed in the
++              face of the input edge, which is id2 and id3.
++      */
++      reversed = Get_EdgeEx(&nedge1,&nedge2,index,next_face_id,size,id2,id3);
++      
++      /*   Input edge and output edge can be the same if there are more than
++          one polygon on an edge 
++     */
++     if ( ((nedge1 == id2) && (nedge2 == id3)) ||
++          ((nedge1 == id3) && (nedge2 == id2)) )
++          /*   Set output edge arbitrarily but when come out of here the
++               next face will be on the old output edge (identical one)
++          */
++          nedge2 = Return_Other(index,id2,id3);
++
++          /*  Do the triangulation */ 
++      P_Triangulate(nedge1,nedge2,id2,id3,size,index,fp,output,reversed,
++                       face_id,next_id,pListHead,temp,where);
++}
++
++ void Input_Edge(int face_id, int *index, int size, int in_edge1, int in_edge2, 
++                FILE *fp, FILE *output,ListHead *pListHead, P_ADJACENCIES temp2,
++                int where)
++ {
++     /* The polygon had an input edge, specified by input1 and input2 */
++    
++     int output1;
++     int vertex4, vertex5,dummy=60;
++
++     output1 = Get_Output_Edge(face_id,size,index,in_edge1,in_edge2);
++      vertex5 = AdjacentEx(in_edge2,in_edge1,index,size); 
++     vertex4 = AdjacentEx(in_edge1,in_edge2,index,size);
++
++     if (vertex4 == output1)
++     {
++              Output_TriEx(in_edge2,in_edge1,output1,output,-1,-1,where);
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(in_edge2,output1,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              /*      Put the new face in the proper bucket of adjacencies */
++              Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++              Change_FaceEx(face_id,in_edge2,output1,pListHead,temp2,FALSE);
++              
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++          Delete_From_ListEx(in_edge2,index,size);
++
++    } 
++    else if (vertex5 == output1)
++    {
++          Output_TriEx(in_edge1,in_edge2,vertex5,output,-1,-1,where);
++              /*      Now delete the adjacencies by one for all the faces
++                      that are adjacent to the triangle that we just outputted.
++              */
++              Delete_AdjEx(in_edge1,in_edge2,&dummy,&dummy,face_id,
++                              &dummy,&dummy,&dummy);
++              Delete_AdjEx(in_edge1,vertex5,&dummy,&dummy, 
++                              face_id,&dummy,&dummy,&dummy);
++              /*      Put the new face in the proper bucket of adjacencies */
++              Change_FaceEx(face_id,in_edge1,in_edge2,pListHead,temp2,FALSE);
++              Change_FaceEx(face_id,in_edge1,vertex5,pListHead,temp2,FALSE);
++              
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++          Delete_From_ListEx(in_edge1,index,size);
++    }
++              
++    /*        Update the face data structure, by deleting the old
++              face and putting in the polygon minus the triangle 
++              as the new face, here we will be decrementing the size
++              by one.
++    */
++    New_Size_Face(face_id);
++    return;
++ }
++ 
++ void Inside_Polygon(int size,int *index,FILE *fp,FILE *output,
++                   int next_face_id,int face_id,int *next_id,
++                   ListHead *pListHead,P_ADJACENCIES temp, int where)
++ {
++     /* We know that we have a polygon that is greater than 4 sides, and
++        that it is better for us to go inside the polygon for the next
++        one, since inside will have less adjacencies than going outside.
++        So, we are not doing partial for a part of the polygon.
++      */
++    int id1,id2,id3;
++    int new1,new2;
++
++    Last_Edge(&id1,&id2,&id3,0);
++
++    /*  See if the input edge existed in the polygon, that will help us */
++      if (Exist(face_id,id2,id3))
++        Input_Edge(face_id,index,size,id2,id3,output,fp,pListHead,temp,where);
++    else
++    {
++        /*  Make one of the input edges 
++            We will choose it by trying to get an edge that has something
++            in common with the last triangle, or by getting the edge that
++            is adjacent to the least number of thigs, with preference given
++            to the first option
++        */
++               
++        Get_Input_Edge(index,id1,id2,id3,&new1,&new2,size,face_id);
++        Input_Edge(face_id,index,size,new1,new2,output,fp,pListHead,temp,where);
++    }
++ }
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6a4e3a5b18daffa9a3cdaf9f74ceda9bca956e40
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,20 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: partial.h
++-----------------------------------------------------------------------*/
++
++void Partial_Triangulate(int size,int *index, FILE *fp,
++                       FILE *output,int next_face_id,int face_id,
++                       int *next_id,ListHead *pListHead,
++                       P_ADJACENCIES temp, int where);
++void Inside_Polygon(int size,int *index,FILE *fp,FILE *output,
++                  int next_face_id,int face_id,int *next_id,
++                  ListHead *pListHead,P_ADJACENCIES temp, int where);
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b3979eb4b54d981b6450459ad43ec83d38f0a874
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,108 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: polverts.h
++-----------------------------------------------------------------------*/
++
++
++#ifndef _POLVERTS_H
++#define _POLVERTS_H
++
++
++#ifdef HAVE_CONFIG_H
++#  include <config.h>
++#endif
++
++#include "queue.h"
++
++#ifdef HAVE_STDLIB_H
++#  include <stdlib.h>
++#else
++#  include <malloc.h>
++#endif
++
++
++typedef struct adjacencies
++{
++      Node ListNode;
++      int face_id;
++} ADJACENCIES,*P_ADJACENCIES;
++
++typedef struct FVerts
++{
++      Node ListNode;
++      int *pPolygon;
++      int nPolSize;
++      int nId;
++} F_VERTS, *PF_VERTS;
++
++/*Every time we need to use this, cast it ( ListInfo*)*/
++
++typedef struct FEdges
++{
++      Node ListNode;
++      int edge[3];
++}F_EDGES,*PF_EDGES;
++
++typedef struct FFaces
++{
++      Node ListNode;
++      int *pPolygon;
++      int *pNorms;
++    int     seen;
++    int seen2;
++    int seen3;
++      int nPolSize;
++      F_EDGES **VertandId;
++      int *marked;
++              int *walked;
++} F_FACES,*PF_FACES;
++      
++
++typedef struct Strips
++{
++      Node ListNode;
++      int face_id;
++} Strips,*P_STRIPS;
++
++
++     struct vert_added
++     {
++          int num;
++          int *normal;
++     };
++
++
++/*      external functions */
++void Find_Adjacencies(int num_faces);
++void Test_Adj_Struct();
++void Test_SGI_Struct();
++void Write_Edges();
++void Build_SGI_Table(int num_verts,int num_faces);
++void Save_Walks(int numfaces);
++void Find_Bands(int numfaces, FILE *output_file, int *swaps, int *bands, 
++                int *cost, int *tri, int norms, int *vert_norms, int texture,
++              int *vert_texture);
++void Save_Rest(int *numfaces);
++void Assign_Walk(int lastvert, PF_FACES temp2, int front_walk,int y,
++                              int back_walk);
++void Save_Walks(int numfaces);
++      
++
++/*      Globals */
++extern ListHead **PolVerts;
++extern ListHead **PolFaces;
++extern ListHead **PolEdges;
++extern ListHead *array[60];
++extern int     id_array[60];
++extern ListHead *strips[1];
++extern ListHead *all_strips[100000]; /*  Assume max 100000 strips */
++
++
++#endif _POLVERTS_H
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4c541f7bcb19f236b9742dc738f798d5f1b9fb13
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,42 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: polvertsex.h
++-----------------------------------------------------------------------*/
++
++#ifdef HAVE_CONFIG_H
++#  include <config.h>
++#endif
++
++#ifdef HAVE_STDLIB_H
++#  include <stdlib.h>
++#else
++#  include <malloc.h>
++#endif
++
++#include "queue.h"
++
++/*      external functions */
++void Start_Vert_Struct();
++void Start_Face_StructEx();
++void Start_Edge_StructEx();
++void AddNewNode();
++void AddNewFaceEx();      
++void Find_AdjacenciesEx();
++void Test_Adj_Struct();
++void Test_SGI_Struct();
++void Write_Edges();
++void End_Verts_Struct();
++void End_Face_StructEx();
++void End_Edge_StructEx();
++void Build_SGI_TableEx();
++void Add_AdjEdgeEx();
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..966f203796931e1177e67d038b7ed6a881bc459b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,226 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: queue.c
++     This file contains the routines used in the data structures lists, which
++     are queues.
++*/
++/*---------------------------------------------------------------------*/
++
++ #include "queue.h"
++ 
++
++
++/*----------------------------------------------------------------------------
++ * InitList:
++ */
++BOOL  InitList  (PLISTHEAD LHead)
++ 
++{
++  if (LHead == NULL) return(FALSE);
++
++  LHead->LHeaders[LISTHEAD] = LHead->LHeaders[LISTTAIL] = NULL;
++  LHead->NumList = 0;
++  return(TRUE);
++}
++
++/*----------------------------------------------------------------------------
++ * AddHead:
++ */
++BOOL  AddHead(PLISTHEAD LHead, PLISTINFO LInfo)
++{
++     if (LHead == NULL || LInfo == NULL)
++          return(FALSE);
++     if (EMPTYLIST(LHead))
++          LHead->LHeaders[LISTTAIL] = LInfo;
++     else LHead->LHeaders[LISTHEAD]->ListNode.Previous = (void  *) LInfo;
++
++     LInfo->ListNode.Next = (void  *) LHead->LHeaders[LISTHEAD];
++     LHead->LHeaders[LISTHEAD] = LInfo;
++     LInfo->ListNode.Previous = NULL;
++     LHead->NumList++;
++     return(TRUE);
++}
++
++/*----------------------------------------------------------------------------
++ * AddTail
++ */
++BOOL  AddTail(PLISTHEAD LHead, PLISTINFO LInfo)
++{
++     if (LHead == NULL || LInfo == NULL)
++          return(FALSE);
++     if (EMPTYLIST(LHead))
++          LHead->LHeaders[LISTHEAD] = LInfo;
++     else LHead->LHeaders[LISTTAIL]->ListNode.Next = (void *) LInfo;
++
++     LInfo->ListNode.Previous = (void  *) LHead->LHeaders[LISTTAIL];
++     LHead->LHeaders[LISTTAIL] = LInfo;
++     LInfo->ListNode.Next = NULL;
++     LHead->NumList++;
++     return(TRUE);
++}
++
++
++BOOL  InsertNode( PLISTHEAD LHead, int nPos, PLISTINFO LInfo )
++{
++PLISTINFO LAddNode;
++
++     if ( LHead == NULL || LInfo == NULL || nPos > NumOnList( LHead ) ) 
++          return( FALSE );
++
++     if ( nPos == 0 )
++          AddHead( LHead, LInfo );
++     else if ( nPos == NumOnList( LHead ) ) 
++          AddTail( LHead, LInfo );
++     else
++     {
++          if ( (LAddNode = PeekList( LHead, LISTHEAD, nPos - 1 )) == NULL )
++               return( FALSE );
++          
++          ((PLISTINFO)LAddNode->ListNode.Next)->ListNode.Previous = LInfo;
++          LInfo->ListNode.Next      = LAddNode->ListNode.Next;
++          LInfo->ListNode.Previous  = LAddNode;
++          LAddNode->ListNode.Next   = LInfo;
++          
++          LHead->NumList++;
++     }
++
++     return( TRUE );
++}
++
++
++
++
++/*----------------------------------------------------------------------------
++ *  RemHead:
++ */
++PLISTINFO  RemHead(PLISTHEAD LHead)
++{
++     PLISTINFO t, t1;
++
++     if ( LHead == NULL || EMPTYLIST(LHead) )
++          return(NULL);
++
++     t = LHead->LHeaders[LISTHEAD];
++     LHead->LHeaders[LISTHEAD] = (PLISTINFO) t->ListNode.Next;
++
++     if (LHead->LHeaders[LISTHEAD] != NULL)
++     {
++          t1 = (PLISTINFO) t->ListNode.Next;
++          t1->ListNode.Previous = NULL;
++     }
++     else
++          LHead->LHeaders[LISTTAIL] = NULL;
++
++     LHead->NumList--;
++
++     return(t);
++}
++
++/*----------------------------------------------------------------------------
++ *  RemTail:
++ */
++PLISTINFO  RemTail(PLISTHEAD   LHead)
++{
++     PLISTINFO   t, t1;
++
++     if ( LHead == NULL || EMPTYLIST(LHead) )
++          return(NULL);
++
++     t = LHead->LHeaders[LISTTAIL];
++     LHead->LHeaders[LISTTAIL] = (PLISTINFO) t->ListNode.Previous;
++     if (LHead->LHeaders[LISTTAIL] != NULL)
++     {
++          t1 = (PLISTINFO) t->ListNode.Previous;
++          t1->ListNode.Next = NULL;
++     }
++     else
++          LHead->LHeaders[LISTHEAD] = NULL;
++
++     LHead->NumList--;
++     return(t);
++}
++
++/*----------------------------------------------------------------------------
++ * PeekList:
++ */
++PLISTINFO  PeekList(PLISTHEAD LHead, int wch, int index )
++{
++     PLISTINFO  t;
++
++     if (LHead == NULL)
++          return(NULL);
++     if ( (t = LHead->LHeaders[wch]) == NULL )
++          return(NULL);
++
++     for (; t != NULL && index > 0; index-- )
++          t = (wch == LISTHEAD)  ? (PLISTINFO) t->ListNode.Next  :
++                                   (PLISTINFO) t->ListNode.Previous;
++     return(t);
++}
++
++
++/*----------------------------------------------------------------------------
++ * RemoveList:
++ */
++PLISTINFO   RemoveList( PLISTHEAD LHead, PLISTINFO LInfo )
++{
++     PLISTINFO     t, t1;
++
++     t = LInfo;
++     if (LHead == NULL)
++          return(NULL);
++     if (LHead->LHeaders[LISTHEAD] == t)
++          t = (PLISTINFO) RemHead(LHead);
++     else if (LHead->LHeaders[LISTTAIL] == t)
++          t = (PLISTINFO) RemTail(LHead);
++     else
++     {
++          t1                    = (PLISTINFO) t->ListNode.Previous;
++          t1->ListNode.Next     = t->ListNode.Next;
++          t1                    = (PLISTINFO) t->ListNode.Next;
++          t1->ListNode.Previous = t->ListNode.Previous;
++          LHead->NumList--;
++     }
++
++     return(t);
++}
++
++/*----------------------------------------------------------------------------
++ * SearchList:
++ *       Try to find a specific node in the queue whose key matches with
++ *  searching key. Return the pointer to that node if found, return NULL
++ *  otherwise
++ *
++ *  Input:
++ *    lpHashTbl       => a far pointer to the hash table
++ *    lpKey           => a far poniter to searching key
++ *    CompareCallBack => comparision function
++ *
++ *  Output: a far pointer to the node to be found
++ *
++ */
++PLISTINFO  SearchList(
++                        PLISTHEAD lpListHead,
++                        PVOID lpSKey,
++                        int (* CompareCallBack) ( PVOID, PVOID ) )
++{
++PLISTINFO lpListInfo;
++
++     lpListInfo = PeekList( lpListHead, LISTHEAD, 0);
++     while ( lpListInfo != NULL )
++     {
++          if ( CompareCallBack( lpListInfo, lpSKey ) )
++               break;
++          lpListInfo = GetNextNode( lpListInfo );
++     }
++
++     return( lpListInfo );
++}
++ 
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0bf926e0f389ddb62faa16f26139285eed538938
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,283 @@@
++
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE:queue.h
++-----------------------------------------------------------------------*/
++
++#ifndef QUEUE_INCLUDED
++#define QUEUE_INCLUDED
++
++/*        %%s  Node      */
++/*****************************************************************
++     This structure is used to store the List linkage information of a
++ListInfo structure.  It contains all the necessary information for the
++List functions to function properly.  This structure must be the first
++one defined in any block of memory to be linked with the List functions.
++for an example of the used of The Node structure look in the files
++ipd2dms.c and ipd2man.h
++******************************************************************/
++#include <stdio.h>
++#define FALSE 0
++#define TRUE  1
++typedef struct
++{
++     void  *Next;
++     void  *Previous;
++}
++     Node, * PNODE;
++
++/*****************************************************************
++     Next     :  is a pointer to the next structure in this List.
++     Previous :  is a pointer to the previous structure in this List.
++     priority :  this is the priority of this structure in the List.  The
++                 highest priority is 0.  This field is only used by the
++                 functions EnQue and DeQue.
++******************************************************************/
++/*        %%e       */
++
++
++/*        %%s  ListInfo      */
++
++/*****************************************************************
++      This is the general means of linking application defined information into
++Lists and queues.  All structures must begin with the Node Structure.  All
++other data in the structure is user definable.
++******************************************************************/
++
++typedef struct List
++{
++     Node     ListNode;       /*  link to the next Listinfo Structure  */
++     /*  user definable data  */
++}    ListInfo, *PLISTINFO;
++
++/*****************************************************************
++     ListNode  :  this is the required node structure for the List
++                  mainpulation functions.  This must be the first
++                  element of a user definable structure.
++
++     In order for an application to use the List routines, it must define
++a structure with all the needed information.  The first element in the
++user definable structure must be a Node structure.  The Node structure
++contains all the necessary information for the List routines to do their
++magic.  For an example of a user defined List structure see the file
++ipd2i.h.  The User definable structure can be passed to any List function
++that excepts a pointer to a ListInfo structure.
++
++example:
++
++typedef  mstruct
++{
++     Node   ListNode;
++     int    a,b,c,d,e,f,g;
++}
++     mystruct;
++
++     the user definable portion of the above structure is represented by
++the integers a,b,c,d,e,f,g.  When passing this structure to a List
++function a cast of (ListInfo *) must be made to satisify the "C" complier.
++******************************************************************/
++/*        %%e       */
++
++
++/*        %%s ListHead        */
++/*****************************************************************
++     ListHead is used as a header to a List.  LHeaders[0] points to the
++head of the List.  LHeaders[1] points the tail of the list.  When
++accessing these variables use the defines  LISTHEAD, LISTTAIL.
++******************************************************************/
++
++typedef struct LHead
++{
++     PLISTINFO  LHeaders[2];
++     int         NumList;
++}
++ListHead, *PLISTHEAD;
++
++/*****************************************************************
++     LHeaders   :  this is an array of two pointers to ListInfo structures.
++                   This information is used to point to the head and tail of
++                   a list.
++     NumList    :  this integer hold the number of structures linked into this
++                   list.
++
++ListHead #define:
++
++     LISTHEAD  :  when Peeking down a list this specifies you should
++                  start at the Head of the list and search downward.
++
++     LISTTAIL  :  when Peeking down a list this specifies you should
++                  start at the tail of the list and search foward.
++ ******************************************************************/
++
++#define  LISTHEAD  0
++
++#define  LISTTAIL  1
++/*        %%e       */ 
++
++typedef int BOOL;
++typedef void * PVOID;
++
++#define PEEKFROMHEAD( lh, ind )     ( PeekList( (lh), LISTHEAD, (ind) ) )
++#define PEEKFROMTAIL( lh, ind )     ( PeekList( (lh), LISTTAIL, (ind) ) )
++#define EMPTYLIST( lh )             ( ( (lh)->LHeaders[LISTHEAD] == NULL ) )
++
++/*   General utility routines   */
++/*        %%s QueRoutines          */
++BOOL    InitList      ( PLISTHEAD );
++
++/*****************************************************************
++     InitList :  Initialize a new list structure for use with the List
++                 routines
++
++     INPUTS   :  LHead : a pointer to a ListHead structure.
++     OUTPUT   :  a boolean value TRUE if no errors occured FALSE
++                 otherwise
++******************************************************************/
++
++
++PLISTINFO  PeekList      ( PLISTHEAD, int, int   );
++
++/*****************************************************************
++     PeekList :  This funciton peeks down a list for the N'th element
++                 from the HEAD or TAIL of the list
++
++     INPUTS   :  LHead    :  a pointer to a List head structure.
++                 from     :  can either search from the HEAD or TAIL
++                             of the list
++                 where    :  how many nodes from the begining should the
++                             List routines look.
++     OUTPUT   :  a pointer to a ListInfo structure identified by
++                 from/where or NULL if an error occurred.
++******************************************************************/
++
++
++PLISTINFO   RemoveList( PLISTHEAD LHead, PLISTINFO LInfo );
++
++
++/*****************************************************************
++     RemoveList: Remove a ListInfo structure from a List.
++
++     INPUTS    : LHead  :  a pointer to a ListHead structure.
++                 LInfo  :  a pointer to the ListInfo structure to remove
++                           from the list.
++     OUTPUT    : a pointer to the ListInfo structure that was removed or
++                 NULL if an error occurred.
++******************************************************************/
++
++BOOL  InsertNode( PLISTHEAD LHead, int nPos, PLISTINFO LInfo );
++
++/*****************************************************************
++     InsertNode: add a node to a list after a given node
++     
++     INPUTS    : LHead : a pointer to a ListHead structure.
++                 nPos  : the position to insert the node into
++                 LInfo : a pointer to the new node to add to the list.
++     OUTPUT: a boolean value TRUE if all goes well false otherwise
++*****************************************************************/
++
++BOOL   AddHead       ( PLISTHEAD, PLISTINFO );
++
++/*****************************************************************
++     AddHead   : add a ListInfo structure to the HEAD of a list.
++
++     INPUTS    : LHead  : a pointer to a ListHead structure of the list
++                          to add to.
++                 LInfo  : a pointer to the ListInfo structure to add to
++                          the list.
++     OUTPUT    : A boolean value TRUE if no errors occurred FALSE
++                 otherwise.
++******************************************************************/
++
++
++BOOL     AddTail       ( PLISTHEAD, PLISTINFO );
++
++/*****************************************************************
++     AddTail   : Add a ListInfo structure to the TAIL of a list.
++
++     INPUTS    : LHead  : a pointer to a ListHead structure of the List
++                          to add to.
++                 LInfo  : a pointer to the ListInfo structure to add to
++                          the List.
++     OUTPUT    : a boolean value TRUE if no errors occurred FALSE
++                 otherwise.
++******************************************************************/
++
++
++PLISTINFO  RemTail       ( PLISTHEAD );
++
++/*****************************************************************
++     RemTail   : Remove a ListInfo structure from the TAIL of a List.
++
++     INPUTS    : LHead  : a pointer to a ListHead structure of the List
++                          to remove from.
++     OUTPUT    : a pointer to the ListInfo structure that was removed
++                 or NULL if an error occurred.
++******************************************************************/
++
++
++PLISTINFO  RemHead       ( PLISTHEAD );
++
++/*****************************************************************
++     RemHead   : Remove a ListInfo structure from the Head of a List.
++
++     INPUTS    : LHead  : a pointer to a ListHead structure of the List
++                          to remove from.
++     OUTPUT    : a pointer to the ListInfo structure that was removed or
++                 NULL if an error occurred.
++******************************************************************/
++
++PLISTINFO  SearchList(
++                        PLISTHEAD lpListHead,
++                        PVOID lpSKey,
++                        int ( * CompareCallBack) ( PVOID, PVOID ) );
++
++/*****************************************************************
++  SearchList:
++        Try to find a specific node in the queue whose key matches with
++   searching key. Return the pointer to that node if found, return NULL
++   otherwise
++
++   Input:
++     lpHashTbl       => a far pointer to the hash table
++     lpKey           => a far poniter to searching key
++     CompareCallBack => comparision function
++
++   Output: a far pointer to the node to be found
++
++ ******************************************************************/
++
++#define           NumOnList(lh) ( ((lh)->NumList)        )
++
++/*****************************************************************
++     NumOnList: Returns the number of Nodes linked to a ListHead
++                structure.  This number is maintained by the List
++                routines.
++******************************************************************/
++
++#define           GetNextNode(pli) ( ((pli)->ListNode.Next) )
++
++/********************************************************
++     GetNextNode: This macro returns the Next Structure in this list.
++                  This macro will return NULL if no more structures are
++                  in the List.
++*********************************************************/
++
++#define           GetPrevNode(pli) ( ((pli)->ListNode.Previous) )
++
++/********************************************************
++     GetPrevNode: This macro returns the Previous Structure in this list.
++                  This macro will reutrn NULL if no more structures are
++                  in the List.
++********************************************************/
++/*        %%e       */
++
++#endif
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1a130906eae02a01d8c70899ea9d4be4223867b1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,628 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: sgi_triang.c
++     File contains the routines that do the whole triangulation
++     of polygons.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include "global.h"
++#include "output.h"
++#include "polverts.h"
++#include "sturcts.h"
++#include "common.h"
++#include "util.h"
++#include "init.h"
++
++int Adjacent(int id2,int id1, int *list, int size)
++{
++      /*      Return the vertex that is adjacent to id1,
++              but is not id2, in the list of integers.
++      */
++
++      register int x=0;
++      
++      while (x < size)
++      {
++              if (*(list+x) == id1)
++              {
++                      if ((x != (size -1)) && (x != 0))
++                      {
++                              if ( *(list+x+1) != id2)
++                                      return *(list+x+1);
++                              else
++                                      return *(list+x-1);
++                      }
++                      else if (x == (size -1))
++                      {
++                              if (*(list) != id2)
++                                      return *(list);
++                              else
++                                      return *(list+x-1);
++                      }
++                      else
++                      {
++                              if (*(list+size-1) != id2)
++                                      return *(list+size-1);
++                              else
++                                      return *(list+x+1);
++                      }
++              }
++              x++;
++      }
++      /*   if there are degeneracies */
++     return id1;
++}
++
++
++void Rearrange_Index(int *index, int size)
++{
++      /*      If we are in the middle of a strip we must find the
++              edge to start on, which is the last edge that we had
++              transmitted.
++      */
++      int x,f,y,e1,e2,e3;
++      register int increment = 1;
++     int *temp;
++
++      /*      Find where the input edge is in the input list */
++      Last_Edge(&e1,&e2,&e3,0);
++      for (y = 0; y < size; y++)
++      {
++              if (*(index+y) == e2)
++              {
++                      if ((y != (size - 1)) && (*(index+y+1) == e3))
++                              break;
++                      else if ((y == (size - 1)) && (*(index) == e3))
++                              break;
++               else if ((y != 0) && (*(index+y-1) == e3))
++               {
++                    increment = -1;
++                    break;
++               }
++               else if ((y==0) && (*(index+size-1) == e3))
++               {
++                    increment = -1;
++                    break;
++               }
++              }
++              if (*(index+y) == e3)
++              {
++                      if ((y != (size - 1)) && (*(index+y+1) == e2))
++                              break;
++                      else if ((y == (size - 1)) && (*(index) == e2))
++                              break;
++            else if ((y != 0) && (*(index+y-1) == e2))
++            {
++                increment = -1;
++                break;
++            }
++            else if ((y==0) && (*(index+size-1) == e2))
++            {
++                increment = -1;
++                break;
++            }
++              }
++              /*      Edge is not here, we are at the beginning */
++              if ((y == (size-1)) && (increment != -1))
++                      return;
++      }
++      
++      /*      Now put the list into a new list, starting with the
++              input edge. Increment tells us whether we have to go 
++              forward or backward.
++      */
++      /*      Was in good position already */
++      if ((y == 0) && (increment == 1)) 
++              return;
++      
++     temp = (int *) malloc(sizeof(int) * size);
++     memcpy(temp,index,sizeof(int)*size);
++
++      if (increment == 1)
++      {
++              x=0;
++              for (f = y ; f< size; f++)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++              /*      Finish the rest of the list */  
++              for(f = 0; f < y ; f++)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++      }
++      else
++      {
++              x=0;
++              for (f = y ; f >= 0; f--)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++              /*      Finish the rest of the list */  
++              for(f = (size - 1); f > y ; f--)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++      }
++}
++
++void Delete_From_List(int id,int *list, int *size)
++{
++      /*      Delete the occurence of id in the list.
++              (list has size size)
++      */
++
++      int *temp;
++      register int x,y=0;
++
++      temp = (int *) malloc(sizeof(int) * (*size));
++      for (x=0; x<(*size); x++)
++      {
++              if (*(list+x) != id)
++              {
++                      *(temp+y) = *(list+x);
++                      y++;
++              }
++      }
++      *(temp+y) = -1;
++     *size = *size - (*size - y - 1);
++      memcpy(list,temp,sizeof(int)*(*size));
++}
++
++
++void Build_SGI_Table(int num_verts,int num_faces)
++{
++      /*      Build a table that has the polygons sorted by the
++              number of adjacent polygons.
++      */
++      int x,y,size,tally=0;
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++
++      /* For each face....*/
++      for (x=0;x < num_faces;x++)
++      {
++              pListHead = PolFaces[x];
++              temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++              /*   Check each edge of the face and tally the number of adjacent
++                      polygons to this face. 
++              */                      
++              if ( temp != NULL )
++              {
++                      /*      Size of the polygon */
++                      size = temp->nPolSize;
++                      if (size != 1)
++      {
++        for (y = 0; y< size; y++)
++                        {
++                                if (y != (size-1))
++                                        tally += Num_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1));
++                                else
++                                        tally += Num_Adj(*(temp->pPolygon),*(temp->pPolygon+(size-1)));
++        }
++                      
++                        /* Tally is the number of polygons that is adjacent to
++                                 the current polygon. 
++                        */
++                        /* Now put the face in the proper bucket depending on tally. */
++                        Add_Sgi_Adj(tally,x);
++                        temp = NULL;
++                        tally=0;
++      }
++              }
++      }
++}
++
++
++void Triangulate_Quad(int out_edge1,int out_edge2,int in_edge1,
++                                        int in_edge2,int size,int *index,
++                                        FILE *output,int reversed,int face_id,
++                      int where,int color1,int color2,int color3)
++{
++      int vertex4,vertex5;
++      
++      /*      This routine will nonblindly triangulate a quad, meaning
++              that there is a definite input and a definite output
++              edge that we must adhere to. Reversed will tell the orientation
++              of the input edge. (Reversed is -1 is we do not have an input
++              edge, in other words we are at the beginning of a strip.)
++              Out_edge* is the output edge, and in_edge* is the input edge. 
++              Index are the edges of the polygon
++              and size is the size of the polygon. Begin is whether we are
++              at the start of a new strip.
++      */
++      
++      /*      If we do not have an input edge, then we can make our input
++              edge whatever we like, therefore it will be easier to come
++              out on the output edge.
++      */
++      if (reversed == -1)
++      {
++              vertex4 = Adjacent(out_edge1,out_edge2,index,size);
++              vertex5 = Get_Other_Vertex(vertex4,out_edge1,out_edge2,index);
++              Output_Tri(vertex5,vertex4,out_edge1,output,color1,color2,color3,where);
++              Output_Tri(vertex4,out_edge1,out_edge2,output,color1,color2,color3,where);
++              return;
++      }
++      
++      /*      These are the 5 cases that we can have for the output edge */
++      
++      /*  Are they consecutive so that we form a triangle to
++              peel off, but cannot use the whole quad?
++      */
++
++      if (in_edge2 == out_edge1) 
++      {
++              /* Output the triangle that comes out the correct
++                       edge last. First output the triangle that comes out
++                       the wrong edge.
++              */
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge2,index);
++    Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where);
++    Output_Tri(vertex4,in_edge2,out_edge2,output,color1,color2,color3,where);
++              return;
++      }
++      /* The next case is where it is impossible to come out the
++               edge that we want. So we will have to start a new strip to
++               come out on that edge. We will output the one triangle
++               that we can, and then start the new strip with the triangle
++               that comes out on the edge that we want to come out on.
++      */
++      else if (in_edge1 == out_edge1)
++      {
++              /* We want to output the first triangle (whose output
++                       edge is not the one that we want.
++                       We have to find the vertex that we need, which is
++                       the other vertex which we do not have.
++              */
++              vertex4 = Get_Other_Vertex(in_edge2,in_edge1,out_edge2,index);
++              Output_Tri(in_edge2,in_edge1,vertex4,output,color1,color2,color3,where);
++              Output_Tri(vertex4,in_edge1,out_edge2,output,color1,color2,color3,where);
++              return;
++      }
++      
++      /*      Consecutive cases again, but with the output edge reversed */
++      else if (in_edge1 == out_edge2)
++      {
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
++              Output_Tri(in_edge2,in_edge1,vertex4,output,color1,color2,color3,where);
++              Output_Tri(vertex4,in_edge1,out_edge1,output,color1,color2,color3,where);
++              return;
++      }
++      else if (in_edge2 == out_edge2)
++      {
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
++              Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where);
++              Output_Tri(vertex4,in_edge2,out_edge1,output,color1,color2,color3,where);
++              return;
++      }
++
++      /*      The final case is where we want to come out the opposite
++              edge.
++      */
++      else
++      {
++    if( ((!reversed) && (out_edge1 == (Adjacent(in_edge1,in_edge2,index,size)))) ||
++        ((reversed) && (out_edge2 == (Adjacent(in_edge2,in_edge1,index,size)))))
++              {
++                /* We need to know the orientation of the input
++                               edge, so we know which way to put the diagonal.
++         And also the output edge, so that we triangulate
++         correctly.
++      */
++                      Output_Tri(in_edge1,in_edge2,out_edge2,output,color1,color2,color3,where);
++                      Output_Tri(in_edge2,out_edge2,out_edge1,output,color1,color2,color3,where);
++              }
++              else
++              {
++                      /* Input and output orientation was reversed, so diagonal will
++                               be reversed from above.
++                      */
++                      Output_Tri(in_edge1,in_edge2,out_edge1,output,color1,color2,color3,where);
++                      Output_Tri(in_edge2,out_edge1,out_edge2,output,color1,color2,color3,where);
++              }
++              return;
++      }
++}
++
++void Triangulate_Polygon(int out_edge1, int out_edge2, int in_edge1,
++                                         int in_edge2, int size, int *index,
++                                                           FILE *output, int reversed, int face_id,
++                         int where, int color1, int color2, int color3)
++{
++      /* We have a polygon that we need to nonblindly triangulate.
++               We will recursively try to triangulate it, until we are left
++               with a polygon of size 4, which can use the quad routine
++               from above. We will be taking off a triangle at a time
++               and outputting it. We will have 3 cases similar to the
++               cases for the quad above. The inputs to this routine
++               are the same as for the quad routine.
++      */
++
++      int vertex4;
++      int *temp;
++              
++      /* Since we are calling this recursively, we have to check whether
++               we are down to the case of the quad.
++      */
++      
++  if (size == 4)
++      {
++        Triangulate_Quad(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                              index,output,reversed,face_id,where,color1,color2,color3);
++              return;
++      }
++
++    
++      
++      /*      We do not have a specified input edge, and therefore we
++              can make it anything we like, as long as we still come out 
++              the output edge that we want.
++      */
++      if (reversed  == -1)
++      {
++              /*      Get the vertex for the last triangle, which is
++                      the one coming out the output edge, before we do
++                      any deletions to the list. We will be doing this
++                      bottom up.
++              */
++              vertex4 = Adjacent(out_edge1,out_edge2,index,size);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_List(out_edge2,index,&size);
++              Triangulate_Polygon(out_edge1,vertex4,in_edge2,
++                                               vertex4,size-1,index,output,reversed,face_id,where,color1,color2,color3);
++              memcpy(index,temp,sizeof(int)*size);
++              /*      Lastly do the triangle that comes out the output
++                      edge.
++              */
++              Output_Tri(vertex4,out_edge1,out_edge2,output,color1,color2,color3,where);
++              return;
++      }
++
++      /*      These are the 5 cases that we can have for the output edge */
++      
++      /*  Are they consecutive so that we form a triangle to
++              peel off that comes out the correct output edge, 
++              but we cannot use the whole polygon?
++      */
++      if (in_edge2 == out_edge1) 
++      {
++              /*      Output the triangle that comes out the correct
++                      edge last. First recursively do the rest of the
++                      polygon.
++              */
++              /*      Do the rest of the polygon without the triangle. 
++                      We will be doing a fan triangulation.
++              */
++              /*      Get the vertex adjacent to in_edge1, but is not
++                      in_edge2.
++              */
++              vertex4 = Adjacent(in_edge2,in_edge1,index,size);
++              Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where);
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++          Delete_From_List(in_edge1,index,&size);
++              Triangulate_Polygon(out_edge1,out_edge2,in_edge2,
++                                              vertex4,size-1,index,output,!reversed,face_id,where,color1,color2,color3);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++
++      /*      Next case is where it is again consecutive, but the triangle
++              formed by the consecutive edges do not come out of the
++              correct output edge. For this case, we can not do much to
++              keep it sequential. Try and do the fan.
++      */
++      else if (in_edge1 == out_edge1)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              vertex4 = Adjacent(in_edge1,in_edge2,index,size);
++              Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where);
++              /*      Since that triangle goes out of the polygon (the
++                      output edge of it), we can make our new input edge
++                      anything we like, so we will try to make it good for
++                      the strip. (This will be like starting a new strip,
++                      all so that we can go out the correct output edge.)
++              */
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_List(in_edge2,index,&size);
++              Triangulate_Polygon(out_edge1,out_edge2,in_edge1,
++                                              vertex4,size-1,index,output,reversed,face_id,where,color1,color2,color3);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++      /*      Consecutive cases again, but with the output edge reversed */
++      else if (in_edge1 == out_edge2)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              vertex4 = Adjacent(in_edge1,in_edge2,index,size);
++              Output_Tri(in_edge2,in_edge1,vertex4,output,color1,color2,color3,where);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_List(in_edge2,index,&size);
++          Triangulate_Polygon(out_edge1,out_edge2,in_edge1,
++                                              vertex4,size-1,index,output,reversed,face_id,where,color1,color2,color3);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++      else if (in_edge2 == out_edge2)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              vertex4 = Adjacent(in_edge2,in_edge1,index,size);
++              Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_List(in_edge1,index,&size);
++          Triangulate_Polygon(out_edge1,out_edge2,vertex4,
++                                              in_edge2,size-1,index,output,reversed,face_id,where,color1,color2,color3);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++
++      /*      Else the edge is not consecutive, and it is sufficiently
++              far away, for us not to make a conclusion at this time.
++              So we can take off a triangle and recursively call this
++              function.
++      */
++      else
++      {
++                      vertex4 = Adjacent(in_edge2,in_edge1,index,size);
++                      Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where);
++                      temp = (int *) malloc(sizeof(int) * size);
++                      memcpy(temp,index,sizeof(int)*size);
++                      Delete_From_List(in_edge1,index,&size);
++               Triangulate_Polygon(out_edge1,out_edge2,in_edge2,
++                                                   vertex4,size-1,index,output,!reversed,face_id,where,color1,color2,color3);
++                      memcpy(index,temp,sizeof(int)*size);
++                   return;
++      }
++}
++
++void Triangulate(int out_edge1,int out_edge2,int in_edge1,
++                               int in_edge2,int size,int *index,
++                               FILE *output,int reversed,int face_id, int where,
++                     int color1, int color2,int color3)
++{
++      /*      We have the info we need to triangulate a polygon */
++
++      if (size == 4)
++              Triangulate_Quad(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                  index,output,reversed,face_id,where,color1,color2,color3);
++      else
++              Triangulate_Polygon(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                     index,output,reversed,face_id,where,color1,color2,color3);
++}
++
++void Non_Blind_Triangulate(int size,int *index,
++                                        FILE *output,int next_face_id,int face_id,int where,
++                           int color1,int color2,int color3)
++{
++      int id1,id2,id3;
++      int nedge1,nedge2;
++      int reversed;
++      /*      We have a polygon that has to be triangulated and we cannot
++              do it blindly, ie we will try to come out on the edge that
++              has the least number of adjacencies
++      */
++
++      Last_Edge(&id1,&id2,&id3,0);
++      /*      Find the edge that is adjacent to the new face ,
++              also return whether the orientation is reversed in the
++              face of the input edge, which is id2 and id3.
++      */
++      if (next_face_id == -1)
++     {
++        printf("The face is -1 and the size is %d\n",size);
++        exit(0);
++     }
++    
++     reversed = Get_Edge(&nedge1,&nedge2,index,next_face_id,size,id2,id3);
++      /*      Do the triangulation */
++      
++      /*      If reversed is -1, the input edge is not in the polygon, therefore we can have the
++              input edge to be anything we like, since we are at the beginning
++              of a strip
++      */
++      Triangulate(nedge1,nedge2,id2,id3,size,index,output,reversed,
++                     face_id, where,color1,color2,color3);
++}
++
++
++
++void Blind_Triangulate(int size, int *index, FILE *output,
++                                 BOOL begin, int where ,int color1,int color2,
++                       int color3)
++{
++      /*      save sides in temp array, we need it so we know
++              about swaps.
++      */
++      int mode, decreasing,increasing,e1,e2,e3;
++
++      /*      Rearrange the index list so that the input edge is first
++      */
++      if (!begin)
++              Rearrange_Index(index,size);
++      
++      /*      We are given a polygon of more than 3 sides
++              and want to triangulate it. We will output the
++              triangles to the output file.
++      */
++      
++    /*        Find where the input edge is in the input list */
++      Last_Edge(&e1,&e2,&e3,0);
++     if (( (!begin) && (*(index) == e2) ) || (begin))
++     {
++          Output_Tri(*(index+0),*(index+1),*(index+size-1),output,color1,color2,color3,where);
++        /*    If we have a quad, (chances are yes), then we know that
++                   we can just add one diagonal and be done. (divide the
++                   quad into 2 triangles.
++        */
++        if (size == 4)
++        {
++                  Output_Tri(*(index+1),*(index+size-1),*(index+2),output,color1,color2,color3,where);
++              return;
++        }
++        increasing = 1;
++        mode = 1;
++
++    }
++    else if (!begin)
++    {
++        Output_Tri(*(index+1),*(index+0),*(index+size-1),output,color1,color2,color3,where);
++        if (size == 4)
++        {
++            Output_Tri(*(index+0),*(index+size-1),*(index+2),output,color1,color2,color3,where);
++            return;
++        }
++        Output_Tri(*(index+0),*(index+size-1),*(index+2),output,color1,color2,color3,where);
++        increasing = 2;
++        mode = 0;
++    }
++    if (size != 4)
++    {
++              /*      We do not have a quad, we have something bigger. */
++              decreasing = size - 1;          
++              do
++              {
++                      /*      Will be alternating diagonals, so we will be increasing
++                              and decreasing around the polygon.
++                      */
++                      if (mode)
++                      {
++                              Output_Tri(*(index+increasing),*(index+decreasing),*(index+increasing+1),output,color1,color2,color3,where);
++                              increasing++;
++                      }
++                      else
++                      {
++                              Output_Tri(*(index+decreasing),*(index+increasing),*(index+decreasing-1),output,color1,color2,color3,where);
++                    decreasing--;
++               }
++                      mode = !mode;
++              } while ((decreasing - increasing) >= 2);
++
++      }
++}
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9f153a1e88b446847312be4ed87d99ee5be85524
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,582 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: sgi_triangex.c
++     This file contains routines that are used for various functions in
++     the local algorithm.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include "global.h"
++#include "outputex.h"
++#include "polverts.h"
++#include "sturctsex.h"
++#include "common.h"
++#include "util.h"
++
++
++int AdjacentEx(int id2,int id1, int *list, int size)
++{
++      /*      Return the vertex that is adjacent to id1,
++              but is not id2, in the list of integers.
++      */
++
++      register int x=0;
++      
++      while (x < size)
++      {
++              if (*(list+x) == id1)
++              {
++                      if ((x != (size -1)) && (x != 0))
++                      {
++                              if ( *(list+x+1) != id2)
++                                      return *(list+x+1);
++                              else
++                                      return *(list+x-1);
++                      }
++                      else if (x == (size -1))
++                      {
++                              if (*(list) != id2)
++                                      return *(list);
++                              else
++                                      return *(list+x-1);
++                      }
++                      else
++                      {
++                              if (*(list+size-1) != id2)
++                                      return *(list+size-1);
++                              else
++                                      return *(list+x+1);
++                      }
++              }
++              x++;
++      }
++      printf("Error in the list\n");
++      exit(0);
++}
++
++
++void Delete_From_ListEx(int id,int *list, int size)
++{
++      /*      Delete the occurence of id in the list.
++              (list has size size)
++      */
++
++      int *temp;
++      register int x,y=0;
++
++      temp = (int *) malloc(sizeof(int) * size);
++      for (x=0; x<size; x++)
++      {
++              if (*(list+x) != id)
++              {
++                      *(temp+y) = *(list+x);
++                      y++;
++              }
++      }
++      if(y != (size-1))
++      {
++              printf("There is an error in the delete\n");
++              exit(0);
++      }
++      *(temp+size-1) = -1;
++      memcpy(list,temp,sizeof(int)*size);
++
++}
++
++
++void Triangulate_QuadEx(int out_edge1,int out_edge2,int in_edge1,
++                                        int in_edge2,int size,int *index,
++                                        FILE *output,FILE *fp,int reversed,int face_id,
++                      int where)
++{
++      int vertex4,vertex5;
++      
++      /*      This routine will nonblindly triangulate a quad, meaning
++              that there is a definite input and a definite output
++              edge that we must adhere to. Reversed will tell the orientation
++              of the input edge. (Reversed is -1 is we do not have an input
++              edge, in other words we are at the beginning of a strip.)
++              Out_edge* is the output edge, and in_edge* is the input edge. 
++              Index are the edges of the polygon
++              and size is the size of the polygon. Begin is whether we are
++              at the start of a new strip.
++      */
++      
++      /*      If we do not have an input edge, then we can make our input
++              edge whatever we like, therefore it will be easier to come
++              out on the output edge.
++      */
++      if (reversed == -1)
++      {
++              vertex4 = AdjacentEx(out_edge1,out_edge2,index,size);
++              vertex5 = Get_Other_Vertex(vertex4,out_edge1,out_edge2,index);
++              Output_TriEx(vertex5,vertex4,out_edge1,output,-1,-1,where);
++              Output_TriEx(vertex4,out_edge1,out_edge2,output,-1,-1,where);
++              return;
++      }
++      
++      /*      These are the 5 cases that we can have for the output edge */
++      
++      /*   Are they consecutive so that we form a triangle to
++              peel off, but cannot use the whole quad?
++      */
++
++      if (in_edge2 == out_edge1) 
++      {
++              /*      Output the triangle that comes out the correct
++                      edge last. First output the triangle that comes out
++                      the wrong edge.
++              */
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge2,index);
++          Output_TriEx(in_edge1,in_edge2,vertex4,output,-1,-1,where);
++          Output_TriEx(vertex4,in_edge2,out_edge2,output,-1,-1,where);
++              return;
++      }
++      /*      The next case is where it is impossible to come out the
++              edge that we want. So we will have to start a new strip to
++              come out on that edge. We will output the one triangle
++              that we can, and then start the new strip with the triangle
++              that comes out on the edge that we want to come out on.
++      */
++      else if (in_edge1 == out_edge1)
++      {
++              /*      We want to output the first triangle (whose output
++                      edge is not the one that we want.
++                      We have to find the vertex that we need, which is
++                      the other vertex which we do not have.
++              */
++              vertex4 = Get_Other_Vertex(in_edge2,in_edge1,out_edge2,index);
++              Output_TriEx(in_edge2,in_edge1,vertex4,output,-1,-1,where);
++              Output_TriEx(vertex4,in_edge1,out_edge2,output,-1,-1,where);
++              return;
++      }
++      
++      /*      Consecutive cases again, but with the output edge reversed */
++      else if (in_edge1 == out_edge2)
++      {
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
++              Output_TriEx(in_edge2,in_edge1,vertex4,output,-1,-1,where);
++              Output_TriEx(vertex4,in_edge1,out_edge1,output,-1,-1,where);
++              return;
++      }
++      else if (in_edge2 == out_edge2)
++      {
++              vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
++              Output_TriEx(in_edge1,in_edge2,vertex4,output,-1,-1,where);
++              Output_TriEx(vertex4,in_edge2,out_edge1,output,-1,-1,where);
++              return;
++      }
++
++      /*      The final case is where we want to come out the opposite edge.*/
++      else
++      {
++           if( ((!reversed) && (out_edge1 == (AdjacentEx(in_edge1,in_edge2,index,size)))) ||
++                    ((reversed) && (out_edge2 == (AdjacentEx(in_edge2,in_edge1,index,size)))))
++               {
++                      /*      We need to know the orientation of the input
++                              edge, so we know which way to put the diagonal.
++                    And also the output edge, so that we triangulate correctly.
++               */
++                      Output_TriEx(in_edge1,in_edge2,out_edge2,output,-1,-1,where);
++                      Output_TriEx(in_edge2,out_edge2,out_edge1,output,-1,-1,where);
++               }
++              else
++              {
++                      /*   Input and output orientation was reversed, so diagonal will
++                              be reversed from above.
++                      */
++                      Output_TriEx(in_edge1,in_edge2,out_edge1,output,-1,-1,where);
++                      Output_TriEx(in_edge2,out_edge1,out_edge2,output,-1,-1,where);
++              }
++              return;
++      }
++}
++
++void Triangulate_PolygonEx(int out_edge1,int out_edge2,int in_edge1,
++                                        int in_edge2,int size,int *index,
++                                        FILE *output,FILE *fp,int reversed,int face_id,
++                           int where)
++{
++      /*      We have a polygon that we need to nonblindly triangulate.
++              We will recursively try to triangulate it, until we are left
++              with a polygon of size 4, which can use the quad routine
++              from above. We will be taking off a triangle at a time
++              and outputting it. We will have 3 cases similar to the
++              cases for the quad above. The inputs to this routine
++              are the same as for the quad routine.
++      */
++
++      int vertex4;
++      int *temp;
++
++              
++      /*      Since we are calling this recursively, we have to check whether
++              we are down to the case of the quad.
++      */
++      
++    if (size == 4)
++      {
++              Triangulate_QuadEx(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                          index,output,fp,reversed,face_id,where);
++              return;
++      }
++
++    
++      
++      /*      We do not have a specified input edge, and therefore we
++              can make it anything we like, as long as we still come out 
++              the output edge that we want.
++      */
++      if (reversed  == -1)
++      {
++              /*      Get the vertex for the last triangle, which is
++                      the one coming out the output edge, before we do
++                      any deletions to the list. We will be doing this
++                      bottom up.
++              */
++              vertex4 = AdjacentEx(out_edge1,out_edge2,index,size);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_ListEx(out_edge2,index,size);
++              Triangulate_PolygonEx(out_edge1,vertex4,in_edge2,
++                                                vertex4,size-1,index,output,fp,reversed,face_id,where);
++              memcpy(index,temp,sizeof(int)*size);
++              /*      Lastly do the triangle that comes out the output
++                      edge.
++              */
++              Output_TriEx(vertex4,out_edge1,out_edge2,output,-1,-1,where);
++              return;
++      }
++
++      /*      These are the 5 cases that we can have for the output edge */
++      
++      /*  Are they consecutive so that we form a triangle to
++              peel off that comes out the correct output edge, 
++              but we cannot use the whole polygon?
++      */
++      if (in_edge2 == out_edge1) 
++      {
++              /*      Output the triangle that comes out the correct
++                      edge last. First recursively do the rest of the
++                      polygon.
++              */
++              /*      Do the rest of the polygon without the triangle. 
++                      We will be doing a fan triangulation.
++              */
++              /*      Get the vertex adjacent to in_edge1, but is not
++                      in_edge2.
++              */
++              vertex4 = AdjacentEx(in_edge2,in_edge1,index,size);
++              Output_TriEx(in_edge1,in_edge2,vertex4,output,-1,-1,where);
++              /*      Create a new edgelist without the triangle that
++                      was just outputted.
++              */
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++          Delete_From_ListEx(in_edge1,index,size);
++              Triangulate_PolygonEx(out_edge1,out_edge2,in_edge2,
++                                                vertex4,size-1,index,output,fp,!reversed,face_id,where);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++
++      /*      Next case is where it is again consecutive, but the triangle
++              formed by the consecutive edges do not come out of the
++              correct output edge. For this case, we can not do much to
++              keep it sequential. Try and do the fan.
++      */
++      else if (in_edge1 == out_edge1)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              vertex4 = AdjacentEx(in_edge1,in_edge2,index,size);
++              Output_TriEx(in_edge1,in_edge2,vertex4,fp,-1,-1,where);
++              /*      Since that triangle goes out of the polygon (the
++                      output edge of it), we can make our new input edge
++                      anything we like, so we will try to make it good for
++                      the strip. (This will be like starting a new strip,
++                      all so that we can go out the correct output edge.)
++              */
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_ListEx(in_edge2,index,size);
++              Triangulate_PolygonEx(out_edge1,out_edge2,in_edge1,
++                                                vertex4,size-1,index,output,fp,reversed,face_id,where);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++      /*      Consecutive cases again, but with the output edge reversed */
++      else if (in_edge1 == out_edge2)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              vertex4 = AdjacentEx(in_edge1,in_edge2,index,size);
++              Output_TriEx(in_edge2,in_edge1,vertex4,fp,-1,-1,where);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_ListEx(in_edge2,index,size);
++          Triangulate_PolygonEx(out_edge1,out_edge2,in_edge1,
++                                     vertex4,size-1,index,output,fp,reversed,face_id,where);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++      else if (in_edge2 == out_edge2)
++      {
++              /*      Get vertex adjacent to in_edge2, but is not in_edge1 */
++              vertex4 = AdjacentEx(in_edge2,in_edge1,index,size);
++              Output_TriEx(in_edge1,in_edge2,vertex4,fp,-1,-1,where);
++              temp = (int *) malloc(sizeof(int) * size);
++              memcpy(temp,index,sizeof(int)*size);
++              Delete_From_ListEx(in_edge1,index,size);
++          Triangulate_PolygonEx(out_edge1,out_edge2,vertex4,
++                                                in_edge2,size-1,index,output,fp,reversed,face_id,where);
++              memcpy(index,temp,sizeof(int)*size);
++              return;
++      }
++
++      /*      Else the edge is not consecutive, and it is sufficiently
++              far away, for us not to make a conclusion at this time.
++              So we can take off a triangle and recursively call this
++              function.
++      */
++      else
++      {
++                      vertex4 = AdjacentEx(in_edge2,in_edge1,index,size);
++                      Output_TriEx(in_edge1,in_edge2,vertex4,fp,-1,-1,where);
++                      temp = (int *) malloc(sizeof(int) * size);
++                      memcpy(temp,index,sizeof(int)*size);
++                      Delete_From_ListEx(in_edge1,index,size);
++               Triangulate_PolygonEx(out_edge1,out_edge2,in_edge2,
++                                                     vertex4,size-1,index,output,fp,!reversed,face_id,where);
++                      memcpy(index,temp,sizeof(int)*size);
++                   return;
++      }
++}
++
++void TriangulateEx(int out_edge1,int out_edge2,int in_edge1,
++                               int in_edge2,int size,int *index,
++                               FILE *fp,FILE *output,int reversed,int face_id, int where)
++{
++      /*      We have the info we need to triangulate a polygon */
++
++      if (size == 4)
++              Triangulate_QuadEx(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                    index,fp,output,reversed,face_id,where);
++      else
++              Triangulate_PolygonEx(out_edge1,out_edge2,in_edge1,in_edge2,size,
++                                       index,fp,output,reversed,face_id,where);
++}
++
++void Non_Blind_TriangulateEx(int size,int *index, FILE *fp,
++                                               FILE *output,int next_face_id,int face_id,int where)
++{
++      int id1,id2,id3;
++      int nedge1,nedge2;
++      int reversed;
++      /*      We have a polygon that has to be triangulated and we cannot
++              do it blindly, ie we will try to come out on the edge that
++              has the least number of adjacencies
++      */
++
++      Last_Edge(&id1,&id2,&id3,0);
++      /*      Find the edge that is adjacent to the new face ,
++              also return whether the orientation is reversed in the
++              face of the input edge, which is id2 and id3.
++      */
++      if (next_face_id == -1)
++    {
++        printf("The face is -1 and the size is %d\n",size);
++        exit(0);
++    }
++    
++    reversed = Get_EdgeEx(&nedge1,&nedge2,index,next_face_id,size,id2,id3);
++      /*      Do the triangulation */
++      
++      /*      If reversed is -1, the input edge is not in the polygon, therefore we can have the
++              input edge to be anything we like, since we are at the beginning
++              of a strip
++      */
++      TriangulateEx(nedge1,nedge2,id2,id3,size,index,fp,output,reversed,
++                       face_id, where);
++}
++
++void Rearrange_IndexEx(int *index, int size)
++{
++      /*      If we are in the middle of a strip we must find the
++              edge to start on, which is the last edge that we had
++              transmitted.
++      */
++      int x,f,y,e1,e2,e3;
++      int increment = 1;
++     int *temp;
++
++      /*      Find where the input edge is in the input list */
++      Last_Edge(&e1,&e2,&e3,0);
++      for (y = 0; y < size; y++)
++      {
++              if (*(index+y) == e2)
++              {
++                      if ((y != (size - 1)) && (*(index+y+1) == e3))
++                              break;
++                      else if ((y == (size - 1)) && (*(index) == e3))
++                              break;
++               else if ((y != 0) && (*(index+y-1) == e3))
++               {
++                   increment = -1;
++                   break;
++               }
++               else if ((y==0) && (*(index+size-1) == e3))
++               {
++                   increment = -1;
++                   break;
++               }
++              }
++              if (*(index+y) == e3)
++              {
++                      if ((y != (size - 1)) && (*(index+y+1) == e2))
++                              break;
++                      else if ((y == (size - 1)) && (*(index) == e2))
++                              break;
++               else if ((y != 0) && (*(index+y-1) == e2))
++               {
++                   increment = -1;
++                   break;
++               }
++               else if ((y==0) && (*(index+size-1) == e2))
++               {
++                   increment = -1;
++                   break;
++               }
++              }
++              /*      Edge is not here, we are at the beginning */
++              if ((y == (size-1)) && (increment != -1))
++                      return;
++      }
++      
++      /*      Now put the list into a new list, starting with the
++              input edge. Increment tells us whether we have to go 
++              forward or backward.
++      */
++      /*      Was in good position already */
++      if ((y == 0) && (increment == 1)) 
++              return;
++      
++                  
++    temp = (int *) malloc(sizeof(int) * size);
++    memcpy(temp,index,sizeof(int)*size);
++
++      if (increment == 1)
++      {
++              x=0;
++              for (f = y ; f< size; f++)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++              /*      Finish the rest of the list */  
++              for(f = 0; f < y ; f++)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++      }
++      else
++      {
++              x=0;
++              for (f = y ; f >= 0; f--)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++              /*      Finish the rest of the list */  
++              for(f = (size - 1); f > y ; f--)
++              {
++                      *(index+x) = *(temp+f);
++                      x++;
++              }
++      }
++}
++
++void Blind_TriangulateEx(int size, int *index, FILE *fp,
++                                               FILE *output, BOOL begin, int where )
++{
++      /*      save sides in temp array, we need it so we know
++              about swaps.
++      */
++      int mode, decreasing,increasing,e1,e2,e3;
++
++      /*      Rearrange the index list so that the input edge is first
++      */
++      if (!begin)
++              Rearrange_IndexEx(index,size);
++      
++      /*      We are given a polygon of more than 3 sides
++              and want to triangulate it. We will output the
++              triangles to the output file.
++      */
++      
++    /*        Find where the input edge is in the input list */
++      Last_Edge(&e1,&e2,&e3,0);
++     if (( (!begin) && (*(index) == e2) ) || (begin))
++     {
++          Output_TriEx(*(index+0),*(index+1),*(index+size-1),fp,-1,-1,where);
++        /*    If we have a quad, (chances are yes), then we know that
++              we can just add one diagonal and be done. (divide the
++              quad into 2 triangles.
++        */
++        if (size == 4)
++        {
++                  Output_TriEx(*(index+1),*(index+size-1),*(index+2),fp,-1,-1,where);
++              return;
++        }
++        increasing = 1;
++        mode = 1;
++
++    }
++    else if (!begin)
++    {
++        Output_TriEx(*(index+1),*(index+0),*(index+size-1),fp,-1,-1,where);
++        if (size == 4)
++        {
++            Output_TriEx(*(index+0),*(index+size-1),*(index+2),fp,-1,-1,where);
++            return;
++        }
++        Output_TriEx(*(index+0),*(index+size-1),*(index+2),fp,-1,-1,where);
++        increasing = 2;
++        mode = 0;
++    }
++      if (size != 4)
++      {
++              /*      We do not have a quad, we have something bigger. */
++              decreasing = size - 1;
++              
++              do
++              {
++                      /*      Will be alternating diagonals, so we will be increasing
++                              and decreasing around the polygon.
++                      */
++                      if (mode)
++                      {
++                              Output_TriEx(*(index+increasing),*(index+decreasing),*(index+increasing+1),fp,-1,-1,where);
++                              increasing++;
++                      }
++                      else
++                      {
++                              Output_TriEx(*(index+decreasing),*(index+increasing),*(index+decreasing-1),fp,-1,-1,where);
++                    decreasing--;
++               }
++                      mode = !mode;
++              } while ((decreasing - increasing) >= 2);
++
++      }
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7010012b7692ab307eaa51c723846361ccd0ae5d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,549 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: struct.c
++     Contains routines that update structures, and micellaneous routines.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdlib.h>
++#include <string.h>
++#include "polverts.h"
++#include "ties.h"
++#include "output.h"
++#include "triangulate.h"
++#include "sturcts.h"
++#include "options.h"
++#include "common.h"
++#include "util.h"
++
++int out1 = -1;
++int out2 = -1;
++
++int Get_Edge(int *edge1,int *edge2,int *index,int face_id,
++              int size, int id1, int id2)
++{
++      /*      Put the edge that is adjacent to face_id into edge1
++              and edge2. For each edge see if it is adjacent to
++              face_id. Id1 and id2 is the input edge, so see if 
++              the orientation is reversed, and save it in reversed.
++      */
++      register int x;
++      int reversed = -1;
++      BOOL set = FALSE;
++    
++     for (x=0; x< size; x++)
++      {
++              if (x == (size-1))
++              {
++                      if ((*(index) == id1) && (*(index+size-1)==id2))
++                      {
++                              if (set)
++                         return 1;
++                              reversed = 1;
++                      }
++                      else if ((*(index) == id2) && (*(index+size-1)==id1))
++                      {
++                              if (set)
++                         return 0;
++                              reversed = 0;
++                      }
++                              
++                      if (Look_Up(*(index),*(index+size-1),face_id))
++                      {
++                              if ( (out1 != -1) && ( (out1 == *(index)) || (out1 == *(index+size-1)) ) &&
++                       ( (out2 == *(index)) || (out2 == *(index+size-1)) ))
++                    {
++                         set = TRUE;
++                         *edge1 = *(index);
++                         *edge2 = *(index+size-1);
++                    }
++                              else if (out1 == -1)
++                    {
++                         set = TRUE;
++                         *edge1 = *(index);
++                         *edge2 = *(index+size-1);
++                    }
++                              if ((reversed != -1) && (set))  
++                                      return reversed;
++                      }
++              }               
++              else
++              {
++                      if ((*(index+x) == id1) && (*(index+x+1)==id2))
++                      {
++                              if (set)
++                         return 0;
++                              reversed = 0;
++                      }
++                      else if ((*(index+x) == id2) && (*(index+x+1)==id1))
++                      {
++                              if (set)
++                                      return 1;
++                              reversed = 1;
++                      }
++
++                      if (Look_Up(*(index+x),*(index+x+1),face_id))
++                      {
++                              if ( (out1 != -1) && ( (out1 == *(index+x)) || (out1 == *(index+x+1)) ) &&
++                         ((out2 == *(index+x)) || (out2 == *(index+x+1))))
++                    {
++                         set = TRUE;
++                         *edge1 = *(index+x);
++                         *edge2 = *(index+x+1);
++                    }
++                              else if (out1 == -1)
++                    {
++                         set = TRUE;
++                         *edge1 = *(index+x);
++                                   *edge2 = *(index+x + 1);
++                    }
++                              if ((reversed != -1) && (set))
++                         return reversed;
++                      }
++              }
++      }                       
++      if ((x == size) && (reversed != -1))
++      {
++              /*      Could not find the output edge */
++              printf("Error in the Lookup %d %d %d %d %d %d %d %d\n",face_id,id1,id2,reversed,*edge1,*edge2,out1,out2);
++              exit(0);
++      }
++      return reversed;
++}
++
++
++void Update_Face(int *next_bucket, int *min_face, int face_id, int *e1,
++                               int *e2,int temp1,int temp2,int *ties)
++{
++      /*      We have a face id that needs to be decremented.
++              We have to determine where it is in the structure,
++              so that we can decrement it.
++      */
++      /*      The number of adjacencies may have changed, so to locate
++              it may be a little tricky. However we know that the number
++              of adjacencies is less than or equal to the original number
++              of adjacencies,
++      */
++      int y,size;
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++      PLISTINFO lpListInfo;
++      static int each_poly = 0;
++      BOOL there = FALSE;
++
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      /*      Check each edge of the face and tally the number of adjacent
++              polygons to this face. 
++      */                      
++      if ( temp != NULL )
++      {
++              /*      Size of the polygon */
++        size = temp->nPolSize;
++        /*  We did it already */
++        if (size == 1)
++            return;
++        for (y = 0; y< size; y++)
++         {
++                      /*      If we are doing partial triangulation, we must check
++                              to see whether the edge is still there in the polygon,
++                              since we might have done a portion of the polygon
++                              and saved the rest for later.
++                      */
++            if (y != (size-1))
++                {
++                              if( ((temp1 == *(temp->pPolygon+y)) && (temp2 ==*(temp->pPolygon+y+1)))
++                                      || ((temp2 == *(temp->pPolygon+y)) && (temp1 ==*(temp->pPolygon+y+1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                }
++                else
++                {
++                              if( ((temp1 == *(temp->pPolygon)) && (temp2 == *(temp->pPolygon+size-1)))
++                                      || ((temp2 == *(temp->pPolygon)) && (temp1 ==*(temp->pPolygon+size-1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                }
++       }
++              
++      if (!there)
++              /*      Original edge was already used, we cannot use this polygon */
++                      return;
++              
++      /*      We have a starting point to start our search to locate
++              this polygon. 
++      */
++
++      /*      Check to see if this polygon was done */
++      lpListInfo = Done(face_id,59,&y);
++
++      if (lpListInfo == NULL)
++              return;
++
++     /*  Was not done, but there is an error in the adjacency calculations */
++     if (y == 0)
++     {
++            printf("There is an error in finding the adjacencies\n");
++            exit(0);
++     }
++
++     /*       Now put the face in the proper bucket depending on tally. */
++      /*      First add it to the new bucket, then remove it from the old */
++      Add_Sgi_Adj(y-1,face_id);
++      RemoveList(array[y],lpListInfo);
++        
++     /*       Save it if it was the smallest seen so far since then
++              it will be the next face 
++              Here we will have different options depending on
++              what we want for resolving ties:
++                      1) First one we see we will use
++                      2) Random resolving
++                      3) Look ahead
++                      4) Alternating direction
++      */
++      /*      At a new strip */
++      if (*next_bucket == 60)
++              *ties = *ties + each_poly;
++      /*      Have a tie */
++      if (*next_bucket == (y-1))
++      {
++              Add_Ties(face_id);
++              each_poly++;
++      }
++      /*      At a new minimum */
++      if (*next_bucket > (y-1))
++      {
++              *next_bucket = y-1;
++              *min_face = face_id;
++              *e1 = temp1;
++              *e2 = temp2;
++              each_poly = 0;
++              Clear_Ties();
++              Add_Ties(face_id);
++      }
++     }
++}
++
++
++void Delete_Adj(int id1, int id2,int *next_bucket,int *min_face, 
++                       int current_face,int *e1,int *e2,int *ties)
++{
++      /*      Find the face that is adjacent to the edge and is not the
++              current face. Delete one adjacency from it. Save the min
++              adjacency seen so far.
++      */
++      register int count=0;
++      PF_EDGES temp = NULL;
++      ListHead *pListHead;
++      int next_face;
++
++      /*      Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++      /*      It could be a new edge that we created. So we can
++              exit, since there is not a face adjacent to it.
++      */
++              return;
++      while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          if (temp == NULL)
++                      /*      Was a new edge that was created and therefore
++                              does not have anything adjacent to it
++                      */
++                      return;
++     }
++      /*      Was not adjacent to anything else except itself */
++      if (temp->edge[2] == -1)
++              return;
++
++      /*      Was adjacent to something */
++      else
++      {
++              if (temp->edge[2] == current_face)
++                      next_face =  temp->edge[1];
++              else 
++                      next_face = temp->edge[2];
++      }
++      /*      We have the other face adjacent to this edge, it is 
++              next_face. Now we need to decrement this faces' adjacencies.
++      */
++      Update_Face(next_bucket, min_face, next_face,e1,e2,id1,id2,ties);
++}
++
++
++int Change_Face(int face_id,int in1,int in2,
++                               ListHead *pListHead, P_ADJACENCIES temp, BOOL no_check)
++{
++      /*      We are doing a partial triangulation and we need to
++              put the new face of triangle into the correct bucket
++      */
++      int input_adj,y;
++      
++      /*      Find the old number of adjacencies to this face,
++              so we know where to delete it from
++      */
++      y = Old_Adj(face_id);
++      
++      /*      Do we need to change the adjacency? Maybe the edge on the triangle
++              that was outputted was not adjacent to anything. We know if we
++              have to check by "check". We came out on the output edge
++              that we needed, then we know that the adjacencies will decrease
++              by exactly one.
++      */
++      if (!no_check)
++      {
++              input_adj = Number_Adj(in1,in2,face_id);
++              /*      If there weren't any then don't do anything */
++              if (input_adj == 0)
++                      return y;
++      }
++
++      RemoveList(pListHead,(PLISTINFO)temp);
++      /*      Before we had a quad with y adjacencies. The in edge
++              did not have an adjacency, since it was just deleted,
++              since we came in on it. The outedge must have an adjacency
++              otherwise we would have a bucket 0, and would not be in this
++              routine. Therefore the new adjacency must be y-1
++      */
++    
++    Add_Sgi_Adj(y-1,face_id);
++    return (y-1);
++}
++
++int Update_Adjacencies(int face_id, int *next_bucket, int *e1, int *e2,
++                                         int *ties)
++{
++      /*      Give the face with id face_id, we want to decrement
++              all the faces that are adjacent to it, since we will
++              be deleting face_id from the data structure.
++              We will return the face that has the least number
++              of adjacencies.
++      */
++      PF_FACES temp = NULL;
++      ListHead *pListHead;
++      int size,y,min_face = -1;
++      
++     *next_bucket = 60;
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      
++      if ( temp == NULL )
++      {
++              printf("The face was already deleted, there is an error\n");
++              exit(0);
++      }
++      
++      /*      Size of the polygon */
++      size = temp->nPolSize;
++      for (y = 0; y< size; y++)
++      {
++              if (y != (size-1))
++                      Delete_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),
++                              next_bucket,&min_face,face_id,e1,e2,ties);
++              else
++                      Delete_Adj(*(temp->pPolygon),*(temp->pPolygon+(size-1)),
++                              next_bucket,&min_face,face_id,e1,e2,ties);
++      }
++      return (min_face);
++}
++
++
++void Find_Adj_Tally(int id1, int id2,int *next_bucket,int *min_face, 
++                              int current_face,int *ties)
++{
++      /*      Find the face that is adjacent to the edge and is not the
++              current face. Save the min adjacency seen so far.
++      */
++      int size,each_poly=0,y,count=0;
++      PF_EDGES temp = NULL;
++      PF_FACES temp2 = NULL;
++      ListHead *pListHead;
++      int next_face;
++      BOOL there = FALSE;
++
++    
++    /*        Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++     /*       This was a new edge that was created, so it is
++              adjacent to nothing.
++      */
++              return;
++
++      while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          if (temp == NULL)
++                      /*      This was a new edge that we created */
++                      return;
++     }
++      /*      Was not adjacent to anything else except itself */
++      if (temp->edge[2] == -1)
++              return;
++      else
++      {
++              if (temp->edge[2] == current_face)
++                      next_face =  temp->edge[1];
++              else 
++                      next_face = temp->edge[2];
++      }
++      /*      We have the other face adjacent to this edge, it is 
++              next_face. Find how many faces it is adjacent to.
++      */
++      pListHead = PolFaces[next_face];
++      temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      /*      Check each edge of the face and tally the number of adjacent 
++              polygons to this face. This will be the original number of
++              polygons adjacent to this polygon, we must then see if this
++              number has been decremented
++      */                      
++      if ( temp2 != NULL )
++      {
++              /*      Size of the polygon */
++              size = temp2->nPolSize;
++              /*  We did it already */
++          if (size == 1)
++            return;
++          for (y = 0; y< size; y++)
++              {
++                      /*      Make sure that the edge is still in the
++                              polygon and was not deleted, because if the edge was
++                              deleted, then we used it already.
++                      */
++                      if (y != (size-1))
++                      {
++                              if( ((id1 == *(temp2->pPolygon+y)) && (id2 ==*(temp2->pPolygon+y+1)))
++                                      || ((id2 == *(temp2->pPolygon+y)) && (id1 ==*(temp2->pPolygon+y+1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++                      else
++                      {               
++                              if( ((id1 == *(temp2->pPolygon)) && (id2 ==*(temp2->pPolygon+size-1)))
++                                      || ((id2 == *(temp2->pPolygon)) && (id1 ==*(temp2->pPolygon+size-1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++              }
++              
++              if (!there)
++                      /*      Edge already used and deleted from the polygon*/
++                      return;
++              
++              /*      See if the face was already deleted, and where
++                      it is if it was not
++              */
++              if (Done(next_face,size,&y) == NULL)
++                      return;
++              
++              /*      Save it if it was the smallest seen so far since then
++                      it will be the next face 
++                      Here we will have different options depending on
++                      what we want for resolving ties:
++                      1) First one we see we will use
++                      2) Random resolving
++                      3) Look ahead
++                      4) Alternating direction
++              */
++              
++              /*      At a new strip */
++              if (*next_bucket == 60)
++                      *ties = *ties + each_poly;
++              /*      Have a tie */
++              if (*next_bucket == (y-1))
++              {
++                      Add_Ties(next_face);
++                      each_poly++;
++              }
++              /*      At a new minimum */
++              if (*next_bucket > (y-1))
++              {
++                      *next_bucket = y-1;
++                      *min_face = next_face;
++                      each_poly = 0;
++                      Clear_Ties();
++                      Add_Ties(next_face);
++              }
++      }
++}
++
++
++int Min_Face_Adj(int face_id, int *next_bucket, int *ties)
++{
++      /*      Used for the Partial triangulation to find the next
++              face. It will return the minimum adjacency face id
++              found at this face.
++      */
++      PF_FACES temp = NULL;
++      ListHead *pListHead;
++      int size,y,min_face,test_face;
++      
++      *next_bucket = 60;
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      
++      if ( temp == NULL )
++      {
++              printf("The face was already deleted, there is an error\n");
++              exit(0);
++      }
++      
++      /*      Size of the polygon */
++      size = temp->nPolSize;
++      for (y = 0; y< size; y++)
++      {
++              if (y != (size-1))
++                      Find_Adj_Tally(*(temp->pPolygon+y),*(temp->pPolygon+y+1),
++                              next_bucket,&min_face,face_id,ties);
++              else
++                      Find_Adj_Tally(*(temp->pPolygon),*(temp->pPolygon+(size-1)),
++                              next_bucket,&min_face,face_id,ties);
++      }
++      /*    Maybe we can do better by triangulating the face, because
++          by triangulating the face we will go to a polygon of lesser
++          adjacencies
++    */
++    if (size == 4)
++    {
++         /*    Checking for a quad whether to do the whole polygon will
++               result in better performance because the triangles in the polygon
++               have less adjacencies
++         */
++         Check_In_Quad(face_id,&test_face);
++         if (*next_bucket > test_face)
++              /*    We can do better by going through the polygon */
++              min_face = face_id;
++    }
++
++    /*  We have a polygon with greater than 4 sides, check to see if going
++        inside is better than going outside the polygon for the output edge.
++    */
++    else
++    {
++        Check_In_Polygon(face_id,&test_face,size);
++        if (*next_bucket > test_face)
++            /*  We can do better by going through the polygon */
++            min_face = face_id;
++    }
++    
++    return (min_face);
++}
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..70359ddc0784de23ce433edf4e545dd314a093d9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,553 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: structex.c
++     This file contains routines that are used for various functions in
++     the local algorithm.
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdlib.h>
++#include <string.h>
++#include "polverts.h"
++#include "ties.h"
++#include "outputex.h"
++#include "triangulatex.h"
++#include "sturctsex.h"
++#include "options.h"
++#include "common.h"
++#include "util.h"
++
++int out1Ex = -1;
++int out2Ex = -1;
++
++int Get_EdgeEx(int *edge1,int *edge2,int *index,int face_id,
++                      int size, int id1, int id2)
++{
++      /*      Put the edge that is adjacent to face_id into edge1
++              and edge2. For each edge see if it is adjacent to
++              face_id. Id1 and id2 is the input edge, so see if 
++              the orientation is reversed, and save it in reversed.
++      */
++      int x;
++      int reversed = -1;
++      BOOL set = FALSE;
++
++     for (x=0; x< size; x++)
++      {
++              if (x == (size-1))
++              {
++                      if ((*(index) == id1) && (*(index+size-1)==id2))
++                      {
++                              if (set)
++                         return 1;
++                              reversed = 1;
++                      }
++                      else if ((*(index) == id2) && (*(index+size-1)==id1))
++                      {
++                              if (set)
++                         return 0;
++                              reversed = 0;
++                      }
++                              
++                      if (Look_Up(*(index),*(index+size-1),face_id))
++                      {
++                              if ( (out1Ex != -1) && ( (out1Ex == *(index)) || (out1Ex == *(index+size-1)) ) &&
++                       ( (out2Ex == *(index)) || (out2Ex == *(index+size-1)) ))
++                    {
++                         set = TRUE;
++                         *edge1 = *(index);
++                         *edge2 = *(index+size-1);
++                    }
++                              else if (out1Ex == -1)
++                    {
++                         set = TRUE;
++                         *edge1 = *(index);
++                         *edge2 = *(index+size-1);
++                    }
++                              if ((reversed != -1) && (set))  
++                                      return reversed;
++                      }
++              }               
++              else
++              {
++                      if ((*(index+x) == id1) && (*(index+x+1)==id2))
++                      {
++                              if (set)
++                         return 0;
++                              reversed = 0;
++                      }
++                      else if ((*(index+x) == id2) && (*(index+x+1)==id1))
++                      {
++                              if (set)
++                                      return 1;
++                              reversed = 1;
++                      }
++
++                      if (Look_Up(*(index+x),*(index+x+1),face_id))
++                      {
++                              if ( (out1Ex != -1) && ( (out1Ex == *(index+x)) || (out1Ex == *(index+x+1)) ) &&
++                        ((out2Ex == *(index+x)) || (out2Ex == *(index+x+1))))
++                    {
++                         set = TRUE;
++                         *edge1 = *(index+x);
++                         *edge2 = *(index+x+1);
++                    }
++                              else if (out1Ex == -1)
++                    {
++                         set = TRUE;
++                         *edge1 = *(index+x);
++                                   *edge2 = *(index+x + 1);
++                    }
++                              if ((reversed != -1) && (set))
++                         return reversed;
++                      }
++              }
++      }                       
++      if ((x == size) && (reversed != -1))
++      {
++              /*      Could not find the output edge */
++              printf("Error in the Lookup %d %d %d %d %d %d %d %d\n",face_id,id1,id2,reversed,*edge1,*edge2,out1Ex,out2Ex);
++              exit(0);
++      }
++      return reversed;
++}
++
++
++void Update_FaceEx(int *next_bucket, int *min_face, int face_id, int *e1,
++                          int *e2,int temp1,int temp2,int *ties)
++{
++      /*      We have a face id that needs to be decremented.
++              We have to determine where it is in the structure,
++              so that we can decrement it.
++      */
++      /*      The number of adjacencies may have changed, so to locate
++              it may be a little tricky. However we know that the number
++              of adjacencies is less than or equal to the original number
++              of adjacencies,
++      */
++      int y,size;
++      ListHead *pListHead;
++      PF_FACES temp = NULL;
++      PLISTINFO lpListInfo;
++      static int each_poly = 0;
++      BOOL there = FALSE;
++
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      /*      Check each edge of the face and tally the number of adjacent
++              polygons to this face. 
++      */                      
++      if ( temp != NULL )
++      {
++              /*      Size of the polygon */
++        size = temp->nPolSize;
++        for (y = 0; y< size; y++)
++              {
++                      /*      If we are doing partial triangulation, we must check
++                              to see whether the edge is still there in the polygon,
++                              since we might have done a portion of the polygon
++                              and saved the rest for later.
++                      */
++               if (y != (size-1))
++                      {
++                              if( ((temp1 == *(temp->pPolygon+y)) && (temp2 ==*(temp->pPolygon+y+1)))
++                                      || ((temp2 == *(temp->pPolygon+y)) && (temp1 ==*(temp->pPolygon+y+1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++                      else
++                      {
++                              if( ((temp1 == *(temp->pPolygon)) && (temp2 == *(temp->pPolygon+size-1)))
++                                      || ((temp2 == *(temp->pPolygon)) && (temp1 ==*(temp->pPolygon+size-1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++              }
++              
++          if (!there)
++              /*      Original edge was already used, we cannot use this polygon */
++                      return;
++              
++              /*      We have a starting point to start our search to locate
++                      this polygon. 
++              */
++
++              /*      Check to see if this polygon was done */
++              lpListInfo = Done(face_id,59,&y);
++
++              if (lpListInfo == NULL)
++                      return;
++
++          /*  Was not done, but there is an error in the adjacency calculations */
++          /*     If more than one edge is adj to it then maybe it was not updated */
++          if (y == 0)
++            return;
++                      
++              /*      Now put the face in the proper bucket depending on tally. */
++              /*      First add it to the new bucket, then remove it from the old */
++              Add_Sgi_Adj(y-1,face_id);
++              RemoveList(array[y],lpListInfo);
++        
++          /*  Save it if it was the smallest seen so far since then
++                      it will be the next face 
++                      Here we will have different options depending on
++                      what we want for resolving ties:
++                      1) First one we see we will use
++                      2) Random resolving
++                      3) Look ahead
++                      4) Alternating direction
++              */
++              /*      At a new strip */
++              if (*next_bucket == 60)
++                      *ties = *ties + each_poly;
++              /*      Have a tie */
++              if (*next_bucket == (y-1))
++              {
++                      Add_Ties(face_id);
++                      each_poly++;
++              }
++              /*      At a new minimum */
++              if (*next_bucket > (y-1))
++              {
++                      *next_bucket = y-1;
++                      *min_face = face_id;
++                      *e1 = temp1;
++                      *e2 = temp2;
++                      each_poly = 0;
++                      Clear_Ties();
++                      Add_Ties(face_id);
++              }
++      }
++}
++
++
++void Delete_AdjEx(int id1, int id2,int *next_bucket,int *min_face, 
++                              int current_face,int *e1,int *e2,int *ties)
++{
++      /*      Find the face that is adjacent to the edge and is not the
++              current face. Delete one adjacency from it. Save the min
++              adjacency seen so far.
++      */
++      register int count=0;
++      PF_EDGES temp = NULL;
++      ListHead *pListHead;
++      int next_face;
++
++      /*      Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++      /*      It could be a new edge that we created. So we can
++              exit, since there is not a face adjacent to it.
++      */
++              return;
++     while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          if (temp == NULL)
++                      /*      Was a new edge that was created and therefore
++                              does not have anything adjacent to it
++                      */
++                      return;
++    }
++      /*      Was not adjacent to anything else except itself */
++    if (temp->edge[2] == -1)
++              return;
++
++    /*        Was adjacent to something */
++    else
++    {
++              if (temp->edge[2] == current_face)
++                      next_face =  temp->edge[1];
++              else 
++                      next_face = temp->edge[2];
++      }
++      /*      We have the other face adjacent to this edge, it is 
++              next_face. Now we need to decrement this faces' adjacencies.
++      */
++      Update_FaceEx(next_bucket, min_face, next_face,e1,e2,id1,id2,ties);
++}
++
++int Change_FaceEx(int face_id,int in1,int in2,
++                               ListHead *pListHead, P_ADJACENCIES temp, BOOL no_check)
++{
++      /*      We are doing a partial triangulation and we need to
++              put the new face of triangle into the correct bucket
++      */
++      int input_adj,y;
++     P_ADJACENCIES pfNode,lpListInfo;
++      
++     /*       Find the old number of adjacencies to this face,
++              so we know where to delete it from
++      */
++      y = Old_Adj(face_id);
++      pListHead = array[y];
++
++     pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++      if ( pfNode )
++              pfNode->face_id = face_id;
++      lpListInfo = (P_ADJACENCIES) (SearchList(array[y], pfNode,
++                  (int (*)(void *,void *)) (Compare)));
++      if (lpListInfo == NULL)
++      {
++              printf("There is an error finding the next polygon3 %d\n",face_id);
++              exit(0);
++      }
++
++     /*       Do we need to change the adjacency? Maybe the edge on the triangle
++              that was outputted was not adjacent to anything. We know if we
++              have to check by "check". We came out on the output edge
++              that we needed, then we know that the adjacencies will decrease
++              by exactly one.
++      */
++      if (!no_check)
++      {
++              input_adj = Number_Adj(in1,in2,face_id);
++              /*      If there weren't any then don't do anything */
++              if (input_adj == 0)
++                      return y;
++      }
++     
++      RemoveList(pListHead,(PLISTINFO)/*(temp*/lpListInfo);
++      /*      Before we had a quad with y adjacencies. The in edge
++              did not have an adjacency, since it was just deleted,
++              since we came in on it. The outedge must have an adjacency
++              otherwise we would have a bucket 0, and would not be in this
++              routine. Therefore the new adjacency must be y-1
++      */
++    
++    Add_Sgi_Adj(y-1,face_id);
++    return (y-1);
++}
++
++int Update_AdjacenciesEx(int face_id, int *next_bucket, int *e1, int *e2,
++                                      int *ties)
++{
++      /*      Give the face with id face_id, we want to decrement
++              all the faces that are adjacent to it, since we will
++              be deleting face_id from the data structure.
++              We will return the face that has the least number
++              of adjacencies.
++      */
++      PF_FACES temp = NULL;
++      ListHead *pListHead;
++      int size,y,min_face = -1;
++      
++     *next_bucket = 60;
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      
++      if ( temp == NULL )
++      {
++              printf("The face was already deleted, there is an error\n");
++              exit(0);
++      }
++      
++      /*      Size of the polygon */
++      size = temp->nPolSize;
++      for (y = 0; y< size; y++)
++      {
++              if (y != (size-1))
++                      Delete_AdjEx(*(temp->pPolygon+y),*(temp->pPolygon+y+1),
++                              next_bucket,&min_face,face_id,e1,e2,ties);
++              else
++                      Delete_AdjEx(*(temp->pPolygon),*(temp->pPolygon+(size-1)),
++                              next_bucket,&min_face,face_id,e1,e2,ties);
++      }
++      return (min_face);
++}
++
++
++
++void Find_Adj_TallyEx(int id1, int id2,int *next_bucket,int *min_face, 
++                             int current_face,int *ties)
++{
++      /*      Find the face that is adjacent to the edge and is not the
++              current face. Save the min adjacency seen so far.
++      */
++      int size,each_poly=0,y,tally=0,count=0;
++      PF_EDGES temp = NULL;
++      PF_FACES temp2 = NULL;
++      ListHead *pListHead;
++      int next_face;
++      BOOL there = FALSE;
++
++    
++    /*        Always want smaller id first */
++      switch_lower(&id1,&id2);
++      
++      pListHead = PolEdges[id1];
++      temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++     if (temp == NULL)
++     /*       This was a new edge that was created, so it is
++              adjacent to nothing.
++      */
++              return;
++      while (temp->edge[0] != id2)
++     {
++              count++;
++              temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
++          if (temp == NULL)
++                      /*      This was a new edge that we created */
++                      return;
++     }
++      /*      Was not adjacent to anything else except itself */
++      if (temp->edge[2] == -1)
++              return;
++      else
++      {
++              if (temp->edge[2] == current_face)
++                      next_face =  temp->edge[1];
++              else 
++                      next_face = temp->edge[2];
++      }
++      /*      We have the other face adjacent to this edge, it is 
++              next_face. Find how many faces it is adjacent to.
++      */
++      pListHead = PolFaces[next_face];
++      temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      /*      Check each edge of the face and tally the number of adjacent 
++              polygons to this face. This will be the original number of
++              polygons adjacent to this polygon, we must then see if this
++              number has been decremented
++      */                      
++      if ( temp2 != NULL )
++      {
++              /*      Size of the polygon */
++              size = temp2->nPolSize;
++              for (y = 0; y< size; y++)
++              {
++                      /*      Make sure that the edge is still in the
++                              polygon and was not deleted, because if the edge was
++                              deleted, then we used it already.
++                      */
++                      if (y != (size-1))
++                      {
++                              if( ((id1 == *(temp2->pPolygon+y)) && (id2 ==*(temp2->pPolygon+y+1)))
++                                      || ((id2 == *(temp2->pPolygon+y)) && (id1 ==*(temp2->pPolygon+y+1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++                      else
++                      {               
++                              if( ((id1 == *(temp2->pPolygon)) && (id2 ==*(temp2->pPolygon+size-1)))
++                                      || ((id2 == *(temp2->pPolygon)) && (id1 ==*(temp2->pPolygon+size-1))))
++                                      /*      edge is still there we are ok */
++                                      there = TRUE;
++                      }
++              }
++              
++              if (!there)
++                      /*      Edge already used and deleted from the polygon*/
++                      return;
++              
++              /*      See if the face was already deleted, and where
++                      it is if it was not
++              */
++              if (Done(next_face,size,&y) == NULL)
++                      return;
++              
++              /*      Save it if it was the smallest seen so far since then
++                      it will be the next face 
++                      Here we will have different options depending on
++                      what we want for resolving ties:
++                      1) First one we see we will use
++                      2) Random resolving
++                      3) Look ahead
++                      4) Alternating direction
++              */
++                                      
++              /*      At a new strip */
++              if (*next_bucket == 60)
++                      *ties = *ties + each_poly;
++              /*      Have a tie */
++              if (*next_bucket == (y-1))
++              {
++                      Add_Ties(next_face);
++                      each_poly++;
++              }
++              /*      At a new minimum */
++              if (*next_bucket > (y-1))
++              {
++                      *next_bucket = y-1;
++                      *min_face = next_face;
++                      each_poly = 0;
++                      Clear_Ties();
++                      Add_Ties(next_face);
++              }
++      }
++}
++
++
++int Min_Face_AdjEx(int face_id, int *next_bucket, int *ties)
++{
++      /*      Used for the Partial triangulation to find the next
++              face. It will return the minimum adjacency face id
++              found at this face.
++      */
++      PF_FACES temp = NULL;
++      ListHead *pListHead;
++      int size,y,min_face,test_face;
++      
++      *next_bucket = 60;
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      
++      if ( temp == NULL )
++      {
++              printf("The face was already deleted, there is an error\n");
++              exit(0);
++      }
++      
++      /*      Size of the polygon */
++      size = temp->nPolSize;
++      for (y = 0; y< size; y++)
++      {
++              if (y != (size-1))
++                      Find_Adj_TallyEx(*(temp->pPolygon+y),*(temp->pPolygon+y+1),
++                              next_bucket,&min_face,face_id,ties);
++              else
++                      Find_Adj_TallyEx(*(temp->pPolygon),*(temp->pPolygon+(size-1)),
++                              next_bucket,&min_face,face_id,ties);
++      }
++      /*    Maybe we can do better by triangulating the face, because
++          by triangulating the face we will go to a polygon of lesser
++          adjacencies
++    */
++    if (size == 4)
++    {
++         /*    Checking for a quad whether to do the whole polygon will
++               result in better performance because the triangles in the polygon
++               have less adjacencies
++         */
++         Check_In_Quad(face_id,&test_face);
++         if (*next_bucket > test_face)
++              /*    We can do better by going through the polygon */
++              min_face = face_id;
++    }
++
++    /*  We have a polygon with greater than 4 sides, check to see if going
++        inside is better than going outside the polygon for the output edge.
++    */
++    else
++    {
++        Check_In_Polygon(face_id,&test_face,size);
++        if (*next_bucket > test_face)
++            /*  We can do better by going through the polygon */
++            min_face = face_id;
++    }
++    
++    return (min_face);
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..57490a69589d6fd25f6737349b00d28a1ac56cdb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,36 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: sturcts.h
++-----------------------------------------------------------------------*/
++
++#define EVEN(x) (((x) & 1) == 0)
++
++int Get_Edge(int *edge1,int *edge2,int *index,int face_id,
++           int size, int id1, int id2);
++void add_vert_id();
++void Update_Face(int *next_bucket, int *min_face, int face_id, int *e1,
++               int *e2,int temp1,int temp2,int *ties);
++int Min_Adj();
++int Min_Face_Adj(int face_id, int *next_bucket, int *ties);
++int Change_Face(int face_id,int in1,int in2, ListHead *pListHead, 
++              P_ADJACENCIES temp, BOOL no_check);
++void Delete_Adj(int id1, int id2,int *next_bucket,int *min_face, 
++              int current_face,int *e1,int *e2,int *ties);
++int Update_Adjacencies(int face_id, int *next_bucket, int *e1, int *e2,
++                     int *ties);
++int Get_Output_Edge();
++int Find_Face();
++
++
++
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6a4a76dbe9ac1b288be47c0ef8d03e017b51b01a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,33 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE:sturctsex.h
++-----------------------------------------------------------------------*/
++
++#define EVEN(x) (((x) & 1) == 0)
++
++int Get_EdgeEx(int *edge1,int *edge2,int *index,int face_id,
++             int size, int id1, int id2);
++void add_vert_idEx();
++void Update_FaceEx(int *next_bucket, int *min_face, int face_id, int *e1,
++                 int *e2,int temp1,int temp2,int *ties);
++int Min_Face_AdjEx(int face_id, int *next_bucket, int *ties);
++int Change_FaceEx(int face_id,int in1,int in2,
++                ListHead *pListHead, P_ADJACENCIES temp, BOOL no_check);
++void Delete_AdjEx(int id1, int id2,int *next_bucket,int *min_face, 
++                int current_face,int *e1,int *e2,int *ties);
++int Number_AdjEx();
++int Update_AdjacenciesEx(int face_id, int *next_bucket, int *e1, int *e2,
++                       int *ties);
++
++
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e3fd31f786d39d2ea51d6562c43f0477d3854150
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,304 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*    STRIPE: ties.c
++     This file will contain all the routines used to determine the next face if there
++      is a tie
++*/
++/*---------------------------------------------------------------------*/
++
++#include <stdlib.h>
++#include "polverts.h"
++#include "ties.h"
++#include "sturctsex.h"
++#include "triangulatex.h"
++#include "options.h"
++#include "common.h"
++#include "util.h"
++
++#define MAX_TIE 60
++int ties_array[60];
++int last = 0;
++
++void Clear_Ties()
++{
++      /*      Clear the buffer, because we do not have the tie
++              any more that we had before */
++      last = 0;
++}
++
++void Add_Ties(int id)
++{
++      /*      We have a tie to add to the buffer */
++      ties_array[last++] = id;
++}
++
++int Alternate_Tie()
++{
++      /*      Alternate in what we choose to break the tie 
++              We are just alternating between the first and
++              second thing that we found
++      */
++      static int x = 0;
++      register int t;
++      
++      t = ties_array[x];
++      x++;
++      if (x == 2)
++              x = 0;
++      return t;
++}
++
++int Random_Tie()
++{
++      /*      Randomly choose the next face with which
++              to break the tie
++      */
++      register int num;
++
++      num = rand();
++      while (num >= last)
++              num = num/20;
++      return (ties_array[num]);
++}
++
++int Look_Ahead(int id)
++{
++      /*      Look ahead at this face and save the minimum
++              adjacency of all the faces that are adjacent to
++              this face.
++      */
++      return Min_Adj(id);
++}
++
++int Random_Look(int id[],int count)
++{
++      /*      We had a tie within a tie in the lookahead, 
++              break it randomly 
++      */
++      register int num;
++
++      num = rand();
++      while (num >= count)
++              num = num/20;
++      return (id[num]);
++}
++
++
++int Look_Ahead_Tie()
++{
++      /*      Look ahead and find the face to go to that
++              will give the least number of adjacencies
++      */
++      int id[60],t,x,f=0,min = 60;
++
++      for (x = 0; x < last; x++)
++      {
++              t = Look_Ahead(ties_array[x]);
++              /*      We have a tie */
++              if (t == min)
++                      id[f++] = ties_array[x];
++              if (t < min)
++              {
++                      f = 0;
++                      min = t;
++                      id[f++] = ties_array[x];
++              }
++      }
++      /*      No tie within the tie */
++      if ( f == 1)
++              return id[0];
++      /*      Or ties, but we are at the end of strips */
++      if (min == 0)
++              return id[0];
++      return (Random_Look(id,f));
++}
++
++
++int Sequential_Tri(int *index)
++{
++    /*  We have a triangle and need to break the ties at it.
++        We will choose the edge that is sequential. There
++        is definitely one since we know we have a triangle
++        and that there is a tie and there are only 2 edges
++        for the tie.
++    */
++    int e1,e2,e3,output1,output2,output3,output4;
++
++    /*  e2 and e3 are the input edge to the triangle */
++    Last_Edge(&e1,&e2,&e3,0);
++    
++    if ((e2 == 0) && (e3 == 0))
++        /*  Starting the strip, don't need to do this */
++        return ties_array[0];
++
++    /*  For the 2 ties find the edge adjacent to face id */
++    Get_EdgeEx(&output1,&output2,index,ties_array[0],3,0,0);
++    Get_EdgeEx(&output3,&output4,index,ties_array[1],3,0,0);
++
++    if ((output1 == e3) || (output2 == e3))
++        return ties_array[0];
++    if ((output3 == e3) || (output4 == e3))
++        return ties_array[1];
++    printf("There is an error trying to break sequential triangle \n");
++}
++
++int Sequential_Quad(int *index,       int triangulate)
++{
++    /*  We have a quad that need to break its ties, we will try
++        and choose a side that is sequential, otherwise use lookahead
++    */
++    int output1,output2,x,e1,e2,e3;
++
++    /*  e2 and e3 are the input edge to the quad */
++    Last_Edge(&e1,&e2,&e3,0);
++
++    /*  No input edge */
++    if ((e2 == 0) && (e3 == 0))
++        return ties_array[0];
++
++      /*  Go through the ties and see if there is a sequential one */
++    for (x = 0; x < last; x++)
++      {
++        Get_EdgeEx(&output1,&output2,index,ties_array[x],4,0,0);
++        /*  Partial and whole triangulation will have different requirements */
++        if (((output1 == e3) || (output2 == e3)) && (triangulate == PARTIAL))
++            return ties_array[x];
++        if (((output1 != e3) && (output1 != e2) &&
++                (output2 != e3) && (output2 != e2)))
++            return ties_array[x];
++    }
++    /*  There was not a tie that was sequential */
++      return Look_Ahead_Tie();
++}
++
++void Whole_Output(int in1,int in2, int *index, int size, int *out1, int *out2)
++{
++    /*  Used to sequentially break ties in the whole triangulation for polygons
++        greater than 4 sides. We will find the output edge that is good
++        for sequential triangulation.
++    */
++
++    int half;
++    
++    /*  Put the input edge first in the list */
++    Rearrange_IndexEx(index,size);
++
++    if (!(EVEN(size)))
++    {
++        if (*(index) == in1)
++            half = size/2 ;
++        else
++            half = size/2 +1;
++    }
++    else
++        half = size/2;
++
++    *out1 = *(index+half);
++    *out2 = *(index+half+1);
++}
++
++int Sequential_Poly(int size, int *index, int triangulate)
++{
++    /*  We have a polygon of greater than 4 sides and wish to break the
++        tie in the most sequential manner.
++    */
++
++    int x,output1,output2,e1,e2,e3,saved1=-1,saved2=-1,output3,output4;
++    
++    /*  e2 and e3 are the input edge to the quad */
++    Last_Edge(&e1,&e2,&e3,0);
++
++    /*  If we are using whole, find the output edge that is sequential */
++    if (triangulate == WHOLE)
++        Whole_Output(e2,e3,index,size,&output3,&output4);
++
++    /*  No input edge */
++    if ((e2 == 0) && (e3 == 0))
++        return ties_array[0];
++    
++    for (x = 0; x < last ; x++)
++    {
++        Get_EdgeEx(&output1,&output2,index,ties_array[x],size,0,0);
++        /*  Partial that can be removed in just one triangle */
++        if (((output1 == e3) || (output2 == e3)) && (triangulate == PARTIAL))
++            saved1 = ties_array[x];
++        /*  Partial removed in more than one triangle */
++        if ((output1 != e3) && (output1 != e2) && (output2 != e3) && (output2 != e2) &&
++            (triangulate == PARTIAL) && (saved2 != -1))
++            saved2 = ties_array[x];
++        /*  Whole is not so easy, since the whole polygon must be done. Given
++            an input edge there is only one way to come out, approximately half
++            way around the polygon.
++        */
++        if (((output1 == output3) && (output2 == output4)) ||
++            ((output1 == output4) && (output2 == output3)) &&
++            (triangulate == WHOLE))
++            return ties_array[x];
++    }
++    
++    if (saved1 != -1)
++        return saved1;
++    if (saved2 != -1)
++        return saved2;
++    
++    /*  There was not a tie that was sequential */
++    return Look_Ahead_Tie();
++}
++
++int Sequential_Tie(int face_id, int triangulate)
++{
++    /*  Break the tie by choosing the face that will
++        not give us a swap and is sequential. If there
++        is not one, then do the lookahead to break the
++        tie.
++    */
++    /*  Separate into 3 cases for simplicity, if the current
++        polygon has 3 sides, 4 sides or if the sides were 
++        greater. We can do the smaller cases faster, so that
++        is why I separated the cases.
++    */
++
++     ListHead *pListFace;
++      PF_FACES face;
++
++    /*        Get the polygon with id face_id */
++      pListFace  = PolFaces[face_id];
++      face = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
++
++     if (face->nPolSize == 3)
++        return(Sequential_Tri(face->pPolygon));
++     if (face->nPolSize == 4)
++        return(Sequential_Quad(face->pPolygon,triangulate));
++     else
++        return(Sequential_Poly(face->nPolSize,face->pPolygon,triangulate));
++
++}
++
++int Get_Next_Face(int t, int face_id, int triangulate)
++{
++      /*      Get the next face depending on what
++              the user specified
++      */
++      
++      /*      Did not have a tie, don't do anything */
++      if (last == 1)
++              return(ties_array[0]);
++      if (t == RANDOM)
++              return Random_Tie();
++      if (t == ALTERNATE)
++              return Alternate_Tie();
++      if (t == LOOK)
++              return Look_Ahead_Tie();
++     if (t == SEQUENTIAL)
++        return Sequential_Tie(face_id,triangulate);
++
++      printf("Illegal option specified for ties, using first \n");
++     return (ties_array[0]);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..502aabf4dc88820bf34106c07c331dd1ef042de4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: ties.h
++-----------------------------------------------------------------------*/
++
++void Clear_Ties();
++void Add_Ties(int id);
++int Get_Next_Face(int t, int face_id, int triangulate);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1f677430ae27ba19903f105e6955e91ccef33961
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,27 @@@
++
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: triangulate.h
++-----------------------------------------------------------------------*/
++
++void Blind_Triangulate(int size, int *index, FILE *output,
++                     BOOL begin, int where ,int color1,int color2,
++                       int color3);
++void Non_Blind_Triangulate(int size,int *index, FILE *output,
++                         int next_face_id,int face_id,int where,
++                           int color1,int color2,int color3);
++int Adjacent(int id2,int id1, int *list, int size);
++void Delete_From_List(int id,int *list, int *size);
++void Triangulate_Polygon(int out_edge1, int out_edge2, int in_edge1,
++                       int in_edge2, int size, int *index,
++                       FILE *output, int reversed, int face_id,
++                         int where, int color1, int color2, int color3);
++void Rearrange_Index(int *index, int size);
++void Find_Local_Strips();
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3b2d8fb5c7b099c1b1767246e03879a6417b3b28
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,28 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: triangulatex.h
++-----------------------------------------------------------------------*/
++
++enum swap_type
++{ ON, OFF};
++
++void SGI_StripEx();
++void Blind_TriangulateEx(int size, int *index, FILE *fp, FILE *output, 
++                       BOOL begin, int where );
++void Non_Blind_TriangulateEx(int size,int *index, FILE *fp, FILE *output,
++                           int next_face_id,int face_id,int where);
++int AdjacentEx(int id2,int id1, int *list, int size);
++void Delete_From_ListEx(int id,int *list, int size);
++void Triangulate_PolygonEx(int out_edge1,int out_edge2,int in_edge1,
++                         int in_edge2,int size,int *index,
++                         FILE *output,FILE *fp,int reversed,int face_id,
++                           int where);
++void Rearrange_IndexEx(int *index, int size);
++void Find_StripsEx();
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f17fe5f7cd64e08c94975499833d7bcd81a2e914
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,272 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: util.c
++     This file contains routines that are used for various functions
++*/
++/*---------------------------------------------------------------------*/
++
++
++#include <stdlib.h>
++#include "polverts.h"
++
++void switch_lower (int *x, int *y)
++{
++      register int temp;
++      
++      /*      Put lower value in x */
++      if (*y < *x)
++      {
++              temp = *x;
++              *x = *y;
++              *y = temp;
++      }
++}
++
++BOOL member(int x , int id1, int id2, int id3)
++{
++    /*  Is x in the triangle specified by id1,id2,id3 */
++    if ((x != id1) && (x != id2) && (x != id3))
++      return FALSE;
++    return TRUE;
++}
++
++
++int Compare (P_ADJACENCIES node1, P_ADJACENCIES node2)
++{
++      /*      This will only return whether 2 adjacency nodes
++              are equivalent.                                                           
++      */
++      if (node1->face_id == node2->face_id)
++              return TRUE;
++      else
++              return FALSE;
++}
++
++
++BOOL Exist(int face_id, int id1, int id2)
++{
++      /*      Does the edge specified by id1 and id2 exist in this
++              face currently? Maybe we deleted in partial triangulation
++      */
++      ListHead *pListHead;
++      PF_FACES temp;
++      register int x,size;
++      BOOL a=FALSE,b =FALSE; 
++
++      pListHead = PolFaces[face_id];
++      temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
++      size = temp->nPolSize;
++      for (x=0; x<size; x++)
++      {
++              if (*(temp->pPolygon+x) == id1)
++                      a = TRUE;
++              if (*(temp->pPolygon+x) == id2)
++                      b = TRUE;
++              if (a && b)
++                      return TRUE;
++      }
++      return FALSE;
++}
++
++int Get_Next_Id(int *index,int e3, int size)
++{
++    /*  Return the id following e3 in the list of vertices */
++
++    register int x;
++
++    for (x = 0; x< size; x++)
++    {
++        if ((*(index+x) == e3) && (x != (size-1)))
++            return *(index+x+1);
++        else if (*(index+x) == e3)
++            return *(index);
++    }
++    printf("There is an error in the next id\n");
++    exit(0);
++}
++
++int Different (int id1,int id2,int id3,int id4,int id5, int id6, int *x, int *y)
++{
++    /*    Find the vertex in the first 3 numbers that does not exist in 
++           the last three numbers
++    */
++    if ((id1 != id4) && (id1 != id5) && (id1 != id6))
++    {
++      *x = id2;
++      *y = id3;
++      return id1;
++    }
++    if ((id2 != id4) && (id2 != id5) && (id2 != id6))
++    {
++      *x = id1;
++      *y = id3;
++      return id2;
++    }
++    if ((id3 != id4) && (id3 != id5) && (id3 != id6))
++    {
++      *x = id1;
++      *y = id2;
++      return id3;
++    }
++    
++    /*  Because there are degeneracies in the data, this might occur */
++    *x = id5;
++    *y = id6;
++    return id4;
++}
++
++int Return_Other(int *index,int e1,int e2)
++{
++      /*   We have a triangle and want to know the third vertex of it */
++      register int x;
++
++      for (x=0;x<3;x++)
++      {
++              if ((*(index+x) != e1) && (*(index+x) != e2))
++                      return *(index+x);
++      }
++     /*   If there is a degenerate triangle return arbitrary */
++     return e1;
++}
++
++int Get_Other_Vertex(int id1,int id2,int id3,int *index)
++{
++      /*      We have a list index of 4 numbers and we wish to
++          return the number that is not id1,id2 or id3
++      */
++      register int x;
++
++      for (x=0; x<4; x++)
++      {
++              if ((*(index+x) != id1) && (*(index+x) != id2) &&
++                      (*(index+x) != id3))
++                      return *(index+x);
++      }
++      /*   If there is some sort of degeneracy this might occur,
++          return arbitrary 
++     */
++     if (x==4)
++          return id1;
++}
++
++
++PLISTINFO Done(int face_id, int size, int *bucket)
++{
++      /*      Check to see whether the polygon with face_id was used
++              already, return NULL if it was, otherwise return a pointer to the face.
++      */
++      P_ADJACENCIES pfNode;
++      register int y;
++      PLISTINFO lpListInfo;
++      
++      pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
++      if ( pfNode )
++              pfNode->face_id = face_id;
++              
++      for (y=size; ; y--)
++      {
++              lpListInfo = SearchList(array[y], pfNode,
++                      (int (*)(void *,void *)) (Compare));
++              if (lpListInfo != NULL)
++              {
++                      *bucket = y;
++                      return lpListInfo;
++              }
++              if (y == 0)
++              /*      This adjacent face was done already */
++                      return lpListInfo;
++      }
++      free (pfNode);
++}
++
++void Output_Edge(int *index,int e2,int e3,int *output1,int *output2)
++{
++    /*  Given a quad and an input edge return the other 2 vertices of the
++        quad.
++    */
++    
++    *output1 = -1;
++    *output2 = -1;
++
++    if ((*(index) != e2) && (*(index) != e3))
++        *output1 = *(index);
++
++    if ((*(index+1) != e2) && (*(index+1) != e3))
++    {
++        if (*output1 == -1)
++            *output1 = *(index+1);
++        else
++        {
++            *output2 = *(index+1);
++            return;
++        }
++    }
++
++    if ((*(index+2) != e2) && (*(index+2) != e3))
++    {
++        if (*output1 == -1)
++            *output1 = *(index+2);
++        else
++        {
++            *output2 = *(index+2);
++            return;
++        }
++    }
++
++    *output2 = *(index+3);
++}
++
++
++void First_Edge(int *id1,int *id2, int *id3)
++{
++    /*  Get the first triangle in the strip we just found, we will use this to
++         try to extend backwards in the strip
++    */
++
++    ListHead *pListHead;
++    register int num;
++    P_STRIPS temp1,temp2,temp3;
++       
++    pListHead = strips[0];
++    num = NumOnList(pListHead);
++     
++    /*    Did not have a strip */
++    if (num < 3)
++         return;
++        
++    temp1 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 0);
++    temp2 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 1);
++    temp3 = ( P_STRIPS ) PeekList( pListHead, LISTHEAD, 2);
++    *id1 = temp1->face_id;
++    *id2 = temp2->face_id;
++    *id3 = temp3->face_id;
++ 
++}
++
++void Last_Edge(int *id1, int *id2, int *id3, BOOL save)
++{
++      /*   We need the last edge that we had  */
++      static int v1, v2, v3;
++
++      if (save)
++      {
++              v1 = *id1;
++              v2 = *id2;
++              v3 = *id3;
++      }
++      else
++      {
++              *id1 = v1;
++              *id2 = v2;
++              *id3 = v3;
++      }
++}
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..64c2f233488ab59cd7f77aff6cc36b9dcd618160
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,24 @@@
++/********************************************************************/
++/*   STRIPE: converting a polygonal model to triangle strips    
++     Francine Evans, 1996.
++     SUNY @ Stony Brook
++     Advisors: Steven Skiena and Amitabh Varshney
++*/
++/********************************************************************/
++
++/*---------------------------------------------------------------------*/
++/*   STRIPE: util.h
++-----------------------------------------------------------------------*/
++
++void switch_lower (int *x, int *y);
++int Compare (P_ADJACENCIES node1, P_ADJACENCIES node2);
++BOOL Exist(int face_id, int id1, int id2);
++int Get_Next_Id(int *index,int e3, int size);
++int Different(int id1,int id2,int id3,int id4,int id5, int id6, int *x, int *y);
++int Return_Other(int *index,int e1,int e2);
++int Get_Other_Vertex(int id1,int id2,int id3,int *index);
++PLISTINFO Done(int face_id, int size, int *bucket);
++void Output_Edge(int *index,int e2,int e3,int *output1,int *output2);
++void Last_Edge(int *id1, int *id2, int *id3, BOOL save);
++void First_Edge(int *id1,int *id2, int *id3);
++BOOL member(int x , int id1, int id2, int id3);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..034024ed4d121ae0fa44d13aa65a6cced1d73dcc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++EXTRA_DIST = process-dem.pl scenery_version.hxx
++
++SUBDIRS = \
++      Lib \
++      Prep \
++      Construct \
++      Utils \
++      Areas \
++      AssemTris \
++      FixObj \
++      SplitTris \
++      Stripe_w \
++      Tri2obj
++
++bin_SCRIPTS = process-dem.pl
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..253e47e0433e7cb5db23c659f3ecf9a4c38b3d5d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,75 @@@
++FG Scenery Tools README
++=======================
++
++Contained here-in are the FG scenery creation tools.  These can be
++used to convert 3 arcsec ASCII format DEM files and 30 arcsec binary
++format DEM files into Flight Gear scenery.
++
++Eventually these tools will expand to support insertion of airports,
++roads, rivers, lakes, etc.
++
++
++Building the Tools
++==================
++
++These tools are compiled and tested under Linux.  I'm all for
++portability, but I just haven't been as motivated to port these tools,
++since scenery creation is less of a general need ... especially at
++this stage.  However, if anyone wants to work on porting to other
++platforms, I will be happy to incorporate patches.
++
++The process for building these tools is very similar to building the
++main FG source code.
++
++1.  Set the FG_ROOT, FG_ROOT_SRC, and FG_ROOT_LIB environment
++    variables.
++
++2.  Run ``make depend''
++
++3.  Run ``make clean''
++
++4.  Run ``make''
++
++
++3 Arcsec ASCII DEM files
++========================
++
++Data files for the USA are available in this format from:
++
++    http://edcwww.cr.usgs.gov/doc/edchome/ndcdb/ndcdb.html
++
++To generate FG scenery from one of these dem files, run:
++
++    ./process-dem.pl <error-tolerance-squared> dem-file-1 [ dem-file-2 ...]
++
++You can vary the error tolerance to control the level of detail (and
++size) of the resulting scenery.  Note, you must specify the error
++tolerance squared.  So, if you wish to allow up to a 10 meter error
++margin (very high level of detail) you would specify a value of 100.
++If you desire an error tolerance of 200 meters (medium detail level)
++you would specify a value of 40000.
++
++The process-dem.pl script will automatically dump the resulting .obj
++files in the proper directory tree.
++
++
++30 Arcsec Binary DEM files
++==========================
++
++These data files have world wide coverage and are available from:
++
++    http://edcwww.cr.usgs.gov/landdaac/gtopo30/gtopo30.html
++
++To process these data files, you must first run:
++
++    DemRaw2Ascii/raw2ascii <input_file_basename> <output_dir>
++
++For example:
++
++    DemRaw2Ascii/raw2ascii /tmp/W020N90 asciidems/ 
++
++This will create ASCII DEM files for each 1 degree x 1 degree area in
++the specified output dir.
++
++Then, you can take these ascii dem files and feed them through the
++same procedure you use with the 3 arcsec dem files.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d056dfc03c1d43694ae5238fc0ef3dc1cac88228
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,37 @@@
++--------------------------------------------------------------------------
++| Done
++--------------------------------------------------------------------------
++
++4/6/98 -   fix 30 arcsec dem file processing
++
++4/6/98 -   incorporate autoconf/automake build system
++
++1/10/98 -  Split areas into smaller tiles
++
++1/14/98 -  Don't create shared corners or edges if one already exists.
++
++1/14/98 -  Reassemble triangles using only body, shared corners, and 
++           shared edges.
++
++1/19/98 -  Retro-fit tri2obj to use shared normals rather than regenerating
++           normals for shared vertices.
++
++
++--------------------------------------------------------------------------
++| Todo 
++--------------------------------------------------------------------------
++
++1/12/98 -  Try reversing cw-wound strips rather than calling glFrontFace() 
++           in the display list.
++
++           gnuplot> set label "1" at 1,1
++           gnuplot> set label "2" at 2,2
++
++           gnuplot> plot x
++
++1/21/98 -  Generate an elevation quad tree.
++
++1/12/98 -  Generate a face adjacency matrix
++
++1/21/98 -  Remove internal shared edges and corners that are not needed
++           after an area is generated.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5a92c5bb58c96a233f11e2f008a02783b81d6b7b
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,655 @@@
++#!/usr/bin/perl
++
++#---------------------------------------------------------------------------
++# Toplevel script to automate DEM file processing and conversion
++#
++# Written by Curtis Olson, started January 1998.
++#
++# Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++# $Id$
++# (Log is kept at end of this file)
++#---------------------------------------------------------------------------
++
++
++# format version number
++$scenery_format_version = "0.1";
++
++$max_area = 10000;            # maximum triangle area
++$remove_tmps = 1;
++
++$| = 1;                         # flush buffers after every write
++
++$do_dem2node =   1;
++$do_triangle_1 = 1;
++$do_fixnode =    1;
++$do_splittris =  1;
++$do_assemtris =  1;
++$do_triangle_2 = 1;
++
++$do_tri2obj =    1;
++$do_strips =     1;
++$do_fixobj =     1;
++ 
++$do_install =    1;
++
++
++if ( $#ARGV < 3 ) {
++    die "Usage: $0 <fg-root-dir> <work-dir> <error^2> dem-file(s)\n";
++}
++
++# Start with file.dem
++
++$fg_root = shift(@ARGV);
++$work_dir = shift(@ARGV);
++$error = shift(@ARGV);
++$error += 0.0;
++$system_name = `uname -s`; chop($system_name);
++
++while ( $dem_file = shift(@ARGV) ) {
++    print "Source file = $dem_file  Error tolerance = $error\n";
++
++    if ( $error < 0.5 ) {
++      die "I doubt you'll be happy with an error tolerance as " . 
++          "low as $error.\n";
++    }
++
++
++    if ( $do_dem2node ) {
++      dem2node() ;
++    } else {
++      $subdir = "./work/Scenery/w120n030/w111n033";
++      print "WARNING:  Hardcoding subdir = $subdir\n";
++    }
++
++    triangle_1() if ( $do_triangle_1 );
++    fixnode() if ( $do_fixnode );
++    splittris() if ( $do_splittris );
++    assemtris() if ( $do_assemtris );
++    triangle_2() if ( $do_triangle_2);
++    tri2obj() if ( $do_tri2obj );
++    strips() if ( $do_strips );
++    fixobj() if ( $do_fixobj );
++    install() if ( $do_install );
++}
++
++
++# exit normally
++exit(0);
++
++
++# replace all unix forward slashes with windoze backwards slashes if
++# running on a cygwin32 system
++sub fix_slashes { my($in) = @_;
++    if ( $system_name =~ m/CYGWIN32/ ) { 
++        $in =~ s/\/+/\//g;
++        $in =~ s/\//\\/g;
++    }
++
++    return($in);
++}
++
++
++# return the file name root (ending at last ".")
++sub file_root {
++    my($file) = @_;
++    my($pos);
++
++    $pos = rindex($file, ".");
++    return substr($file, 0, $pos);
++}
++
++
++# 1.  dem2node work_dir dem_file tolerance^2 (meters)
++# 
++#     - dem2node .. dem_file 160000
++#
++#     splits dem file into 64 file.node's which contain the
++#     irregularly fitted vertices
++
++sub dem2node {
++    $command = "Dem2node/dem2node $work_dir $dem_file $error";
++    $command = fix_slashes($command);
++    print "Running '$command'\n";
++
++    open(OUT, "$command |");
++    while ( <OUT> ) {
++      print $_;
++      if ( m/^Dir = / ) {
++          $subdir = $_;
++          $subdir =~ s/^Dir = //;
++          chop($subdir);
++      }
++      if ( m/Quad name field/ ) {
++          $quad_name = $_;
++          # strip header
++          $quad_name =~ s/.*Quad name field: //;
++          # crunch consequetive spaces
++          $quad_name =~ s/  +/ /g;
++          chop($quad_name);
++          print "QUAD NAME = $quad_name\n";
++      }
++    }
++    close(OUT);
++} 
++
++
++# 2.  triangle -q file (Takes file.node and produces file.1.node and
++#                      file.1.ele)
++
++print "Subdirectory for this dem file is $subdir\n";
++
++sub triangle_1 {
++    @FILES = `ls $subdir`;
++    foreach $file ( @FILES ) {
++      # print $file;
++      chop($file);
++      if ( ($file =~ m/\.node$/) && ($file !~ m/\.\d\.node$/) ) {
++          # special handling is needed if .poly file exists
++          $fileroot = $file;
++          $fileroot =~ s/\.node$//;
++          print "$subdir/$fileroot\n";
++          $command = "Triangle/triangle";
++          $command = fix_slashes($command);
++          if ( -r "$subdir/$fileroot.poly" ) {
++              $command .= " -pc";
++          }
++          $command .= " -a$max_area -q10 $subdir/$file";
++          print "Running '$command'\n";
++          open(OUT, "$command |");
++          while ( <OUT> ) {
++              print $_;
++          }
++          close(OUT);
++
++          # remove input file.node
++          if ( $remove_tmps ) {
++              $file1 = "$subdir/$file";
++              $file1 = fix_slashes($file1);
++              unlink($file1);
++          }
++      }
++    }
++}
++
++
++# 3.  fixnode file.dem subdir
++#
++#     Take the original .dem file (for interpolating Z values) and the
++#     subdirecotry containing all the file.1.node's and replace with
++#     fixed file.1.node
++
++sub fixnode {
++    $command = "FixNode/fixnode";
++    $command = fix_slashes($command);
++    $command .= " $dem_file $subdir";
++    print "Running '$command'\n";
++    open(OUT, "$command |") || die "cannot run command\n";
++    while ( <OUT> ) {
++      print $_;
++    }
++    close(OUT);
++}
++
++
++# 4.1 splittris file (.1.node) (.1.ele)
++
++#     Extract the corner, edge, and body vertices (in original
++#     geodetic coordinates) and normals (in cartesian coordinates) and
++#     save them in something very close to the .obj format as file.se,
++#     file.sw, file.nw, file.ne, file.north, file.south, file.east,
++#     file.west, and file.body.  This way we can reconstruct the
++#     region using consistant edges and corners.  
++
++#     Arbitration rules: If an opposite edge file already exists,
++#     don't create our matching edge.  If a corner already exists,
++#     don't create ours.  Basically, the early bird gets the worm and
++#     gets to define the edge verticies and normals.  All the other
++#     adjacent tiles must use these.
++
++sub splittris {
++    @FILES = `ls $subdir`;
++    foreach $file ( @FILES ) {
++      chop($file);
++      if ( $file =~ m/\.1\.node$/ ) {
++          $file =~ s/\.node$//;  # strip off the ".node"
++      
++          $command = "SplitTris/splittris";
++          $command = fix_slashes($command);
++          $command .= " $subdir/$file";
++          print "Running '$command'\n";
++          open(OUT, "$command |");
++          while ( <OUT> ) {
++              print $_;
++          }
++          close(OUT);
++
++          if ( $remove_tmps ) {
++              $file1 = "$subdir/$file.node";
++              $file1 = fix_slashes($file1);
++              unlink($file1);
++              $file1 = "$subdir/$file.node.orig";
++              $file1 = fix_slashes($file1);
++              unlink($file1);
++              $file1 = "$subdir/$file.ele";
++              $file1 = fix_slashes($file1);
++              unlink($file1);
++          }
++      }
++    }
++}
++
++
++# 4.2 read in the split of version of the tiles, reconstruct the tile
++#     using the proper shared corners and edges.  Save as a node file
++#     so we can retriangulate.
++
++sub assemtris {
++    @FILES = `ls $subdir`;
++    foreach $file ( @FILES ) {
++      chop($file);
++      if ( $file =~ m/\.1\.body$/ ) {
++          $file =~ s/\.1\.body$//;  # strip off the ".body"
++      
++          $command = "AssemTris/assemtris";
++          $command = fix_slashes($command);
++          $command .= " $subdir/$file";
++          print "Running '$command'\n";
++          open(OUT, "$command |");
++          while ( <OUT> ) {
++              print $_;
++          }
++          close(OUT);
++      }
++      if ( $remove_tmps ) {
++          $file1 = "$subdir/$file.body";
++          $file1 = fix_slashes($file1);
++          unlink($file1);
++      }
++    }
++}
++
++
++# 4.3 Retriangulate reassembled files (without -q option) so no new
++#     nodes are generated.
++
++sub triangle_2 {
++    @FILES = `ls $subdir`;
++    foreach $file ( @FILES ) {
++      # print $file;
++      chop($file);
++      if ( ($file =~ m/\.node$/) && ($file !~ m/\.\d\.node$/) ) {
++          $base = $file;
++          $base =~ s/\.node$//;
++          print("Test for $subdir/$base.q\n");
++
++          $command = "Triangle/triangle";
++          $command = fix_slashes($command);
++
++          if ( -r "$subdir/$base.q" ) {
++              # if triangle hangs, we can create a filebase.q for
++              # the file it hung on.  Then, we test for that file
++              # here which causes the incremental algorithm to run
++              # (which shouldn't ever hang.)
++              $command .= " -i";
++          }
++
++          if ( -r "$subdir/$base.poly" ) {
++              $command .= " -pc $subdir/$base";
++          } else {
++              $command .= " $subdir/$file";
++          }
++
++          print "Running '$command'\n";
++          open(OUT, "$command |");
++          while ( <OUT> ) {
++              print $_;
++          }
++          close(OUT);
++
++          # remove input file.node
++          if ( $remove_tmps ) {
++              $file1 = "$subdir/$file";
++              $file1 = fix_slashes($file1);
++              unlink($file1);
++          }
++      }
++    }
++}
++
++
++# 5.  tri2obj file (.1.node) (.1.ele)
++#
++#     Take the file.1.node and file.1.ele and produce file.1.obj
++#
++#     Extracts normals out of the shared edge/vertex files, and uses
++#     the precalcuated normals for these nodes instead of calculating
++#     new ones.  By sharing normals as well as vertices, not only are
++#     the gaps between tiles eliminated, but the colors and lighting
++#     transition smoothly across tile boundaries.
++
++sub tri2obj {
++    @FILES = `ls $subdir`;
++    foreach $file ( @FILES ) {
++      chop($file);
++      if ( $file =~ m/\.1\.node$/ ) {
++          $file =~ s/\.node$//;  # strip off the ".node"
++          
++          $command = "Tri2obj/tri2obj";
++          $command = fix_slashes($command);
++          $command .= " $subdir/$file";
++          print "Running '$command'\n";
++          open(OUT, "$command |");
++          while ( <OUT> ) {
++              print $_;
++          }
++          close(OUT);
++          
++          if ( $remove_tmps ) {
++              $file1 = "$subdir/$file.node";
++              $file1 = fix_slashes($file1);
++              unlink($file1);
++              $file1 = "$subdir/$file.node.orig";
++              $file1 = fix_slashes($file1);
++              unlink($file1);
++              $file1 = "$subdir/$file.ele";
++              $file1 = fix_slashes($file1);
++              unlink($file1);
++          }
++      }
++    }
++}
++
++
++# 6.  strip file.1.obj
++# 
++#     Strip the file.1.obj's.  Note, strips doesn't handle the minimal
++#     case of striping a square correctly.
++#
++# 7.  cp stripe.objf file.2.obj
++#
++#     strips produces a file called "stripe.objf" ... copy this to file.2.obj
++
++sub strips {
++    @FILES = `ls $subdir`;
++    foreach $file ( @FILES ) {
++      chop($file);
++      if ( $file =~ m/\.1\.obj$/ ) {
++          $newfile = $file;
++          $newfile =~ s/\.1\.obj$//;
++          $command = "Stripe_w/strips";
++          $command = fix_slashes($command);
++          $command .= " $subdir/$file $subdir/$newfile.2.obj";
++          print "Running '$command'\n";
++          # $input = <STDIN>;
++          open(OUT, "$command |");
++          while ( <OUT> ) {
++              print $_;
++          }
++          close(OUT);
++          
++          # copy to destination file
++          # $newfile = $file;
++          # $newfile =~ s/\.1\.obj$//;
++          # print "Copying to $subdir/$newfile.2.obj\n";
++          # open(IN, "<bands.d");
++          # open(IN, "<stripe.objf");
++          # open(OUT, ">$subdir/$newfile.2.obj");
++          # while ( <IN> ) {
++              # print OUT $_;
++          # }
++          # close(IN);
++          # close(OUT);
++          
++          if ( $remove_tmps ) {
++              $file1 = "$subdir/$file";
++              $file1 = fix_slashes($file1);
++              unlink($file1);
++          }
++      }
++    }
++}
++
++
++# 8.  fixobj file-new
++#
++#     Sort file.2.obj by strip winding
++
++sub fixobj {
++    @FILES = `ls $subdir`;
++    foreach $file ( @FILES ) {
++      chop($file);
++      if ( $file =~ m/\.2\.obj$/ ) {
++          $newfile = $file;
++          $newfile =~ s/\.2\.obj$/.obj/;
++          
++          $command = "FixObj/fixobj";
++          $command = fix_slashes($command);
++          $command .= " $subdir/$file $subdir/$newfile";
++          print "Running '$command'\n";
++          open(OUT, "$command |");
++          while ( <OUT> ) {
++              print $_;
++          }
++          close(OUT);
++
++          if ( $remove_tmps ) {
++              $file1 = "$subdir/$file";
++              $file1 = fix_slashes($file1);
++              unlink($file1);
++          }
++      }
++    }
++}
++
++
++# 9.  install
++#
++#     rename, compress, and install scenery files
++
++sub install {
++    $tmp = $subdir;
++    $tmp =~ s/$work_dir//;
++    # print "Temp dir = $tmp\n";
++    $install_dir = "$fg_root/$tmp";
++
++    # try to get rid of double //
++    $install_dir =~ s/\/+/\//g;
++    print "Install dir = $install_dir\n";
++
++    if ( $system_name !~ m/CYGWIN32/ ) {
++      $command = "mkdir -p $install_dir";
++    } else {
++        $command = "Makedir/makedir $install_dir";
++      $command = fix_slashes($command);
++    }
++
++    # print "Running '$command'\n";
++    open(OUT, "$command |");
++    while ( <OUT> ) {
++      print $_;
++    }
++    close(OUT);
++
++    # write out version and info record
++    $version_file = "$install_dir/VERSION";
++    open(VERSION, ">$version_file") || 
++      die "Cannot open $version_file for writing\n";
++    print VERSION "FGFS Scenery Version $scenery_format_version\n";
++    if ( $system_name !~ m/CYGWIN32/ ) {
++      $date = `date`; chop($date);
++    } else {
++      # ???
++      $date = "not available";
++    }
++    $hostname = `hostname`; chop($hostname);
++    print VERSION "Creator = $ENV{LOGNAME}\n";
++    print VERSION "Date = $date\n";
++    print VERSION "Machine = $hostname\n";
++    print VERSION "\n";
++    print VERSION "DEM File Name = $dem_file\n";
++    print VERSION "DEM Label = $quad_name\n";
++    print VERSION "Error Tolerance = $error (this value is squared)\n";
++    close(VERSION);
++
++    @FILES = `ls $subdir`;
++    foreach $file ( @FILES ) {
++      chop($file);
++      if ( $file =~ m/\d\d.obj$/ ) {
++          $new_file = file_root($file);
++          
++          $command = 
++              "gzip -c --best -v < $subdir/$file > $install_dir/$new_file.gz";
++          $command = fix_slashes($command);
++
++          print "Running '$command'\n";
++          open(OUT, "$command |");
++          while ( <OUT> ) {
++              print $_;
++          }
++          close(OUT);
++
++          if ( $remove_tmps ) {
++              $file1 = "$subdir/$file";
++              $file1 = fix_slashes($file1);
++              unlink($file1);
++          }
++      } elsif ( $file =~ m/\d\d.apt$/ ) {
++          $command = "cp $subdir/$file $install_dir/$file";
++          $command = fix_slashes($command);
++          print "Running '$command'\n";
++          open(OUT, "$command |");
++          while ( <OUT> ) {
++              print $_;
++          }
++          close(OUT);
++      }
++    }
++}
++
++
++#---------------------------------------------------------------------------
++# $Log$
++# Revision 1.32  1998/11/20 01:02:55  curt
++# Speedups for win32.
++#
++# Revision 1.31  1998/10/28 19:39:06  curt
++# Changes to better support win32 scenery development.
++#
++# Revision 1.30  1998/10/22 22:00:10  curt
++# Modified the info that is put in the VERSION file.
++#
++# Revision 1.29  1998/10/02 21:41:56  curt
++# Added Makedir + fixes for win32.
++#
++# Revision 1.28  1998/09/17 18:40:15  curt
++# Changes to allow multiple copies of the scenery processing tools
++# to be run concurrently.
++#
++# Revision 1.27  1998/09/09 20:58:35  curt
++# Fixes and tweaks to handle area cutouts for airports.
++#
++# Revision 1.26  1998/08/26 22:31:29  curt
++# Write out version and "meta" info into each dem's subdirectory containing
++# all the tiles.
++#
++# Revision 1.25  1998/07/22 21:46:09  curt
++# minor tweaks.
++#
++# Revision 1.24  1998/07/21 04:33:47  curt
++# More tweaks for sub-area cutouts.
++#
++# Revision 1.23  1998/07/20 12:55:35  curt
++# Several tweaks to start incorporating area cutouts into the pipeline.
++#
++# Revision 1.22  1998/07/08 14:49:13  curt
++# tweaks.
++#
++# Revision 1.21  1998/06/08 17:18:37  curt
++# Mods to test new Stripe fixes from Wilbur Streett.
++#
++# Revision 1.20  1998/06/05 18:20:24  curt
++# Added DemInfo to dump out "A" record DEM info.
++# Modified process-dem.pl to work in a temp directory and compress/copy the
++# result to the final destination.
++#
++# Revision 1.19  1998/05/27 02:25:26  curt
++# Added a flag to the first run of "triangle" to impose a maximum triangle
++# size.  This forces really flat areas to be subdivided a certain amount
++# anyways.  This makes for slightly more interesting scenery.
++#
++# Revision 1.18  1998/05/20 20:55:40  curt
++# Makefile tweaks
++#
++# Revision 1.17  1998/04/28 01:23:25  curt
++# Added a work around so that we can get past the "triangle" program
++# hanging, by aborting and rerunning with that tile marked to use the "-i"
++# option.
++#
++# Revision 1.16  1998/04/18 03:57:53  curt
++# Added zlib library support.
++#
++# Revision 1.15  1998/04/08 23:24:07  curt
++# Adopted Gnu automake/autoconf system.
++#
++# Revision 1.14  1998/04/06 21:09:38  curt
++# Additional win32 support.
++# Fixed a bad bug in dem file parsing that was causing the output to be
++# flipped about x = y.
++#
++# Revision 1.13  1998/03/19 02:52:52  curt
++# Updated to reflect some minor tool reorganization and the creation of class
++# to handle DEM processing needs.
++#
++# Revision 1.12  1998/03/19 01:48:35  curt
++# Added gpc-2.01 (generic polygon clipping library)
++#
++# Revision 1.11  1998/03/03 03:36:57  curt
++# Cumulative tweaks.
++#
++# Revision 1.10  1998/02/01 03:42:26  curt
++# Modifications to handle compressed dem files.
++#
++# Revision 1.9  1998/01/27 18:36:54  curt
++# Lots of updates to get back in sync with changes made over in .../Src/
++#
++# Revision 1.8  1998/01/21 17:59:05  curt
++# Uncomment lines to remove several intermediate files.
++#
++# Revision 1.7  1998/01/19 19:51:06  curt
++# A couple final pre-release tweaks.
++#
++# Revision 1.6  1998/01/15 21:33:33  curt
++# Assembling triangles and building a new .node file with the proper shared
++# vertices now works.  Now we just have to use the shared normals and we'll
++# be all set.
++#
++# Revision 1.5  1998/01/15 02:50:08  curt
++# Tweaked to add next stage.
++#
++# Revision 1.4  1998/01/14 15:55:34  curt
++# Finished splittris, started assemtris.
++#
++# Revision 1.3  1998/01/14 02:15:52  curt
++# Updated front end script to keep plugging away on tile fitting.
++#
++# Revision 1.2  1998/01/12 20:42:08  curt
++# Working on fitting tiles together in a seamless manner.
++#
++# Revision 1.1  1998/01/09 23:06:46  curt
++# Initial revision.
++#
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c5616a646e0ae5cba0f50517f652e997a6424959
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,31 @@@
++// scenery_version.hxx -- Scenery file format version
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#define FG_SCENERY_FILE_FORMAT "0.2"
++
++
++// $Log$
++// Revision 1.1  1999/03/25 19:13:35  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c27fc320f02b285298b1508cda51d5e2d8bc09b0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,71 @@@
++#---------------------------------------------------------------------------
++# Makefile
++#
++# Written by Curtis Olson, started January 1998.
++#
++# Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++# $Id$
++# (Log is kept at end of this file)
++#---------------------------------------------------------------------------
++
++
++bin_PROGRAMS = tri2obj
++
++tri2obj_SOURCES = tri2obj.cxx tri2obj.hxx
++
++tri2obj_LDADD = \
++      $(top_builddir)/Lib/Bucket/libBucket.a \
++      $(top_builddir)/Lib/Math/libMath.a \
++        $(top_builddir)/Lib/Debug/libDebug.a \
++        $(top_builddir)/Lib/zlib/libz.a \
++      $(base_LIBS)
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
++
++
++#---------------------------------------------------------------------------
++# $Log$
++# Revision 1.7  1998/11/04 23:02:02  curt
++# Changes to the automake/autoconf system to reduce the number of libraries
++# that are unnecessarily linked into the various executables.
++#
++# Revision 1.6  1998/07/30 23:49:26  curt
++# Removed libtool support.
++#
++# Revision 1.5  1998/07/08 14:49:14  curt
++# tweaks.
++#
++# Revision 1.4  1998/04/24 00:44:07  curt
++# Added zlib support.
++#
++# Revision 1.3  1998/04/18 04:01:29  curt
++# Now use libMath rather than having local copies of math routines.
++#
++# Revision 1.2  1998/04/14 02:26:09  curt
++# Code reorganizations.  Added a Lib/ directory for more general libraries.
++#
++# Revision 1.1  1998/04/08 23:22:13  curt
++# Adopted Gnu automake/autoconf system.
++#
++# Revision 1.2  1998/01/21 02:55:46  curt
++# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
++#
++# Revision 1.1  1998/01/15 02:45:25  curt
++# Initial revision.
++#
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a3401052cfd33e156d0455b75c439ea0d322ed0c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,695 @@@
++// tri2obj.cxx -- read in a .ele/.node file pair generated by the triangle 
++//                program and output a simple Wavefront .obj file.
++//
++// Written by Curtis Olson, started October 1997.
++//
++// Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
++//
++// This program is free software; you can redistribute it and/or modify
++// it under the terms of the GNU General Public License as published by
++// the Free Software Foundation; either version 2 of the License, or
++// (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++// GNU General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include <stdio.h>
++#include <stdlib.h>   // for atoi()
++#include <string.h>
++#include <sys/stat.h> // for stat()
++#include <unistd.h>   // for stat()
++
++#include "tri2obj.hxx"
++
++#include <Include/fg_constants.h>
++#include <Bucket/bucketutils.h>
++
++#include <Math/fg_geodesy.hxx>
++#include <Math/mat3.h>
++#include <Math/polar3d.hxx>
++
++
++int nodecount, tricount;
++int normalcount = 0;
++static Point3D nodes[MAX_NODES];
++static int tris[MAX_TRIS][3];
++
++static double normals[MAX_NODES][3];
++
++fgBUCKET my_index;
++fgBUCKET ne_index, nw_index, sw_index, se_index;
++fgBUCKET north_index, south_index, east_index, west_index;
++
++
++// given three points defining a triangle, calculate the normal
++void calc_normal(const Point3D& p1, const Point3D& p2, 
++               const Point3D& p3, double normal[3])
++{
++    double v1[3], v2[3];
++    double temp;
++
++    v1[0] = p2.x() - p1.x(); v1[1] = p2.y() - p1.y(); v1[2] = p2.z() - p1.z();
++    v2[0] = p3.x() - p1.x(); v2[1] = p3.y() - p1.y(); v2[2] = p3.z() - p1.z();
++
++    MAT3cross_product(normal, v1, v2);
++    MAT3_NORMALIZE_VEC(normal, temp);
++
++//  printf("  Normal = %.2f %.2f %.2f\n", normal[0], normal[1], normal[2]);
++}
++
++
++// return the index of all triangles containing the specified node
++void find_tris(int n, int *t1, int *t2, int *t3, int *t4, int *t5) {
++    int i;
++
++    *t1 = *t2 = *t3 = *t4 = *t5 = 0;
++
++    i = 1;
++    while ( i <= tricount ) {
++        if ( (n == tris[i][0]) || (n == tris[i][1]) || (n == tris[i][2]) ) {
++            if ( *t1 == 0 ) {
++              *t1 = i;
++            } else if ( *t2 == 0 ) {
++              *t2 = i;
++            } else if ( *t3 == 0 ) {
++              *t3 = i;
++            } else if ( *t4 == 0 ) {
++              *t4 = i;
++          } else {
++              *t5 = i;
++          }
++        }
++        i++;
++    }
++}
++
++
++// return the file base name ( foo/bar/file.ext = file.ext )
++void extract_file(char *in, char *base) {
++    int len, i;
++
++    len = strlen(in);
++
++    i = len - 1;
++    while ( (i >= 0) && (in[i] != '/') ) {
++      i--;
++    }
++
++    in += (i + 1);
++    strcpy(base, in);
++}
++
++
++// return the file path name ( foo/bar/file.ext = foo/bar )
++void extract_path(char *in, char *base) {
++    int len, i;
++
++    len = strlen(in);
++    strcpy(base, in);
++
++    i = len - 1;
++    while ( (i >= 0) && (in[i] != '/') ) {
++      i--;
++    }
++
++    base[i] = '\0';
++}
++
++
++// check if a file exists
++int file_exists(char *file) {
++    struct stat stat_buf;
++    int result;
++
++    printf("checking %s ... ", file);
++
++    result = stat(file, &stat_buf);
++
++    if ( result != 0 ) {
++      // stat failed, no file
++      printf("not found.\n");
++      return(0);
++    } else {
++      // stat succeeded, file exists
++      printf("exists.\n");
++      return(1);
++    }
++}
++
++
++// check to see if a shared object exists
++int shared_object_exists(char *basepath, char *ext, char *file) {
++    char scene_path[256];
++    long int index;
++
++    if ( strcmp(ext, ".sw") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&west_index, scene_path);
++      index = fgBucketGenIndex(&west_index);
++      sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&sw_index, scene_path);
++      index = fgBucketGenIndex(&sw_index);
++      sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&south_index, scene_path);
++      index = fgBucketGenIndex(&south_index);
++      sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".se") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&east_index, scene_path);
++      index = fgBucketGenIndex(&east_index);
++      sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&se_index, scene_path);
++      index = fgBucketGenIndex(&se_index);
++      sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&south_index, scene_path);
++      index = fgBucketGenIndex(&south_index);
++      sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".ne") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&east_index, scene_path);
++      index = fgBucketGenIndex(&east_index);
++      sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&ne_index, scene_path);
++      index = fgBucketGenIndex(&ne_index);
++      sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&north_index, scene_path);
++      index = fgBucketGenIndex(&north_index);
++      sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".nw") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&west_index, scene_path);
++      index = fgBucketGenIndex(&west_index);
++      sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&nw_index, scene_path);
++      index = fgBucketGenIndex(&nw_index);
++      sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&north_index, scene_path);
++      index = fgBucketGenIndex(&north_index);
++      sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".south") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.south", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&south_index, scene_path);
++      index = fgBucketGenIndex(&south_index);
++      sprintf(file, "%s/%s/%ld.1.north", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".north") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.north", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&north_index, scene_path);
++      index = fgBucketGenIndex(&north_index);
++      sprintf(file, "%s/%s/%ld.1.south", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".west") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.west", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&west_index, scene_path);
++      index = fgBucketGenIndex(&west_index);
++      sprintf(file, "%s/%s/%ld.1.east", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".east") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.east", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++      fgBucketGenBasePath(&east_index, scene_path);
++      index = fgBucketGenIndex(&east_index);
++      sprintf(file, "%s/%s/%ld.1.west", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    if ( strcmp(ext, ".body") == 0 ) {
++      fgBucketGenBasePath(&my_index, scene_path);
++      index = fgBucketGenIndex(&my_index);
++      sprintf(file, "%s/%s/%ld.1.body", basepath, scene_path, index);
++      if ( file_exists(file) ) {
++          return(1);
++      }
++    }
++
++    return(0);
++}
++
++
++// given a file pointer, read all the vn (normals from it)
++void read_normals(FILE *fp) {
++    char line[256];
++
++    while ( fgets(line, 250, fp) != NULL ) {
++      if ( strncmp(line, "vn ", 3) == 0 ) {
++          sscanf( line, "vn %lf %lf %lf\n", 
++                  &normals[normalcount][0], 
++                  &normals[normalcount][1], 
++                  &normals[normalcount][2] );
++          /*
++          printf("read_normals(%d) %.2f %.2f %.2f %s", normalcount, 
++                 normals[normalcount][0], normals[normalcount][1], 
++                 normals[normalcount][2], line);
++                 */
++          normalcount++;
++      }
++    }
++}
++
++
++// my custom file opening routine ... don't open if a shared edge or
++// vertex alread exists
++FILE *my_open(char *basename, char *basepath, char *ext) {
++    FILE *fp;
++    char filename[256];
++
++    // check if a shared object already exists
++    if ( shared_object_exists(basepath, ext, filename) ) {
++      // not an actual file open error, but we've already got the
++        // shared edge, so we don't want to create another one
++      fp = fopen(filename, "r");
++      printf("Opening %s\n", filename);
++      return(fp);
++    } else {
++      // open the file
++      printf("not opening\n");
++      return(NULL);
++    }
++}
++
++
++// Initialize a new mesh structure
++void triload(char *basename, char *basepath) {
++    char nodename[256], elename[256];
++    double n[3];
++    Point3D p;
++    FILE *ne, *nw, *se, *sw, *north, *south, *east, *west;
++    FILE *node, *ele;
++    int dim, junk1, junk2;
++    int i;
++
++    ne = my_open(basename, basepath, ".ne");
++    read_normals(ne);
++    fclose(ne);
++
++    nw = my_open(basename, basepath, ".nw");
++    read_normals(nw);
++    fclose(nw);
++
++    se = my_open(basename, basepath, ".se");
++    read_normals(se);
++    fclose(se);
++
++    sw = my_open(basename, basepath, ".sw");
++    read_normals(sw);
++    fclose(sw);
++
++    north = my_open(basename, basepath, ".north");
++    read_normals(north);
++    fclose(north);
++
++    south = my_open(basename, basepath, ".south");
++    read_normals(south);
++    fclose(south);
++
++    east = my_open(basename, basepath, ".east");
++    read_normals(east);
++    fclose(east);
++
++    west = my_open(basename, basepath, ".west");
++    read_normals(west);
++    fclose(west);
++
++    strcpy(nodename, basename);
++    strcat(nodename, ".node");
++    strcpy(elename, basename);
++    strcat(elename, ".ele");
++
++    printf("Loading node file:  %s ...\n", nodename);
++    if ( (node = fopen(nodename, "r")) == NULL ) {
++      printf("Cannot open file '%s'\n", nodename);
++      exit(-1);
++    }
++
++    fscanf(node, "%d %d %d %d", &nodecount, &dim, &junk1, &junk2);
++
++    if ( nodecount > MAX_NODES - 1 ) {
++      printf("Error, too many nodes, need to increase array size\n");
++      exit(-1);
++    } else {
++      printf("    Expecting %d nodes\n", nodecount);
++    }
++
++    for ( i = 1; i <= nodecount; i++ ) {
++      fscanf(node, "%d %lf %lf %lf %d\n", &junk1, 
++             &n[0], &n[1], &n[2], &junk2);
++      // printf("%d %.2f %.2f %.2f\n", junk1, n[0], n[1], n[2]);
++      p = Point3D( n[0] * ARCSEC_TO_RAD,
++                   n[1] * ARCSEC_TO_RAD,
++                   n[2] );
++      nodes[i] = fgGeodToCart(p);
++      // printf("%d %.2f %.2f %.2f\n", 
++      //        junk1, nodes[i].x, nodes[i].y, nodes[i].z);
++    }
++
++    fclose(node);
++
++    printf("Loading element file:  %s ...\n", elename);
++    if ( (ele = fopen(elename, "r")) == NULL ) {
++      printf("Cannot open file '%s'\n", elename);
++      exit(-1);
++    }
++
++    fscanf(ele, "%d %d %d", &tricount, &junk1, &junk2);
++
++    if ( tricount > MAX_TRIS - 1 ) {
++      printf("Error, too many elements, need to increase array size\n");
++      exit(-1);
++    } else {
++      printf("    Expecting %d elements\n", tricount);
++    }
++
++    for ( i = 1; i <= tricount; i++ ) {
++      fscanf(ele, "%d %d %d %d\n", &junk1, 
++             &tris[i][0], &tris[i][1], &tris[i][2]);
++      // printf("%d %d %d %d\n", junk1, tris[i][0], tris[i][1], tris[i][2]);*/
++    }
++
++    fclose(ele);
++}
++
++
++// dump in WaveFront .obj format
++void dump_obj(char *basename) {
++    char objname[256];
++    double n1[3], n2[3], n3[3], n4[3], n5[3], norm[3], temp;
++    FILE *obj;
++    int i, t1, t2, t3, t4, t5, count;
++    double x, y, z;
++
++    strcpy(objname, basename);
++    strcat(objname, ".obj");
++
++    printf("Dumping to file:  %s ...\n", objname);
++
++    obj = fopen(objname, "w");
++
++    // dump vertices
++    printf("  writing vertices\n");
++    for ( i = 1; i <= nodecount; i++ ) {
++      x = nodes[i].x();
++      y = nodes[i].y();
++      z = nodes[i].z();
++      fprintf(obj, "v %.6f %.6f %.6f\n", x, y, z);
++    }
++
++    printf("  calculating and writing normals\n");
++    printf("  First %d normals taken from shared files.\n", normalcount);
++                                                   
++    // calculate and generate normals
++    for ( i = 1; i <= nodecount; i++ ) {
++
++      if ( i <= normalcount ) {
++          // use precalculated (shared) normal
++          norm[0] = normals[i-1][0];
++          norm[1] = normals[i-1][1];
++          norm[2] = normals[i-1][2];
++      } else {
++          // printf("Finding normal\n");
++
++          find_tris(i, &t1, &t2, &t3, &t4, &t5);
++
++          n1[0] = n1[1] = n1[2] = 0.0;
++          n2[0] = n2[1] = n2[2] = 0.0;
++          n3[0] = n3[1] = n3[2] = 0.0;
++          n4[0] = n4[1] = n4[2] = 0.0;
++          n5[0] = n5[1] = n5[2] = 0.0;
++
++          count = 1;
++          calc_normal(nodes[tris[t1][0]], nodes[tris[t1][1]], 
++                      nodes[tris[t1][2]], n1);
++
++          if ( t2 > 0 ) {
++              calc_normal(nodes[tris[t2][0]], nodes[tris[t2][1]], 
++                          nodes[tris[t2][2]], n2);
++              count = 2;
++          }
++
++          if ( t3 > 0 ) {
++              calc_normal(nodes[tris[t3][0]], nodes[tris[t3][1]],
++                          nodes[tris[t3][2]], n3);
++              count = 3;
++          }
++
++          if ( t4 > 0 ) {
++              calc_normal(nodes[tris[t4][0]], nodes[tris[t4][1]],
++                          nodes[tris[t4][2]], n4);
++              count = 4;
++          }
++
++          if ( t5 > 0 ) {
++              calc_normal(nodes[tris[t5][0]], nodes[tris[t5][1]],
++                          nodes[tris[t5][2]], n5);
++              count = 5;
++          }
++
++          // printf("  norm[2] = %.2f %.2f %.2f\n", n1[2], n2[2], n3[2]);
++
++          norm[0] = ( n1[0] + n2[0] + n3[0] + n4[0] + n5[0] ) / (double)count;
++          norm[1] = ( n1[1] + n2[1] + n3[1] + n4[1] + n5[1] ) / (double)count;
++          norm[2] = ( n1[2] + n2[2] + n3[2] + n4[2] + n5[2] ) / (double)count;
++      
++          //  printf("  count = %d\n", count);
++          //  printf("  Ave. normal = %.4f %.4f %.4f\n", 
++          //         norm[0], norm[1], norm[2]);*/
++          MAT3_NORMALIZE_VEC(norm, temp);
++          //  printf("  Normalized ave. normal = %.4f %.4f %.4f\n", 
++          //         norm[0], norm[1], norm[2]);
++      }
++      // printf("%d vn %.4f %.4f %.4f\n", i, norm[0], norm[1], norm[2]);
++      fprintf(obj, "vn %.4f %.4f %.4f\n", norm[0], norm[1], norm[2]);
++    }
++
++    // dump faces
++    printf("  writing faces\n");
++    for ( i = 1; i <= tricount; i++ ) {
++      fprintf(obj, "f %d %d %d\n", tris[i][0], tris[i][1], tris[i][2]);
++    }
++
++    fclose(obj);
++}
++
++int main(int argc, char **argv) {
++    char basename[256], basepath[256], temp[256];
++    long int tmp_index;
++    int len;
++
++    strcpy(basename, argv[1]);
++
++    // find the base path of the file
++    extract_path(basename, basepath);
++    extract_path(basepath, basepath);
++    extract_path(basepath, basepath);
++    printf("%s\n", basepath);
++
++    // find the index of the current file
++    extract_file(basename, temp);
++    len = strlen(temp);
++    if ( len >= 2 ) {
++      temp[len-2] = '\0';
++    }
++    tmp_index = atoi(temp);
++    printf("%ld\n", tmp_index);
++    fgBucketParseIndex(tmp_index, &my_index);
++
++    printf("bucket = %d %d %d %d\n", 
++         my_index.lon, my_index.lat, my_index.x, my_index.y);
++    // generate the indexes of the neighbors
++    fgBucketOffset(&my_index, &ne_index,  1,  1);
++    fgBucketOffset(&my_index, &nw_index, -1,  1);
++    fgBucketOffset(&my_index, &se_index,  1, -1);
++    fgBucketOffset(&my_index, &sw_index, -1, -1);
++
++    fgBucketOffset(&my_index, &north_index,  0,  1);
++    fgBucketOffset(&my_index, &south_index,  0, -1);
++    fgBucketOffset(&my_index, &east_index,  1,  0);
++    fgBucketOffset(&my_index, &west_index, -1,  0);
++
++    // load the input data files
++    triload(basename, basepath);
++
++    // dump in WaveFront .obj format
++    dump_obj(basename);
++
++    return(0);
++}
++
++
++// $Log$
++// Revision 1.5  1998/10/21 14:56:50  curt
++// Minor parameter passing tweak.
++//
++// Revision 1.4  1998/10/20 15:52:46  curt
++// Fixed a units conversion bug introduced when converting to Point3D class.
++//
++// Revision 1.3  1998/10/19 19:33:31  curt
++// C++-ification.
++//
++// Revision 1.2  1998/10/18 01:17:29  curt
++// Point3D tweaks.
++//
++// Revision 1.1  1998/07/08 14:54:53  curt
++// renamed *.[ch] to *.[ch]xx
++//
++// Revision 1.17  1998/07/04 00:56:40  curt
++// typedef'd struct fgBUCKET.
++//
++// Revision 1.16  1998/05/23 15:20:41  curt
++// Output more digits after the decimal place.
++//
++// Revision 1.15  1998/05/02 01:54:39  curt
++// Converting to polar3d.h routines.
++//
++// Revision 1.14  1998/04/18 04:01:32  curt
++// Now use libMath rather than having local copies of math routines.
++//
++// Revision 1.13  1998/04/14 02:26:11  curt
++// Code reorganizations.  Added a Lib/ directory for more general libraries.
++//
++// Revision 1.12  1998/04/08 23:22:18  curt
++// Adopted Gnu automake/autoconf system.
++//
++// Revision 1.11  1998/03/03 16:01:00  curt
++// More c++ compile tweaks.
++//
++// Revision 1.10  1998/01/31 00:41:27  curt
++// Made a few changes converting floats to doubles.
++//
++// Revision 1.9  1998/01/27 18:37:04  curt
++// Lots of updates to get back in sync with changes made over in .../Src/
++//
++// Revision 1.8  1998/01/17 01:25:39  curt
++// Added support for shared normals.
++//
++// Revision 1.7  1998/01/12 02:42:00  curt
++// Average up to five triangles per vertex instead of three.
++//
++// Revision 1.6  1998/01/09 23:03:15  curt
++// Restructured to split 1deg x 1deg dem's into 64 subsections.
++//
++// Revision 1.5  1997/12/08 19:17:50  curt
++// Fixed a type in the normal generation code.
++//
++// Revision 1.4  1997/12/02 13:13:32  curt
++// Fixed problem with averaged vertex normals.
++//
++// Revision 1.3  1997/11/15 18:05:05  curt
++// minor tweaks ...
++//
++// Revision 1.2  1997/11/14 00:29:13  curt
++// Transform scenery coordinates at this point in pipeline when scenery is
++// being translated to .obj format, not when it is being loaded into the end
++// renderer.  Precalculate normals for each node as average of the normals
++// of each containing polygon so Garoude shading is now supportable.
++//
++// Revision 1.1  1997/10/29 23:05:15  curt
++// Initial revision.
++//
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c7a54d159855258173e7d36d3a103cae4e01dbb2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,68 @@@
++/* tri2obj.h -- read in a .ele/.node file pair generated by the triangle 
++ *              program and output a Wavefront .obj file.
++ *
++ * Written by Curtis Olson, started October 1997.
++ *
++ * Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * $Id$
++ * (Log is kept at end of this file)
++ */
++
++
++#ifndef TRI2OBJ_H
++#define TRI2OBJ_H
++
++
++#include <stdio.h>
++#include <string.h>
++
++
++#define MAX_NODES 200000
++#define MAX_TRIS  400000
++
++
++/* Initialize a new mesh structure */
++void triload(char *basename, char *basepath);
++
++
++#endif /* TRI2OBJ_H */
++
++
++/* $Log$
++/* Revision 1.1  1998/07/08 14:54:54  curt
++/* renamed *.[ch] to *.[ch]xx
++/*
++ * Revision 1.5  1998/03/03 16:01:00  curt
++ * More c++ compile tweaks.
++ *
++ * Revision 1.4  1998/01/17 01:25:40  curt
++ * Added support for shared normals.
++ *
++ * Revision 1.3  1997/11/15 18:05:06  curt
++ * minor tweaks ...
++ *
++ * Revision 1.2  1997/11/14 00:29:13  curt
++ * Transform scenery coordinates at this point in pipeline when scenery is
++ * being translated to .obj format, not when it is being loaded into the end
++ * renderer.  Precalculate normals for each node as average of the normals
++ * of each containing polygon so Garoude shading is now supportable.
++ *
++ * Revision 1.1  1997/10/29 23:05:15  curt
++ * Initial revision.
++ *
++ */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..166a71773a6b72b6393e09a9fdd6530ff01cf426
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,62 @@@
++29 2 1 0
++1 0.200000 -0.776400 -0.57
++2 0.220000 -0.773200 -0.55
++3 0.245600 -0.756400 -0.51
++4 0.277600 -0.702000 -0.53
++5 0.488800 -0.207600 0.28
++6 0.504800 -0.207600 0.30
++7 0.740800 -0.739600 0
++8 0.756000 -0.761200 -0.01
++9 0.774400 -0.772400 0
++10 0.800000 -0.776400 0.02
++11 0.800000 -0.792400 0.01
++12 0.579200 -0.792400 -0.21
++13 0.579200 -0.776400 -0.2
++14 0.621600 -0.771600 -0.15
++15 0.633600 -0.762800 -0.13
++16 0.639200 -0.744400 -0.1
++17 0.620800 -0.684400 -0.06
++18 0.587200 -0.604400 -0.01
++19 0.360800 -0.604400 -0.24
++20 0.319200 -0.706800 -0.39
++21 0.312000 -0.739600 -0.43
++22 0.318400 -0.761200 -0.44
++23 0.334400 -0.771600 -0.44
++24 0.371200 -0.776400 -0.41
++25 0.371200 -0.792400 -0.42
++26 0.374400 -0.570000 -0.2
++27 0.574400 -0.570000 0
++28 0.473600 -0.330800 0.14
++29 0.200000 -0.792400 -0.59
++29 0
++1 29 1
++2 1 2
++3 2 3
++4 3 4
++5 4 5
++6 5 6
++7 6 7
++8 7 8
++9 8 9
++10 9 10
++11 10 11
++12 11 12
++13 12 13
++14 13 14
++15 14 15
++16 15 16
++17 16 17
++18 17 18
++19 18 19
++20 19 20
++21 20 21
++22 21 22
++23 22 23
++24 23 24
++25 24 25
++26 25 29
++27 26 27
++28 27 28
++29 28 26
++1
++1 0.47 -0.5
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..caa86591bbd84c4af82619dac24f5e2fd465070b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,24 @@@
++# DEFS is a list of definitions used to compile an object code version
++#   of Triangle (triangle.o) to be called by another program.  The file
++#   "triangle.h" contains detailed information on how to call triangle.o.
++#
++# The -DTRILIBRARY should always be used when compiling Triangle into an
++#   object file.
++#
++# An example DEFS line is:
++#
++#   DEFS = -DTRILIBRARY -DREDUCED -DCDT_ONLY
++
++DEFS += -DTRILIBRARY
++
++noinst_LIBRARIES = libTriangle.a
++
++libTriangle_a_SOURCES = triangle.c triangle.h
++
++if HAVE_XWINDOWS
++
++bin_PROGRAMS = showme
++showme_SOURCES = showme.c
++showme_LDADD = -lX11
++
++endif
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..571d5689f736c9a6332a2be3769b8886d8982590
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,181 @@@
++Triangle
++A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.
++Version 1.3
++
++Show Me
++A Display Program for Meshes and More.
++Version 1.3
++
++Copyright 1996 Jonathan Richard Shewchuk
++School of Computer Science
++Carnegie Mellon University
++5000 Forbes Avenue
++Pittsburgh, Pennsylvania  15213-3891
++Please send bugs and comments to jrs@cs.cmu.edu
++
++Created as part of the Archimedes project (tools for parallel FEM).
++Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.
++There is no warranty whatsoever.  Use at your own risk.
++
++
++Triangle generates exact Delaunay triangulations, constrained Delaunay
++triangulations, and quality conforming Delaunay triangulations.  The
++latter can be generated with no small angles, and are thus suitable for
++finite element analysis.  Show Me graphically displays the contents of
++the geometric files used by Triangle.  Show Me can also write images in
++PostScript form.
++
++Information on the algorithms used by Triangle, including complete
++references, can be found in the comments at the beginning of the triangle.c
++source file.  Another listing of these references, with PostScript copies
++of some of the papers, is available from the Web page
++
++    http://www.cs.cmu.edu/~quake/triangle.research.html
++
++------------------------------------------------------------------------------
++
++These programs may be freely redistributed under the condition that the
++copyright notices (including the copy of this notice in the code comments
++and the copyright notice printed when the `-h' switch is selected) are
++not removed, and no compensation is received.  Private, research, and
++institutional use is free.  You may distribute modified versions of this
++code UNDER THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT
++IN THE SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH
++SOURCE AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND
++CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS.  Distribution of this code as
++part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT
++WITH THE AUTHOR.  (If you are not directly supplying this code to a
++customer, and you are instead telling them how they can obtain it for
++free, then you are not required to make any arrangement with me.)
++
++------------------------------------------------------------------------------
++
++The files included in this distribution are:
++
++  README           The file you're reading now.
++  triangle.c       Complete C source code for Triangle.
++  showme.c         Complete C source code for Show Me.
++  triangle.h       Include file for calling Triangle from another program.
++  tricall.c        Sample program that calls Triangle.
++  makefile         Makefile for compiling Triangle and Show Me.
++  A.poly           A sample data file.
++
++Triangle and Show Me are each a single portable C file.  The easiest way to
++compile them is to edit and use the included makefile.  Before compiling,
++read the makefile, which describes your options, and edit it accordingly.
++You should specify:
++
++  The source and binary directories.
++
++  The C compiler and level of optimization.
++
++  Do you want single precision or double?  Do you want to leave out some of
++  Triangle's features to reduce the size of the executable file?
++
++  The "correct" directories for include files (especially X include files),
++  if necessary.
++
++Once you've done this, type "make" to compile the programs.  Alternatively,
++the files are usually easy to compile without a makefile:
++
++  cc -O -o triangle triangle.c -lm
++  cc -O -o showme showme.c -lX11
++
++On some systems, the C compiler won't be able to find the X include files
++or libraries, and you'll need to specify an include path or library path:
++
++  cc -O -I/usr/local/include -o showme showme.c -L/usr/local/lib -lX11
++
++However, on other systems (like my workstation), the latter incantation
++will cause the wrong files to be read, and the Show Me mouse buttons won't
++work properly in the main window.  Hence, try the "-I" and "-L" switches
++ONLY if the compiler fails without it.  (If you're using the makefile, you
++may edit it to add this switch.)
++
++Some processors, possibly including Intel x86 family and Motorola 68xxx
++family chips, are IEEE conformant but have extended length internal
++floating-point registers that may defeat Triangle's exact arithmetic
++routines by failing to cause enough roundoff error!  Typically, there is
++a way to set these internal registers so that they are rounded off to
++IEEE single or double precision format.  If you have such a processor,
++you should check your C compiler or system manuals to find out how to
++configure these internal registers to the precision you are using.
++Otherwise, the exact arithmetic routines won't be exact at all.
++Unfortunately, I don't have access to any such systems, and can't give
++advice on how to configure them.  These problems don't occur on any
++workstations I am aware of.  However, Triangle's exact arithmetic hasn't
++a hope of working on machines like the Cray C90 or Y-MP, which are not
++IEEE conformant and have inaccurate rounding.
++
++Triangle and Show Me both produce their own documentation.  Complete
++instructions are printed by invoking each program with the `-h' switch:
++
++  triangle -h
++  showme -h
++
++The instructions are long; you'll probably want to pipe the output to
++`more' or `lpr' or redirect it to a file.  Both programs give a short list
++of command line options if they are invoked without arguments (that is,
++just type `triangle' or `showme').  Alternatively, you may want to read
++the instructions on the World Wide Web.  The appropriate URLs are:
++
++  http://www.cs.cmu.edu/~quake/triangle.html
++  http://www.cs.cmu.edu/~quake/showme.html
++
++Try out Triangle on the enclosed sample file, A.poly:
++
++  triangle -p A
++  showme A.poly &
++
++Triangle will read the Planar Straight Line Graph defined by A.poly, and
++write its constrained Delaunay triangulation to A.1.node and A.1.ele.
++Show Me will display the figure defined by A.poly.  There are two buttons
++marked "ele" in the Show Me window; click on the top one.  This will cause
++Show Me to load and display the triangulation.
++
++For contrast, try running
++
++  triangle -pq A
++
++Now, click on the same "ele" button.  A new triangulation will be loaded;
++this one having no angles smaller than 20 degrees.
++
++To see a Voronoi diagram, try this:
++
++  cp A.poly A.node
++  triangle -v A
++
++Click the "ele" button again.  You will see the Delaunay triangulation of
++the points in A.poly, without the segments.  Now click the top "voro" button.
++You will see the Voronoi diagram corresponding to that Delaunay triangulation.
++Click the "Reset" button to see the full extent of the diagram.
++
++------------------------------------------------------------------------------
++
++If you wish to call Triangle from another program, instructions for doing
++so are contained in the file `triangle.h' (but read Triangle's regular
++instructions first!).  Also look at `tricall.c', which provides an example.
++
++Type "make trilibrary" to create triangle.o, a callable object file.
++Alternatively, the object file is usually easy to compile without a
++makefile:
++
++  cc -DTRILIBRARY -O -c triangle.c
++
++------------------------------------------------------------------------------
++
++If you use Triangle, and especially if you use it to accomplish real
++work, I would like very much to hear from you.  A short letter or email
++(to jrs@cs.cmu.edu) describing how you use Triangle will mean a lot to
++me.  The more people I know are using this program, the more easily I can
++justify spending time on improvements and on the three-dimensional
++successor to Triangle, which in turn will benefit you.  Also, I can put
++you on a list to receive email whenever a new version of Triangle is
++available.
++
++If you use a mesh generated by Triangle or plotted by Show Me in a
++publication, please include an acknowledgment as well.
++
++
++Jonathan Richard Shewchuk
++July 20, 1996
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..722cba8ace4117e2d6a6e01c1c006a19e569b70c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3384 @@@
++/*****************************************************************************/
++/*                                                                           */
++/*    ,d88^^o 888                                   o    o                   */
++/*    8888    888o^88,  o88^^o Y88b    o    /      d8b  d8b      o88^^8o     */
++/*    "Y88b   888  888 d888   b Y88b  d8b  /      d888bdY88b    d888  88b    */
++/*     "Y88b, 888  888 8888   8  Y888/Y88b/      / Y88Y Y888b   8888oo888    */
++/*    o  8888 888  888 q888   p   Y8/  Y8/      /   YY   Y888b  q888         */
++/*    "oo88P" 888  888  "88oo"     Y    Y      /          Y888b  "88oooo"    */
++/*                                                                           */
++/*  A Display Program for Meshes and More.                                   */
++/*  (showme.c)                                                               */
++/*                                                                           */
++/*  Version 1.3                                                              */
++/*  July 20, 1996                                                            */
++/*                                                                           */
++/*  Copyright 1996                                                           */
++/*  Jonathan Richard Shewchuk                                                */
++/*  School of Computer Science                                               */
++/*  Carnegie Mellon University                                               */
++/*  5000 Forbes Avenue                                                       */
++/*  Pittsburgh, Pennsylvania  15213-3891                                     */
++/*  jrs@cs.cmu.edu                                                           */
++/*                                                                           */
++/*  This program may be freely redistributed under the condition that the    */
++/*    copyright notices (including this entire header and the copyright      */
++/*    notice printed when the `-h' switch is selected) are not removed, and  */
++/*    no compensation is received.  Private, research, and institutional     */
++/*    use is free.  You may distribute modified versions of this code UNDER  */
++/*    THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE   */
++/*    SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE   */
++/*    AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR    */
++/*    NOTICE IS GIVEN OF THE MODIFICATIONS.  Distribution of this code as    */
++/*    part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT  */
++/*    WITH THE AUTHOR.  (If you are not directly supplying this code to a    */
++/*    customer, and you are instead telling them how they can obtain it for  */
++/*    free, then you are not required to make any arrangement with me.)      */
++/*                                                                           */
++/*  Hypertext instructions for Triangle are available on the Web at          */
++/*                                                                           */
++/*      http://www.cs.cmu.edu/~quake/showme.html                             */
++/*                                                                           */
++/*  Show Me was created as part of the Archimedes project in the School of   */
++/*    Computer Science at Carnegie Mellon University.  Archimedes is a       */
++/*    system for compiling parallel finite element solvers.  For further     */
++/*    information, see Anja Feldmann, Omar Ghattas, John R. Gilbert, Gary L. */
++/*    Miller, David R. O'Hallaron, Eric J. Schwabe, Jonathan R. Shewchuk,    */
++/*    and Shang-Hua Teng.  "Automated Parallel Solution of Unstructured PDE  */
++/*    Problems."  To appear in Communications of the ACM, we hope.           */
++/*                                                                           */
++/*  If you make any improvements to this code, please please please let me   */
++/*    know, so that I may obtain the improvements.  Even if you don't change */
++/*    the code, I'd still love to hear what it's being used for.             */
++/*                                                                           */
++/*  Disclaimer:  Neither I nor Carnegie Mellon warrant this code in any way  */
++/*    whatsoever.  Use at your own risk.                                     */
++/*                                                                           */
++/*****************************************************************************/
++
++/* For single precision (which will save some memory and reduce paging),     */
++/*   write "#define SINGLE" below.                                           */
++/*                                                                           */
++/* For double precision (which will allow you to display triangulations of   */
++/*   a finer resolution), leave SINGLE undefined.                            */
++
++/* #define SINGLE */
++
++#ifdef SINGLE
++#define REAL float
++#else
++#define REAL double
++#endif
++
++/* Maximum number of characters in a file name (including the null).         */
++
++#define FILENAMESIZE 1024
++
++/* Maximum number of characters in a line read from a file (including the    */
++/*   null).                                                                  */
++
++#define INPUTLINESIZE 512
++
++#define STARTWIDTH 414
++#define STARTHEIGHT 414
++#define MINWIDTH 50
++#define MINHEIGHT 50
++#define BUTTONHEIGHT 21
++#define BUTTONROWS 3
++#define PANELHEIGHT (BUTTONHEIGHT * BUTTONROWS)
++#define MAXCOLORS 64
++
++#define IMAGE_TYPES 7
++#define NOTHING -1
++#define NODE 0
++#define POLY 1
++#define ELE 2
++#define EDGE 3
++#define PART 4
++#define ADJ 5
++#define VORO 6
++
++#define STARTEXPLOSION 0.5
++
++#include <stdio.h>
++#include <string.h>
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++#include <X11/Xatom.h>
++
++/* The following obscenity seems to be necessary to ensure that this program */
++/* will port to Dec Alphas running OSF/1, because their stdio.h file commits */
++/* the unpardonable sin of including stdlib.h.  Hence, malloc(), free(), and */
++/* exit() may or may not already be defined at this point.  I declare these  */
++/* functions explicitly because some non-ANSI C compilers lack stdlib.h.     */
++
++#ifndef _STDLIB_H_
++extern char *malloc();
++extern void free();
++extern void exit();
++extern double strtod();
++extern long strtol();
++#endif
++
++/* A necessary forward declaration.                                          */
++
++int load_image();
++
++Display *display;
++int screen;
++Window rootwindow;
++Window mainwindow;
++Window quitwin;
++Window leftwin;
++Window rightwin;
++Window upwin;
++Window downwin;
++Window resetwin;
++Window pswin;
++Window epswin;
++Window expwin;
++Window exppluswin;
++Window expminuswin;
++Window widthpluswin;
++Window widthminuswin;
++Window versionpluswin;
++Window versionminuswin;
++Window fillwin;
++Window nodewin[2];
++Window polywin[2];
++Window elewin[2];
++Window edgewin[2];
++Window partwin[2];
++Window adjwin[2];
++Window voronoiwin[2];
++
++int windowdepth;
++XEvent event;
++Colormap rootmap;
++XFontStruct *font;
++int width, height;
++int black, white;
++int showme_foreground;
++GC fontgc;
++GC blackfontgc;
++GC linegc;
++GC trianglegc;
++int colors[MAXCOLORS];
++XColor rgb[MAXCOLORS];
++int color;
++
++int start_image, current_image;
++int start_inc, current_inc;
++int loweriteration;
++int line_width;
++int loaded[2][IMAGE_TYPES];
++REAL xlo[2][IMAGE_TYPES], ylo[2][IMAGE_TYPES];
++REAL xhi[2][IMAGE_TYPES], yhi[2][IMAGE_TYPES];
++REAL xscale, yscale;
++REAL xoffset, yoffset;
++int zoom;
++
++int nodes[2], node_dim[2];
++REAL *nodeptr[2];
++int polynodes[2], poly_dim[2], polyedges[2], polyholes[2];
++REAL *polynodeptr[2], *polyholeptr[2];
++int *polyedgeptr[2];
++int elems[2], ele_corners[2];
++int *eleptr[2];
++int edges[2];
++int *edgeptr[2];
++REAL *normptr[2];
++int subdomains[2];
++int *partpart[2];
++REAL *partcenter[2], *partshift[2];
++int adjsubdomains[2];
++int *adjptr[2];
++int vnodes[2], vnode_dim[2];
++REAL *vnodeptr[2];
++int vedges[2];
++int *vedgeptr[2];
++REAL *vnormptr[2];
++int firstnumber[2];
++
++int quiet, fillelem, bw_ps, explode;
++REAL explosion;
++
++char filename[FILENAMESIZE];
++char nodefilename[2][FILENAMESIZE];
++char polyfilename[2][FILENAMESIZE];
++char elefilename[2][FILENAMESIZE];
++char edgefilename[2][FILENAMESIZE];
++char partfilename[2][FILENAMESIZE];
++char adjfilename[2][FILENAMESIZE];
++char vnodefilename[2][FILENAMESIZE];
++char vedgefilename[2][FILENAMESIZE];
++
++char *colorname[] = {"aquamarine", "red", "green yellow", "magenta",
++                     "yellow", "green", "orange", "blue",
++                     "white", "sandy brown", "cyan", "moccasin",
++                     "cadet blue", "coral", "cornflower blue", "sky blue",
++                     "firebrick", "forest green", "gold", "goldenrod",
++                     "gray", "hot pink", "chartreuse", "pale violet red",
++                     "indian red", "khaki", "lavender", "light blue",
++                     "light gray", "light steel blue", "lime green", "azure",
++                     "maroon", "medium aquamarine", "dodger blue", "honeydew",
++                     "medium orchid", "medium sea green", "moccasin",
++                     "medium slate blue", "medium spring green",
++                     "medium turquoise", "medium violet red",
++                     "orange red", "chocolate", "light goldenrod",
++                     "orchid", "pale green", "pink", "plum",
++                     "purple", "salmon", "sea green",
++                     "sienna", "slate blue", "spring green",
++                     "steel blue", "tan", "thistle", "turquoise",
++                     "violet", "violet red", "wheat",
++                     "yellow green"};
++
++void syntax()
++{
++  printf("showme [-bfw_Qh] input_file\n");
++  printf("    -b  Black and white PostScript (default is color).\n");
++  printf("    -f  Fill triangles of partitioned mesh with color.\n");
++  printf("    -w  Set line width to some specified number.\n");
++  printf("    -Q  Quiet:  No terminal output except errors.\n");
++  printf("    -h  Help:  Detailed instructions for Show Me.\n");
++  exit(0);
++}
++
++void info()
++{
++  printf("Show Me\n");
++  printf("A Display Program for Meshes and More.\n");
++  printf("Version 1.3\n\n");
++  printf(
++"Copyright 1996 Jonathan Richard Shewchuk  (bugs/comments to jrs@cs.cmu.edu)\n"
++);
++  printf("School of Computer Science / Carnegie Mellon University\n");
++  printf("5000 Forbes Avenue / Pittsburgh, Pennsylvania  15213-3891\n");
++  printf(
++"Created as part of the Archimedes project (tools for parallel FEM).\n");
++  printf(
++"Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.\n");
++  printf("There is no warranty whatsoever.  Use at your own risk.\n");
++#ifdef SINGLE
++  printf("This executable is compiled for single precision arithmetic.\n\n\n");
++#else
++  printf("This executable is compiled for double precision arithmetic.\n\n\n");
++#endif
++  printf(
++"Show Me graphically displays the contents of geometric files, especially\n");
++  printf(
++"those generated by Triangle, my two-dimensional quality mesh generator and\n"
++);
++  printf(
++"Delaunay triangulator.  Show Me can also write images in PostScript form.\n");
++  printf(
++"Show Me is also useful for checking the consistency of the files you create\n"
++);
++  printf(
++"as input to Triangle; Show Me does these checks more thoroughly than\n");
++  printf("Triangle does.  The command syntax is:\n\n");
++  printf("showme [-bfw_Qh] input_file\n\n");
++  printf(
++"The underscore indicates that a number should follow the -w switch.\n");
++  printf(
++"input_file may be one of several types of file.  It must have extension\n");
++  printf(
++".node, .poly, .ele, .edge, .part, or .adj.  If no extension is provided,\n");
++  printf(
++"Show Me will assume the extension .ele.  A .node file represents a set of\n");
++  printf(
++"points; a .poly file represents a Planar Straight Line Graph; an .ele file\n"
++);
++  printf(
++"(coupled with a .node file) represents the elements of a mesh or the\n");
++  printf(
++"triangles of a triangulation; an .edge file (coupled with a .node file)\n");
++  printf(
++"represents a set of edges; a .part file specifies a partition of a mesh;\n");
++  printf(
++"and a .adj file represents the adjacency graph defined by a partition.\n");
++  printf("\n");
++  printf("Command Line Switches:\n");
++  printf("\n");
++  printf(
++"    -b  Makes all PostScript output black and white.  If this switch is not\n"
++);
++  printf(
++"        selected, color PostScript is used for partitioned meshes and\n");
++  printf("        adjacency graphs (.part and .adj files).\n");
++  printf(
++"    -f  On color displays and in color PostScript, displays partitioned\n");
++  printf(
++"        meshes by filling triangles with color, rather than by coloring the\n"
++);
++  printf(
++"        edges.  This switch will result in a clearer picture if all\n");
++  printf(
++"        triangles are reasonably large, and a less clear picture if small\n");
++  printf(
++"        triangles are present.  (There is also a button to toggle this\n");
++  printf("        behavior.)\n");
++  printf(
++"    -w  Followed by an integer, specifies the line width used in all\n");
++  printf(
++"        images.  (There are also buttons to change the line width.)\n");
++  printf(
++"    -Q  Quiet:  Suppresses all explanation of what Show Me is doing, unless\n"
++);
++  printf("        an error occurs.\n");
++  printf("    -h  Help:  Displays these instructions.\n");
++  printf("\n");
++  printf("Controls:\n");
++  printf("\n");
++  printf(
++"  To zoom in on an image, point at the location where you want a closer\n");
++  printf(
++"  look, and click the left mouse button.  To zoom out, click the right\n");
++  printf(
++"  mouse button.  In either case, the point you click on will be centered in\n"
++);
++  printf(
++"  the window.  If you want to know the coordinates of a point, click the\n");
++  printf(
++"  middle mouse button; the coordinates will be printed on the terminal you\n"
++);
++  printf("  invoked Show Me from.\n\n");
++  printf(
++"  If you resize the window, the image will grow or shrink to match.\n");
++  printf("\n");
++  printf(
++"  There is a panel of control buttons at the bottom of the Show Me window:\n"
++);
++  printf("\n");
++  printf("  Quit:  Shuts down Show Me.\n");
++  printf("  <, >, ^, v:  Moves the image in the indicated direction.\n");
++  printf(
++"  Reset: Unzooms and centers the image in the window.  When you switch from\n"
++);
++  printf(
++"    one image to another, the viewing region does not change, so you may\n");
++  printf(
++"    need to reset the new image to make it fully visible.  This often is\n");
++  printf(
++"    the case when switching between Delaunay triangulations and their\n");
++  printf(
++"    corresponding Voronoi diagrams, as Voronoi vertices can be far from the\n"
++);
++  printf("    initial point set.\n");
++  printf(
++"  Width+, -:  Increases or decreases the width of all lines and points.\n");
++  printf(
++"  Exp, +, -:  These buttons appear only when you are viewing a partitioned\n"
++);
++  printf(
++"    mesh (.part file).  `Exp' toggles between an exploded and non-exploded\n"
++);
++  printf(
++"    image of the mesh.  The non-exploded image will not show the partition\n"
++);
++  printf(
++"    on a black and white monitor.  `+' and `-' allow you to adjust the\n");
++  printf(
++"    spacing between pieces of the mesh to better distinguish them.\n");
++  printf(
++"  Fill:  This button appears only when you are viewing a partitioned mesh\n");
++  printf(
++"    (.part file).  It toggles between color-filled triangles and colored\n");
++  printf(
++"    edges (as the -f switch does).  Filled triangles look better when all\n");
++  printf(
++"    triangles are reasonably large; colored edges look better when there\n");
++  printf("    are very small triangles present.\n");
++  printf(
++"  PS:  Creates a PostScript file containing the image you are viewing.  If\n"
++);
++  printf(
++"    the -b switch is selected, all PostScript output will be black and\n");
++  printf(
++"    white; otherwise, .part.ps and .adj.ps files will be color, independent\n"
++);
++  printf(
++"    of whether you are using a color monitor.  Normally the output will\n");
++  printf(
++"    preserve the properties of the image you see on the screen, including\n");
++  printf(
++"    zoom and line width; however, if black and white output is selected (-b\n"
++);
++  printf(
++"    switch), partitioned meshes will always be drawn exploded.  The output\n"
++);
++  printf(
++"    file name depends on the image being viewed.  If you want several\n");
++  printf(
++"    different snapshots (zooming in on different parts) of the same object,\n"
++);
++  printf(
++"    you'll have to rename each file after Show Me creates it so that it\n");
++  printf("    isn't overwritten by the next snapshot.\n");
++  printf(
++"  EPS:  Creates an encapsulated PostScript file, suitable for inclusion in\n"
++);
++  printf(
++"    documents.  Otherwise, this button is just like the PS button.  (The\n");
++  printf(
++"    main difference is that .eps files lack a `showpage' command at the\n");
++  printf("    end.)\n\n");
++  printf(
++"  There are two nearly-identical rows of buttons that load different images\n"
++);
++  printf("  from disk.  Each row contains the following buttons:\n\n");
++  printf("  node:  Loads a .node file.\n");
++  printf(
++"  poly:  Loads a .poly file (and possibly an associated .node file).\n");
++  printf("  ele:  Loads an .ele file (and associated .node file).\n");
++  printf("  edge:  Loads an .edge file (and associated .node file).\n");
++  printf(
++"  part:  Loads a .part file (and associated .node and .ele files).\n");
++  printf(
++"  adj:  Loads an .adj file (and associated .node, .ele, and .part files).\n");
++  printf("  voro:  Loads a .v.node and .v.edge file for a Voronoi diagram.\n");
++  printf("\n");
++  printf(
++"  Each row represents a different iteration number of the geometry files.\n");
++  printf(
++"  For a full explanation of iteration numbers, read the instructions for\n");
++  printf(
++"  Triangle.  Briefly, iteration numbers are used to allow a user to easily\n"
++);
++  printf(
++"  represent a sequence of related triangulations.  Iteration numbers are\n");
++  printf(
++"  used in the names of geometry files; for instance, mymesh.3.ele is a\n");
++  printf(
++"  triangle file with iteration number three, and mymesh.ele has an implicit\n"
++);
++  printf("  iteration number of zero.\n\n");
++  printf(
++"  The control buttons at the right end of each row display the two\n");
++  printf(
++"  iterations currently under view.  These buttons can be clicked to\n");
++  printf(
++"  increase or decrease the iteration numbers, and thus conveniently view\n");
++  printf("  a sequence of meshes.\n\n");
++  printf(
++"  Show Me keeps each file in memory after loading it, but you can force\n");
++  printf(
++"  Show Me to reread a set of files (for one iteration number) by reclicking\n"
++);
++  printf(
++"  the button that corresponds to the current image.  This is convenient if\n"
++);
++  printf("  you have changed a geometry file.\n\n");
++  printf("File Formats:\n\n");
++  printf(
++"  All files may contain comments prefixed by the character '#'.  Points,\n");
++  printf(
++"  segments, holes, triangles, edges, and subdomains must be numbered\n");
++  printf(
++"  consecutively, starting from either 1 or 0.  Whichever you choose, all\n");
++  printf(
++"  input files must be consistent (for any single iteration number); if the\n"
++);
++  printf(
++"  nodes are numbered from 1, so must be all other objects.  Show Me\n");
++  printf(
++"  automatically detects your choice while reading a .node (or .poly) file.\n"
++);
++  printf("  Examples of these file formats are given below.\n\n");
++  printf("  .node files:\n");
++  printf(
++"    First line:  <# of points> <dimension (must be 2)> <# of attributes>\n");
++  printf(
++"                                           <# of boundary markers (0 or 1)>\n"
++);
++  printf(
++"    Remaining lines:  <point #> <x> <y> [attributes] [boundary marker]\n");
++  printf("\n");
++  printf(
++"    The attributes, which are typically floating-point values of physical\n");
++  printf(
++"    quantities (such as mass or conductivity) associated with the nodes of\n"
++);
++  printf(
++"    a finite element mesh, are ignored by Show Me.  Show Me also ignores\n");
++  printf(
++"    boundary markers.  See the instructions for Triangle to find out what\n");
++  printf("    attributes and boundary markers are.\n\n");
++  printf("  .poly files:\n");
++  printf(
++"    First line:  <# of points> <dimension (must be 2)> <# of attributes>\n");
++  printf(
++"                                           <# of boundary markers (0 or 1)>\n"
++);
++  printf(
++"    Following lines:  <point #> <x> <y> [attributes] [boundary marker]\n");
++  printf("    One line:  <# of segments> <# of boundary markers (0 or 1)>\n");
++  printf(
++"    Following lines:  <segment #> <endpoint> <endpoint> [boundary marker]\n");
++  printf("    One line:  <# of holes>\n");
++  printf("    Following lines:  <hole #> <x> <y>\n");
++  printf("    [Optional additional lines that are ignored]\n\n");
++  printf(
++"    A .poly file represents a Planar Straight Line Graph (PSLG), an idea\n");
++  printf(
++"    familiar to computational geometers.  By definition, a PSLG is just a\n");
++  printf(
++"    list of points and edges.  A .poly file also contains some additional\n");
++  printf("    information.\n\n");
++  printf(
++"    The first section lists all the points, and is identical to the format\n"
++);
++  printf(
++"    of .node files.  <# of points> may be set to zero to indicate that the\n"
++);
++  printf(
++"    points are listed in a separate .node file; .poly files produced by\n");
++  printf(
++"    Triangle always have this format.  When Show Me reads such a file, it\n");
++  printf("    also reads the corresponding .node file.\n\n");
++  printf(
++"    The second section lists the segments.  Segments are edges whose\n");
++  printf(
++"    presence in a triangulation produced from the PSLG is enforced.  Each\n");
++  printf(
++"    segment is specified by listing the indices of its two endpoints.  This\n"
++);
++  printf(
++"    means that its endpoints must be included in the point list.  Each\n");
++  printf(
++"    segment, like each point, may have a boundary marker, which is ignored\n"
++);
++  printf("    by Show Me.\n\n");
++  printf(
++"    The third section lists holes and concavities that are desired in any\n");
++  printf(
++"    triangulation generated from the PSLG.  Holes are specified by\n");
++  printf("    identifying a point inside each hole.\n\n");
++  printf("  .ele files:\n");
++  printf(
++"    First line:  <# of triangles> <points per triangle> <# of attributes>\n");
++  printf(
++"    Remaining lines:  <triangle #> <point> <point> <point> ... [attributes]\n"
++);
++  printf("\n");
++  printf(
++"    Points are indices into the corresponding .node file.  Show Me ignores\n"
++);
++  printf(
++"    all but the first three points of each triangle; these should be the\n");
++  printf(
++"    corners listed in counterclockwise order around the triangle.  The\n");
++  printf("    attributes are ignored by Show Me.\n\n");
++  printf("  .edge files:\n");
++  printf("    First line:  <# of edges> <# of boundary markers (0 or 1)>\n");
++  printf(
++"    Following lines:  <edge #> <endpoint> <endpoint> [boundary marker]\n");
++  printf("\n");
++  printf(
++"    Endpoints are indices into the corresponding .node file.  The boundary\n"
++);
++  printf("    markers are ignored by Show Me.\n\n");
++  printf(
++"    In Voronoi diagrams, one also finds a special kind of edge that is an\n");
++  printf(
++"    infinite ray with only one endpoint.  For these edges, a different\n");
++  printf("    format is used:\n\n");
++  printf("        <edge #> <endpoint> -1 <direction x> <direction y>\n\n");
++  printf(
++"    The `direction' is a floating-point vector that indicates the direction\n"
++);
++  printf("    of the infinite ray.\n\n");
++  printf("  .part files:\n");
++  printf("    First line:  <# of triangles> <# of subdomains>\n");
++  printf("    Remaining lines:  <triangle #> <subdomain #>\n\n");
++  printf(
++"    The set of triangles is partitioned by a .part file; each triangle is\n");
++  printf("    mapped to a subdomain.\n\n");
++  printf("  .adj files:\n");
++  printf("    First line:  <# of subdomains>\n");
++  printf("    Remaining lines:  <adjacency matrix entry>\n\n");
++  printf(
++"    An .adj file represents adjacencies between subdomains (presumably\n");
++  printf("    computed by a partitioner).  The first line is followed by\n");
++  printf(
++"    (subdomains X subdomains) lines, each containing one entry of the\n");
++  printf(
++"    adjacency matrix.  A nonzero entry indicates that two subdomains are\n");
++  printf("    adjacent (share a point).\n\n");
++  printf("Example:\n\n");
++  printf(
++"  Here is a sample file `box.poly' describing a square with a square hole:\n"
++);
++  printf("\n");
++  printf(
++"    # A box with eight points in 2D, no attributes, no boundary marker.\n");
++  printf("    8 2 0 0\n");
++  printf("    # Outer box has these vertices:\n");
++  printf("     1   0 0\n");
++  printf("     2   0 3\n");
++  printf("     3   3 0\n");
++  printf("     4   3 3\n");
++  printf("    # Inner square has these vertices:\n");
++  printf("     5   1 1\n");
++  printf("     6   1 2\n");
++  printf("     7   2 1\n");
++  printf("     8   2 2\n");
++  printf("    # Five segments without boundary markers.\n");
++  printf("    5 0\n");
++  printf("     1   1 2          # Left side of outer box.\n");
++  printf("     2   5 7          # Segments 2 through 5 enclose the hole.\n");
++  printf("     3   7 8\n");
++  printf("     4   8 6\n");
++  printf("     5   6 5\n");
++  printf("    # One hole in the middle of the inner square.\n");
++  printf("    1\n");
++  printf("     1   1.5 1.5\n\n");
++  printf(
++"  After this PSLG is triangulated by Triangle, the resulting triangulation\n"
++);
++  printf(
++"  consists of a .node and .ele file.  Here is the former, `box.1.node',\n");
++  printf("  which duplicates the points of the PSLG:\n\n");
++  printf("    8  2  0  0\n");
++  printf("       1    0  0\n");
++  printf("       2    0  3\n");
++  printf("       3    3  0\n");
++  printf("       4    3  3\n");
++  printf("       5    1  1\n");
++  printf("       6    1  2\n");
++  printf("       7    2  1\n");
++  printf("       8    2  2\n");
++  printf("    # Generated by triangle -pcBev box\n");
++  printf("\n");
++  printf("  Here is the triangulation file, `box.1.ele'.\n");
++  printf("\n");
++  printf("    8  3  0\n");
++  printf("       1       1     5     6\n");
++  printf("       2       5     1     3\n");
++  printf("       3       2     6     8\n");
++  printf("       4       6     2     1\n");
++  printf("       5       7     3     4\n");
++  printf("       6       3     7     5\n");
++  printf("       7       8     4     2\n");
++  printf("       8       4     8     7\n");
++  printf("    # Generated by triangle -pcBev box\n\n");
++  printf("  Here is the edge file for the triangulation, `box.1.edge'.\n\n");
++  printf("    16  0\n");
++  printf("       1   1  5\n");
++  printf("       2   5  6\n");
++  printf("       3   6  1\n");
++  printf("       4   1  3\n");
++  printf("       5   3  5\n");
++  printf("       6   2  6\n");
++  printf("       7   6  8\n");
++  printf("       8   8  2\n");
++  printf("       9   2  1\n");
++  printf("      10   7  3\n");
++  printf("      11   3  4\n");
++  printf("      12   4  7\n");
++  printf("      13   7  5\n");
++  printf("      14   8  4\n");
++  printf("      15   4  2\n");
++  printf("      16   8  7\n");
++  printf("    # Generated by triangle -pcBev box\n");
++  printf("\n");
++  printf(
++"  Here's a file `box.1.part' that partitions the mesh into four subdomains.\n"
++);
++  printf("\n");
++  printf("    8  4\n");
++  printf("       1    3\n");
++  printf("       2    3\n");
++  printf("       3    4\n");
++  printf("       4    4\n");
++  printf("       5    1\n");
++  printf("       6    1\n");
++  printf("       7    2\n");
++  printf("       8    2\n");
++  printf("    # Generated by slice -s4 box.1\n\n");
++  printf(
++"  Here's a file `box.1.adj' that represents the resulting adjacencies.\n");
++  printf("\n");
++  printf("    4\n");
++  printf("      9\n");
++  printf("      2\n");
++  printf("      2\n");
++  printf("      0\n");
++  printf("      2\n");
++  printf("      9\n");
++  printf("      0\n");
++  printf("      2\n");
++  printf("      2\n");
++  printf("      0\n");
++  printf("      9\n");
++  printf("      2\n");
++  printf("      0\n");
++  printf("      2\n");
++  printf("      2\n");
++  printf("      9\n");
++  printf("\n");
++  printf("Display Speed:\n");
++  printf("\n");
++  printf(
++"  It is worthwhile to note that .edge files typically plot and print twice\n"
++);
++  printf(
++"  as quickly as .ele files, because .ele files cause each internal edge to\n"
++);
++  printf(
++"  be drawn twice.  For the same reason, PostScript files created from edge\n"
++);
++  printf("  sets are smaller than those created from triangulations.\n\n");
++  printf("Show Me on the Web:\n\n");
++  printf(
++"  To see an illustrated, updated version of these instructions, check out\n");
++  printf("\n");
++  printf("    http://www.cs.cmu.edu/~quake/showme.html\n");
++  printf("\n");
++  printf("A Brief Plea:\n");
++  printf("\n");
++  printf(
++"  If you use Show Me (or Triangle), and especially if you use it to\n");
++  printf(
++"  accomplish real work, I would like very much to hear from you.  A short\n");
++  printf(
++"  letter or email (to jrs@cs.cmu.edu) describing how you use Show Me (and\n");
++  printf(
++"  its sister programs) will mean a lot to me.  The more people I know\n");
++  printf(
++"  are using my programs, the more easily I can justify spending time on\n");
++  printf(
++"  improvements, which in turn will benefit you.  Also, I can put you\n");
++  printf(
++"  on a list to receive email whenever new versions are available.\n");
++  printf("\n");
++  printf(
++"  If you use a PostScript file generated by Show Me in a publication,\n");
++  printf("  please include an acknowledgment as well.\n\n");
++  exit(0);
++}
++
++void set_filenames(filename, lowermeshnumber)
++char *filename;
++int lowermeshnumber;
++{
++  char numberstring[100];
++  int i;
++
++  for (i = 0; i < 2; i++) {
++    strcpy(nodefilename[i], filename);
++    strcpy(polyfilename[i], filename);
++    strcpy(elefilename[i], filename);
++    strcpy(edgefilename[i], filename);
++    strcpy(partfilename[i], filename);
++    strcpy(adjfilename[i], filename);
++    strcpy(vnodefilename[i], filename);
++    strcpy(vedgefilename[i], filename);
++
++    if (lowermeshnumber + i > 0) {
++      sprintf(numberstring, ".%d", lowermeshnumber + i);
++      strcat(nodefilename[i], numberstring);
++      strcat(polyfilename[i], numberstring);
++      strcat(elefilename[i], numberstring);
++      strcat(edgefilename[i], numberstring);
++      strcat(partfilename[i], numberstring);
++      strcat(adjfilename[i], numberstring);
++      strcat(vnodefilename[i], numberstring);
++      strcat(vedgefilename[i], numberstring);
++    }
++
++    strcat(nodefilename[i], ".node");
++    strcat(polyfilename[i], ".poly");
++    strcat(elefilename[i], ".ele");
++    strcat(edgefilename[i], ".edge");
++    strcat(partfilename[i], ".part");
++    strcat(adjfilename[i], ".adj");
++    strcat(vnodefilename[i], ".v.node");
++    strcat(vedgefilename[i], ".v.edge");
++  }
++}
++
++void parsecommandline(argc, argv)
++int argc;
++char **argv;
++{
++  int increment;
++  int meshnumber;
++  int i, j;
++
++  quiet = 0;
++  fillelem = 0;
++  line_width = 1;
++  bw_ps = 0;
++  start_image = ELE;
++  filename[0] = '\0';
++  for (i = 1; i < argc; i++) {
++    if (argv[i][0] == '-') {
++      for (j = 1; argv[i][j] != '\0'; j++) {
++        if (argv[i][j] == 'f') {
++          fillelem = 1;
++      }
++        if (argv[i][j] == 'w') {
++          if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '9')) {
++            line_width = 0;
++            while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
++              j++;
++              line_width = line_width * 10 + (int) (argv[i][j] - '0');
++            }
++            if (line_width > 100) {
++              printf("Error:  Line width cannot exceed 100.\n");
++              line_width = 1;
++          }
++        }
++      }
++        if (argv[i][j] == 'b') {
++          bw_ps = 1;
++      }
++        if (argv[i][j] == 'Q') {
++          quiet = 1;
++      }
++        if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
++            (argv[i][j] == '?')) {
++          info();
++      }
++      }
++    } else {
++      strcpy(filename, argv[i]);
++    }
++  }
++  if (filename[0] == '\0') {
++    syntax();
++  }
++  if (!strcmp(&filename[strlen(filename) - 5], ".node")) {
++    filename[strlen(filename) - 5] = '\0';
++    start_image = NODE;
++  }
++  if (!strcmp(&filename[strlen(filename) - 5], ".poly")) {
++    filename[strlen(filename) - 5] = '\0';
++    start_image = POLY;
++  }
++  if (!strcmp(&filename[strlen(filename) - 4], ".ele")) {
++    filename[strlen(filename) - 4] = '\0';
++    start_image = ELE;
++  }
++  if (!strcmp(&filename[strlen(filename) - 5], ".edge")) {
++    filename[strlen(filename) - 5] = '\0';
++    start_image = EDGE;
++  }
++  if (!strcmp(&filename[strlen(filename) - 5], ".part")) {
++    filename[strlen(filename) - 5] = '\0';
++    start_image = PART;
++  }
++  if (!strcmp(&filename[strlen(filename) - 4], ".adj")) {
++    filename[strlen(filename) - 4] = '\0';
++    start_image = ADJ;
++  }
++
++  increment = 0;
++  j = 1;
++  while (filename[j] != '\0') {
++    if ((filename[j] == '.') && (filename[j + 1] != '\0')) {
++      increment = j + 1;
++    }
++    j++;
++  }
++  meshnumber = 0;
++  if (increment > 0) {
++    j = increment;
++    do {
++      if ((filename[j] >= '0') && (filename[j] <= '9')) {
++        meshnumber = meshnumber * 10 + (int) (filename[j] - '0');
++      } else {
++        increment = 0;
++      }
++      j++;
++    } while (filename[j] != '\0');
++  }
++  if (increment > 0) {
++    filename[increment - 1] = '\0';
++  }
++
++  if (meshnumber == 0) {
++    start_inc = 0;
++    loweriteration = 0;
++  } else {
++    start_inc = 1;
++    loweriteration = meshnumber - 1;
++  }
++  set_filenames(filename, loweriteration);
++}
++
++void free_inc(inc)
++int inc;
++{
++  if (loaded[inc][NODE]) {
++    free(nodeptr[inc]);
++  }
++  if (loaded[inc][POLY]) {
++    if (polynodes[inc] > 0) {
++      free(polynodeptr[inc]);
++    }
++    free(polyedgeptr[inc]);
++    free(polyholeptr[inc]);
++  }
++  if (loaded[inc][ELE]) {
++    free(eleptr[inc]);
++  }
++  if (loaded[inc][PART]) {
++    free(partpart[inc]);
++    free(partcenter[inc]);
++    free(partshift[inc]);
++  }
++  if (loaded[inc][EDGE]) {
++    free(edgeptr[inc]);
++    free(normptr[inc]);
++  }
++  if (loaded[inc][ADJ]) {
++    free(adjptr[inc]);
++  }
++  if (loaded[inc][VORO]) {
++    free(vnodeptr[inc]);
++    free(vedgeptr[inc]);
++    free(vnormptr[inc]);
++  }
++}
++
++void move_inc(inc)
++int inc;
++{
++  int i;
++
++  free_inc(1 - inc);
++  for (i = 0; i < IMAGE_TYPES; i++) {
++    loaded[1 - inc][i] = loaded[inc][i];
++    loaded[inc][i] = 0;
++    xlo[1 - inc][i] = xlo[inc][i];
++    ylo[1 - inc][i] = ylo[inc][i];
++    xhi[1 - inc][i] = xhi[inc][i];
++    yhi[1 - inc][i] = yhi[inc][i];
++  }
++  nodes[1 - inc] = nodes[inc];
++  node_dim[1 - inc] = node_dim[inc];
++  nodeptr[1 - inc] = nodeptr[inc];
++  polynodes[1 - inc] = polynodes[inc];
++  poly_dim[1 - inc] = poly_dim[inc];
++  polyedges[1 - inc] = polyedges[inc];
++  polyholes[1 - inc] = polyholes[inc];
++  polynodeptr[1 - inc] = polynodeptr[inc];
++  polyedgeptr[1 - inc] = polyedgeptr[inc];
++  polyholeptr[1 - inc] = polyholeptr[inc];
++  elems[1 - inc] = elems[inc];
++  ele_corners[1 - inc] = ele_corners[inc];
++  eleptr[1 - inc] = eleptr[inc];
++  edges[1 - inc] = edges[inc];
++  edgeptr[1 - inc] = edgeptr[inc];
++  normptr[1 - inc] = normptr[inc];
++  subdomains[1 - inc] = subdomains[inc];
++  partpart[1 - inc] = partpart[inc];
++  partcenter[1 - inc] = partcenter[inc];
++  partshift[1 - inc] = partshift[inc];
++  adjsubdomains[1 - inc] = adjsubdomains[inc];
++  adjptr[1 - inc] = adjptr[inc];
++  vnodes[1 - inc] = vnodes[inc];
++  vnode_dim[1 - inc] = vnode_dim[inc];
++  vnodeptr[1 - inc] = vnodeptr[inc];
++  vedges[1 - inc] = vedges[inc];
++  vedgeptr[1 - inc] = vedgeptr[inc];
++  vnormptr[1 - inc] = vnormptr[inc];
++  firstnumber[1 - inc] = firstnumber[inc];
++  firstnumber[inc] = -1;
++}
++
++void unload_inc(inc)
++int inc;
++{
++  int i;
++
++  current_image = NOTHING;
++  for (i = 0; i < IMAGE_TYPES; i++) {
++    loaded[inc][i] = 0;
++    firstnumber[inc] = -1;
++  }
++}
++
++void showme_init()
++{
++  current_image = NOTHING;
++  current_inc = 0;
++  explosion = STARTEXPLOSION;
++  unload_inc(0);
++  unload_inc(1);
++}
++
++char *readline(string, infile, infilename)
++char *string;
++FILE *infile;
++char *infilename;
++{
++  char *result;
++
++  do {
++    result = fgets(string, INPUTLINESIZE, infile);
++    if (result == (char *) NULL) {
++      printf("  Error:  Unexpected end of file in %s.\n",
++             infilename);
++      exit(1);
++    }
++    while ((*result != '\0') && (*result != '#')
++           && (*result != '.') && (*result != '+') && (*result != '-')
++           && ((*result < '0') || (*result > '9'))) {
++      result++;
++    }
++  } while ((*result == '#') || (*result == '\0'));
++  return result;
++}
++
++char *findfield(string)
++char *string;
++{
++  char *result;
++
++  result = string;
++  while ((*result != '\0') && (*result != '#')
++         && (*result != ' ') && (*result != '\t')) {
++    result++;
++  }
++  while ((*result != '\0') && (*result != '#')
++         && (*result != '.') && (*result != '+') && (*result != '-')
++         && ((*result < '0') || (*result > '9'))) {
++    result++;
++  }
++  if (*result == '#') {
++    *result = '\0';
++  }
++  return result;
++}
++
++int load_node(fname, firstnumber, nodes, dim, ptr, xmin, ymin, xmax, ymax)
++char *fname;
++int *firstnumber;
++int *nodes;
++int *dim;
++REAL **ptr;
++REAL *xmin;
++REAL *ymin;
++REAL *xmax;
++REAL *ymax;
++{
++  FILE *infile;
++  char inputline[INPUTLINESIZE];
++  char *stringptr;
++  int extras;
++  int nodemarks;
++  int index;
++  int nodenumber;
++  int i, j;
++  int smallerr;
++  REAL x, y;
++
++  *xmin = *ymin = 0.0;
++  *xmax = *ymax = 1.0;
++  if (!quiet) {
++    printf("Opening %s.\n", fname);
++  }
++  infile = fopen(fname, "r");
++  if (infile == (FILE *) NULL) {
++    printf("  Error:  Cannot access file %s.\n", fname);
++    return 1;
++  }
++  stringptr = readline(inputline, infile, fname);
++  *nodes = (int) strtol (stringptr, &stringptr, 0);
++  if (*nodes < 3) {
++    printf("  Error:  %s contains %d points.\n", fname, *nodes);
++    return 1;
++  }
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    *dim = 2;
++  } else {
++    *dim = (int) strtol (stringptr, &stringptr, 0);
++  }
++  if (*dim < 1) {
++    printf("  Error:  %s has dimensionality %d.\n", fname, *dim);
++    return 1;
++  }
++  if (*dim != 2) {
++    printf("  I only understand two-dimensional meshes.\n");
++    return 1;
++  }
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    extras = 0;
++  } else {
++    extras = (int) strtol (stringptr, &stringptr, 0);
++  }
++  if (extras < 0) {
++    printf("  Error:  %s has negative value for number of attributes.\n",
++           fname);
++    return 1;
++  }
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    nodemarks = 0;
++  } else {
++    nodemarks = (int) strtol (stringptr, &stringptr, 0);
++  }
++  if (nodemarks < 0) {
++    printf("  Warning:  %s has negative value for number of point markers.\n",
++           fname);
++  }
++  if (nodemarks > 1) {
++    printf(
++   "  Warning:  %s has value greater than one for number of point markers.\n",
++           fname);
++  }
++  *ptr = (REAL *) malloc((*nodes + 1) * *dim * sizeof(REAL));
++  if (*ptr == (REAL *) NULL) {
++    printf("  Out of memory.\n");
++    return 1;
++  }
++  index = *dim;
++  smallerr = 1;
++  for (i = 0; i < *nodes; i++) {
++    stringptr = readline(inputline, infile, fname);
++    nodenumber = (int) strtol (stringptr, &stringptr, 0);
++    if ((i == 0) && (*firstnumber == -1)) {
++      if (nodenumber == 0) {
++        *firstnumber = 0;
++      } else {
++        *firstnumber = 1;
++      }
++    }
++    if ((nodenumber != *firstnumber + i) && (smallerr)) {
++      printf("  Warning:  Points in %s are not numbered correctly\n", fname);
++      printf("            (starting with point %d).\n", *firstnumber + i);
++      smallerr = 0;
++    }
++    for (j = 0; j < *dim; j++) {
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        printf("Error:  Point %d is missing a coordinate in %s.\n",
++               *firstnumber + i, fname);
++        free(*ptr);
++        return 1;
++      }
++      (*ptr)[index++] = (REAL) strtod(stringptr, &stringptr);
++    }
++  }
++  fclose(infile);
++  index = *dim;
++  *xmin = *xmax = (*ptr)[index];
++  *ymin = *ymax = (*ptr)[index + 1];
++  for (i = 2; i <= *nodes; i++) {
++    index += *dim;
++    x = (*ptr)[index];
++    y = (*ptr)[index + 1];
++    if (x < *xmin) {
++      *xmin = x;
++    }
++    if (y < *ymin) {
++      *ymin = y;
++    }
++    if (x > *xmax) {
++      *xmax = x;
++    }
++    if (y > *ymax) {
++      *ymax = y;
++    }
++  }
++  if (*xmin == *xmax) {
++    *xmin -= 0.5;
++    *xmax += 0.5;
++  }
++  if (*ymin == *ymax) {
++    *ymin -= 0.5;
++    *ymax += 0.5;
++  }
++  return 0;
++}
++
++int load_poly(inc, fname, firstnumber, pnodes, dim, edges, holes, nodeptr,
++              edgeptr, holeptr, xmin, ymin, xmax, ymax)
++int inc;
++char *fname;
++int *firstnumber;
++int *pnodes;
++int *dim;
++int *edges;
++int *holes;
++REAL **nodeptr;
++int **edgeptr;
++REAL **holeptr;
++REAL *xmin;
++REAL *ymin;
++REAL *xmax;
++REAL *ymax;
++{
++  FILE *infile;
++  char inputline[INPUTLINESIZE];
++  char *stringptr;
++  int extras;
++  int nodemarks;
++  int segmentmarks;
++  int index;
++  int nodenumber, edgenumber, holenumber;
++  int maxnode;
++  int i, j;
++  int smallerr;
++  REAL x, y;
++
++  if (!quiet) {
++    printf("Opening %s.\n", fname);
++  }
++  infile = fopen(fname, "r");
++  if (infile == (FILE *) NULL) {
++    printf("  Error:  Cannot access file %s.\n", fname);
++    return 1;
++  }
++  stringptr = readline(inputline, infile, fname);
++  *pnodes = (int) strtol (stringptr, &stringptr, 0);
++  if (*pnodes == 0) {
++    if (!loaded[inc][NODE]) {
++      if (load_image(inc, NODE)) {
++        return 1;
++      }
++    }
++    maxnode = nodes[inc];
++    *xmin = xlo[inc][NODE];
++    *ymin = ylo[inc][NODE];
++    *xmax = xhi[inc][NODE];
++    *ymax = yhi[inc][NODE];
++  } else {
++    if (*pnodes < 1) {
++      printf("  Error:  %s contains %d points.\n", fname, *pnodes);
++      return 1;
++    }
++    maxnode = *pnodes;
++  }
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    *dim = 2;
++  } else {
++    *dim = (int) strtol (stringptr, &stringptr, 0);
++  }
++  if (*dim < 1) {
++    printf("  Error:  %s has dimensionality %d.\n", fname, *dim);
++    return 1;
++  }
++  if (*dim != 2) {
++    printf("  I only understand two-dimensional meshes.\n");
++    return 1;
++  }
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    extras = 0;
++  } else {
++    extras = (int) strtol (stringptr, &stringptr, 0);
++  }
++  if (extras < 0) {
++    printf("  Error:  %s has negative value for number of attributes.\n",
++           fname);
++    return 1;
++  }
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    nodemarks = 0;
++  } else {
++    nodemarks = (int) strtol (stringptr, &stringptr, 0);
++  }
++  if (nodemarks < 0) {
++    printf("  Warning:  %s has negative value for number of point markers.\n",
++           fname);
++  }
++  if (nodemarks > 1) {
++    printf(
++   "  Warning:  %s has value greater than one for number of point markers.\n",
++           fname);
++  }
++  if (*pnodes > 0) {
++    *nodeptr = (REAL *) malloc((*pnodes + 1) * *dim * sizeof(REAL));
++    if (*nodeptr == (REAL *) NULL) {
++      printf("  Out of memory.\n");
++      return 1;
++    }
++    index = *dim;
++    smallerr = 1;
++    for (i = 0; i < *pnodes; i++) {
++      stringptr = readline(inputline, infile, fname);
++      nodenumber = (int) strtol (stringptr, &stringptr, 0);
++      if ((i == 0) && (*firstnumber == -1)) {
++        if (nodenumber == 0) {
++          *firstnumber = 0;
++        } else {
++          *firstnumber = 1;
++        }
++      }
++      if ((nodenumber != *firstnumber + i) && (smallerr)) {
++        printf("  Warning:  Points in %s are not numbered correctly.\n",
++               fname);
++        printf("            (starting with point %d).\n", *firstnumber + i);
++        smallerr = 0;
++      }
++      for (j = 0; j < *dim; j++) {
++        stringptr = findfield(stringptr);
++        if (*stringptr == '\0') {
++          printf("Error:  Point %d is missing a coordinate in %s.\n",
++                 *firstnumber + i, fname);
++          free(*nodeptr);
++          return 1;
++        }
++        (*nodeptr)[index++] = (REAL) strtod(stringptr, &stringptr);
++      }
++    }
++  }
++  stringptr = readline(inputline, infile, fname);
++  *edges = (int) strtol (stringptr, &stringptr, 0);
++  if (*edges < 0) {
++    printf("  Error:  %s contains %d segments.\n", fname, *edges);
++    free(*nodeptr);
++    return 1;
++  }
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    segmentmarks = 0;
++  } else {
++    segmentmarks = (int) strtol (stringptr, &stringptr, 0);
++  }
++  if (segmentmarks < 0) {
++    printf("  Error:  %s has negative value for number of segment markers.\n",
++           fname);
++    free(*nodeptr);
++    return 1;
++  }
++  if (segmentmarks > 1) {
++    printf(
++   "  Error:  %s has value greater than one for number of segment markers.\n",
++           fname);
++    free(*nodeptr);
++    return 1;
++  }
++  *edgeptr = (int *) malloc(((*edges + 1) << 1) * sizeof(int));
++  if (*edgeptr == (int *) NULL) {
++    printf("  Out of memory.\n");
++    free(*nodeptr);
++    return 1;
++  }
++  index = 2;
++  smallerr = 1;
++  for (i = *firstnumber; i < *firstnumber + *edges; i++) {
++    stringptr = readline(inputline, infile, fname);
++    edgenumber = (int) strtol (stringptr, &stringptr, 0);
++    if ((edgenumber != i) && (smallerr)) {
++      printf("  Warning:  Segments in %s are not numbered correctly.\n",
++             fname);
++      printf("            (starting with segment %d).\n", i);
++      smallerr = 0;
++    }
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      printf("Error:  Segment %d is missing its endpoints in %s.\n", i, fname);
++      free(*nodeptr);
++      free(*edgeptr);
++      return 1;
++    }
++    (*edgeptr)[index] = (int) strtol (stringptr, &stringptr, 0) + 1 -
++                        *firstnumber;
++    if (((*edgeptr)[index] < 1) || ((*edgeptr)[index] > maxnode)) {
++      printf("Error:  Segment %d has invalid endpoint in %s.\n", i, fname);
++      return 1;
++    }
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      printf("Error:  Segment %d is missing an endpoint in %s.\n", i, fname);
++      free(*nodeptr);
++      free(*edgeptr);
++      return 1;
++    }
++    (*edgeptr)[index + 1] = (int) strtol (stringptr, &stringptr, 0) + 1 -
++                            *firstnumber;
++    if (((*edgeptr)[index + 1] < 1) || ((*edgeptr)[index + 1] > maxnode)) {
++      printf("Error:  Segment %d has invalid endpoint in %s.\n", i, fname);
++      return 1;
++    }
++    index += 2;
++  }
++  stringptr = readline(inputline, infile, fname);
++  *holes = (int) strtol (stringptr, &stringptr, 0);
++  if (*holes < 0) {
++    printf("  Error:  %s contains %d holes.\n", fname, *holes);
++    free(*nodeptr);
++    free(*edgeptr);
++    return 1;
++  }
++  *holeptr = (REAL *) malloc((*holes + 1) * *dim * sizeof(REAL));
++  if (*holeptr == (REAL *) NULL) {
++    printf("  Out of memory.\n");
++    free(*nodeptr);
++    free(*edgeptr);
++    return 1;
++  }
++  index = *dim;
++  smallerr = 1;
++  for (i = *firstnumber; i < *firstnumber + *holes; i++) {
++    stringptr = readline(inputline, infile, fname);
++    holenumber = (int) strtol (stringptr, &stringptr, 0);
++    if ((holenumber != i) && (smallerr)) {
++      printf("  Warning:  Holes in %s are not numbered correctly.\n", fname);
++      printf("            (starting with hole %d).\n", i);
++      smallerr = 0;
++    }
++    for (j = 0; j < *dim; j++) {
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        printf("Error:  Hole %d is missing a coordinate in %s.\n", i,
++               fname);
++        free(*nodeptr);
++        free(*edgeptr);
++        free(*holeptr);
++        return 1;
++      }
++      (*holeptr)[index++] = (REAL) strtod(stringptr, &stringptr);
++    }
++  }
++  fclose(infile);
++  if (*pnodes > 0) {
++    index = *dim;
++    *xmin = *xmax = (*nodeptr)[index];
++    *ymin = *ymax = (*nodeptr)[index + 1];
++    for (i = 2; i <= *pnodes; i++) {
++      index += *dim;
++      x = (*nodeptr)[index];
++      y = (*nodeptr)[index + 1];
++      if (x < *xmin) {
++        *xmin = x;
++      }
++      if (y < *ymin) {
++        *ymin = y;
++      }
++      if (x > *xmax) {
++        *xmax = x;
++      }
++      if (y > *ymax) {
++        *ymax = y;
++      }
++    }
++  }
++  index = *dim;
++  for (i = 1; i <= *holes; i++) {
++    x = (*holeptr)[index];
++    y = (*holeptr)[index + 1];
++    if (x < *xmin) {
++      *xmin = x;
++    }
++    if (y < *ymin) {
++      *ymin = y;
++    }
++    if (x > *xmax) {
++      *xmax = x;
++    }
++    if (y > *ymax) {
++      *ymax = y;
++    }
++    index += *dim;
++  }
++  return 0;
++}
++
++int load_ele(fname, firstnumber, nodes, elems, corners, ptr)
++char *fname;
++int firstnumber;
++int nodes;
++int *elems;
++int *corners;
++int **ptr;
++{
++  FILE *infile;
++  char inputline[INPUTLINESIZE];
++  char *stringptr;
++  int extras;
++  int index;
++  int elemnumber;
++  int i, j;
++  int smallerr;
++
++  if (!quiet) {
++    printf("Opening %s.\n", fname);
++  }
++  infile = fopen(fname, "r");
++  if (infile == (FILE *) NULL) {
++    printf("  Error:  Cannot access file %s.\n", fname);
++    return 1;
++  }
++  stringptr = readline(inputline, infile, fname);
++  *elems = (int) strtol (stringptr, &stringptr, 0);
++  if (*elems < 1) {
++    printf("  Error:  %s contains %d triangles.\n", fname, *elems);
++    return 1;
++  }
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    *corners = 3;
++  } else {
++    *corners = (int) strtol (stringptr, &stringptr, 0);
++  }
++  if (*corners < 3) {
++    printf("  Error:  Triangles in %s have only %d corners.\n", fname,
++           *corners);
++    return 1;
++  }
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    extras = 0;
++  } else {
++    extras = (int) strtol (stringptr, &stringptr, 0);
++  }
++  if (extras < 0) {
++    printf("  Error:  %s has negative value for extra fields.\n", fname);
++    return 1;
++  }
++  *ptr = (int *) malloc((*elems + 1) * 3 * sizeof(int));
++  if (*ptr == (int *) NULL) {
++    printf("  Out of memory.\n");
++    return 1;
++  }
++  index = 3;
++  smallerr = 1;
++  for (i = firstnumber; i < firstnumber + *elems; i++) {
++    stringptr = readline(inputline, infile, fname);
++    elemnumber = (int) strtol (stringptr, &stringptr, 0);
++    if ((elemnumber != i) && (smallerr)) {
++      printf("  Warning:  Triangles in %s are not numbered correctly.\n",
++             fname);
++      printf("            (starting with triangle %d).\n", i);
++      smallerr = 0;
++    }
++    for (j = 0; j < 3; j++) {
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        printf("Error:  Triangle %d is missing a corner in %s.\n", i, fname);
++        free(*ptr);
++        return 1;
++      }
++      (*ptr)[index] = (int) strtol (stringptr, &stringptr, 0) + 1 -
++                      firstnumber;
++      if (((*ptr)[index] < 1) || ((*ptr)[index] > nodes)) {
++        printf("Error:  Triangle %d has invalid corner in %s.\n", i, fname);
++        return 1;
++      }
++      index++;
++    }
++  }
++  fclose(infile);
++  return 0;
++}
++
++int load_edge(fname, firstnumber, nodes, edges, edgeptr, normptr)
++char *fname;
++int firstnumber;
++int nodes;
++int *edges;
++int **edgeptr;
++REAL **normptr;
++{
++  FILE *infile;
++  char inputline[INPUTLINESIZE];
++  char *stringptr;
++  int index;
++  int edgenumber;
++  int edgemarks;
++  int i;
++  int smallerr;
++
++  if (!quiet) {
++    printf("Opening %s.\n", fname);
++  }
++  infile = fopen(fname, "r");
++    if (infile == (FILE *) NULL) {
++      printf("  Error:  Cannot access file %s.\n", fname);
++      return 1;
++    }
++  stringptr = readline(inputline, infile, fname);
++  *edges = (int) strtol (stringptr, &stringptr, 0);
++  if (*edges < 1) {
++    printf("  Error:  %s contains %d edges.\n", fname, *edges);
++    return 1;
++  }
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    edgemarks = 0;
++  } else {
++    edgemarks = (int) strtol (stringptr, &stringptr, 0);
++  }
++  if (edgemarks < 0) {
++    printf("  Error:  %s has negative value for number of edge markers.\n",
++           fname);
++    return 1;
++  }
++  if (edgemarks > 1) {
++    printf(
++   "  Error:  %s has value greater than one for number of edge markers.\n",
++           fname);
++    return 1;
++  }
++  *edgeptr = (int *) malloc(((*edges + 1) << 1) * sizeof(int));
++  if (*edgeptr == (int *) NULL) {
++    printf("  Out of memory.\n");
++    return 1;
++  }
++  *normptr = (REAL *) malloc(((*edges + 1) << 1) * sizeof(REAL));
++  if (*normptr == (REAL *) NULL) {
++    printf("  Out of memory.\n");
++    free(*edgeptr);
++    return 1;
++  }
++  index = 2;
++  smallerr = 1;
++  for (i = firstnumber; i < firstnumber + *edges; i++) {
++    stringptr = readline(inputline, infile, fname);
++    edgenumber = (int) strtol (stringptr, &stringptr, 0);
++    if ((edgenumber != i) && (smallerr)) {
++      printf("  Warning:  Edges in %s are not numbered correctly.\n", fname);
++      printf("            (starting with edge %d).\n", i);
++      smallerr = 0;
++    }
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      printf("Error:  Edge %d is missing its endpoints in %s.\n", i, fname);
++      free(*edgeptr);
++      free(*normptr);
++      return 1;
++    }
++    (*edgeptr)[index] = (int) strtol (stringptr, &stringptr, 0) + 1 -
++                        firstnumber;
++    if (((*edgeptr)[index] < 1) || ((*edgeptr)[index] > nodes)) {
++      printf("Error:  Edge %d has invalid endpoint in %s.\n", i, fname);
++      return 1;
++    }
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      printf("Error:  Edge %d is missing an endpoint in %s.\n", i, fname);
++      free(*edgeptr);
++      free(*normptr);
++      return 1;
++    }
++    (*edgeptr)[index + 1] = (int) strtol (stringptr, &stringptr, 0);
++    if ((*edgeptr)[index + 1] == -1) {
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        printf("Error:  Edge %d is missing its direction in %s.\n", i, fname);
++        free(*edgeptr);
++        free(*normptr);
++        return 1;
++      }
++      (*normptr)[index] = (REAL) strtod(stringptr, &stringptr);
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        printf("Error:  Edge %d is missing a direction coordinate in %s.\n",
++               i, fname);
++        free(*edgeptr);
++        free(*normptr);
++        return 1;
++      }
++      (*normptr)[index + 1] = (REAL) strtod(stringptr, &stringptr);
++    } else {
++      (*edgeptr)[index + 1] += 1 - firstnumber;
++      if (((*edgeptr)[index + 1] < 1) || ((*edgeptr)[index + 1] > nodes)) {
++        printf("Error:  Edge %d has invalid endpoint in %s.\n", i, fname);
++        return 1;
++      }
++    }
++    index += 2;
++  }
++  fclose(infile);
++  return 0;
++}
++
++int load_part(fname, dim, firstnumber, elems, nodeptr, eleptr, parts,
++              partition, partcenter, partshift)
++char *fname;
++int dim;
++int firstnumber;
++int elems;
++REAL *nodeptr;
++int *eleptr;
++int *parts;
++int **partition;
++REAL **partcenter;
++REAL **partshift;
++{
++  FILE *infile;
++  char inputline[INPUTLINESIZE];
++  char *stringptr;
++  int partelems;
++  int index;
++  int elemnumber;
++  int i, j;
++  int smallerr;
++  int *partsize;
++
++  if (!quiet) {
++    printf("Opening %s.\n", fname);
++  }
++  infile = fopen(fname, "r");
++  if (infile == (FILE *) NULL) {
++    printf("  Error:  Cannot access file %s.\n", fname);
++    return 1;
++  }
++  stringptr = readline(inputline, infile, fname);
++  partelems = (int) strtol (stringptr, &stringptr, 0);
++  if (partelems != elems) {
++    printf(
++      "  Error:  .ele and .part files do not agree on number of triangles.\n");
++    return 1;
++  }
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    *parts = 1;
++  } else {
++    *parts = (int) strtol (stringptr, &stringptr, 0);
++  }
++  if (*parts < 1) {
++    printf("  Error:  %s specifies %d subdomains.\n", fname, *parts);
++    return 1;
++  }
++  *partition = (int *) malloc((elems + 1) * sizeof(int));
++  if (*partition == (int *) NULL) {
++    printf("  Out of memory.\n");
++    return 1;
++  }
++  smallerr = 1;
++  for (i = firstnumber; i < firstnumber + partelems; i++) {
++    stringptr = readline(inputline, infile, fname);
++    elemnumber = (int) strtol (stringptr, &stringptr, 0);
++    if ((elemnumber != i) && (smallerr)) {
++      printf("  Warning:  Triangles in %s are not numbered correctly.\n",
++             fname);
++      printf("            (starting with triangle %d).\n", i);
++      smallerr = 0;
++    }
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      printf("Error:  Triangle %d has no subdomain in %s.\n", i, fname);
++      free(*partition);
++      return 1;
++    }
++    (*partition)[i] = (int) strtol (stringptr, &stringptr, 0) - firstnumber;
++    if (((*partition)[i] >= *parts) || ((*partition)[i] < 0)) {
++      printf("  Error:  Triangle %d of %s has an invalid subdomain.\n",
++             i, fname);
++      free(*partition);
++      return 1;
++    }
++  }
++  fclose(infile);
++  *partcenter = (REAL *) malloc(((*parts + 1) << 1) * sizeof(REAL));
++  if (*partcenter == (REAL *) NULL) {
++    printf("Error:  Out of memory.\n");
++    free(*partition);
++    return 1;
++  }
++  *partshift = (REAL *) malloc((*parts << 1) * sizeof(REAL));
++  if (*partshift == (REAL *) NULL) {
++    printf("Error:  Out of memory.\n");
++    free(*partition);
++    free(*partcenter);
++    return 1;
++  }
++  partsize = (int *) malloc((*parts + 1) * sizeof(int));
++  if (partsize == (int *) NULL) {
++    printf("Error:  Out of memory.\n");
++    free(*partition);
++    free(*partcenter);
++    free(*partshift);
++    return 1;
++  }
++  index = 3;
++  for (i = 0; i <= *parts; i++) {
++    partsize[i] = 0;
++    (*partcenter)[i << 1] = 0.0;
++    (*partcenter)[(i << 1) + 1] = 0.0;
++  }
++  for (i = 1; i <= elems; i++) {
++    partsize[(*partition)[i]] += 3;
++    for (j = 0; j < 3; j++) {
++      (*partcenter)[(*partition)[i] << 1] +=
++                nodeptr[eleptr[index] * dim];
++      (*partcenter)[((*partition)[i] << 1) + 1] +=
++                nodeptr[eleptr[index++] * dim + 1];
++    }
++  }
++  for (i = 0; i < *parts; i++) {
++    (*partcenter)[i << 1] /= (REAL) partsize[i];
++    (*partcenter)[(i << 1) + 1] /= (REAL) partsize[i];
++    (*partcenter)[*parts << 1] += (*partcenter)[i << 1];
++    (*partcenter)[(*parts << 1) + 1] += (*partcenter)[(i << 1) + 1];
++  }
++  (*partcenter)[*parts << 1] /= (REAL) *parts;
++  (*partcenter)[(*parts << 1) + 1] /= (REAL) *parts;
++  free(partsize);
++  return 0;
++}
++
++int load_adj(fname, subdomains, ptr)
++char *fname;
++int *subdomains;
++int **ptr;
++{
++  FILE *infile;
++  char inputline[INPUTLINESIZE];
++  char *stringptr;
++  int i, j;
++
++  if (!quiet) {
++    printf("Opening %s.\n", fname);
++  }
++  infile = fopen(fname, "r");
++  if (infile == (FILE *) NULL) {
++    printf("  Error:  Cannot access file %s.\n", fname);
++    return 1;
++  }
++  stringptr = readline(inputline, infile, fname);
++  *subdomains = (int) strtol (stringptr, &stringptr, 0);
++  if (*subdomains < 1) {
++    printf("  Error:  %s contains %d subdomains.\n", fname, *subdomains);
++    return 1;
++  }
++  *ptr = (int *) malloc(*subdomains * *subdomains * sizeof(int));
++  if (*ptr == (int *) NULL) {
++    printf("  Out of memory.\n");
++    return 1;
++  }
++  for (i = 0; i < *subdomains; i++) {
++    for (j = 0; j < *subdomains; j++) {
++      stringptr = readline(inputline, infile, fname);
++      (*ptr)[i * *subdomains + j] = (int) strtol (stringptr, &stringptr, 0);
++    }
++  }
++  return 0;
++}
++
++void findpartshift(parts, explosion, partcenter, partshift)
++int parts;
++REAL explosion;
++REAL *partcenter;
++REAL *partshift;
++{
++  int i;
++
++  for (i = 0; i < parts; i++) {
++    partshift[i << 1] = explosion *
++          (partcenter[i << 1] - partcenter[parts << 1]);
++    partshift[(i << 1) + 1] = explosion *
++          (partcenter[(i << 1) + 1] - partcenter[(parts << 1) + 1]);
++  }
++}
++
++int load_image(inc, image)
++int inc;
++int image;
++{
++  int error;
++
++  switch (image) {
++    case NODE:
++      error = load_node(nodefilename[inc], &firstnumber[inc], &nodes[inc],
++                        &node_dim[inc], &nodeptr[inc], &xlo[inc][NODE],
++                        &ylo[inc][NODE], &xhi[inc][NODE], &yhi[inc][NODE]);
++      break;
++    case POLY:
++      error = load_poly(inc, polyfilename[inc], &firstnumber[inc],
++                        &polynodes[inc], &poly_dim[inc], &polyedges[inc],
++                        &polyholes[inc], &polynodeptr[inc], &polyedgeptr[inc],
++                        &polyholeptr[inc],
++                        &xlo[inc][POLY], &ylo[inc][POLY],
++                        &xhi[inc][POLY], &yhi[inc][POLY]);
++      break;
++    case ELE:
++      error = load_ele(elefilename[inc], firstnumber[inc], nodes[inc],
++                       &elems[inc], &ele_corners[inc], &eleptr[inc]);
++      xlo[inc][ELE] = xlo[inc][NODE];
++      ylo[inc][ELE] = ylo[inc][NODE];
++      xhi[inc][ELE] = xhi[inc][NODE];
++      yhi[inc][ELE] = yhi[inc][NODE];
++      break;
++    case EDGE:
++      error = load_edge(edgefilename[inc], firstnumber[inc], nodes[inc],
++                        &edges[inc], &edgeptr[inc], &normptr[inc]);
++      xlo[inc][EDGE] = xlo[inc][NODE];
++      ylo[inc][EDGE] = ylo[inc][NODE];
++      xhi[inc][EDGE] = xhi[inc][NODE];
++      yhi[inc][EDGE] = yhi[inc][NODE];
++      break;
++    case PART:
++      error = load_part(partfilename[inc], node_dim[inc], firstnumber[inc],
++                        elems[inc], nodeptr[inc], eleptr[inc],
++                        &subdomains[inc], &partpart[inc], &partcenter[inc],
++                        &partshift[inc]);
++      if (!error) {
++        findpartshift(subdomains[inc], explosion, partcenter[inc],
++                      partshift[inc]);
++      }
++      xlo[inc][PART] = xlo[inc][NODE];
++      ylo[inc][PART] = ylo[inc][NODE];
++      xhi[inc][PART] = xhi[inc][NODE];
++      yhi[inc][PART] = yhi[inc][NODE];
++      break;
++    case ADJ:
++      error = load_adj(adjfilename[inc], &adjsubdomains[inc], &adjptr[inc]);
++      xlo[inc][ADJ] = xlo[inc][NODE];
++      ylo[inc][ADJ] = ylo[inc][NODE];
++      xhi[inc][ADJ] = xhi[inc][NODE];
++      yhi[inc][ADJ] = yhi[inc][NODE];
++      break;
++    case VORO:
++      error = load_node(vnodefilename[inc], &firstnumber[inc], &vnodes[inc],
++                        &vnode_dim[inc], &vnodeptr[inc], &xlo[inc][VORO],
++                        &ylo[inc][VORO], &xhi[inc][VORO], &yhi[inc][VORO]);
++      if (!error) {
++        error = load_edge(vedgefilename[inc], firstnumber[inc], vnodes[inc],
++                          &vedges[inc], &vedgeptr[inc], &vnormptr[inc]);
++      }
++      break;
++    default:
++      error = 1;
++  }
++  if (!error) {
++    loaded[inc][image] = 1;
++  }
++  return error;
++}
++
++void choose_image(inc, image)
++int inc;
++int image;
++{
++  if (!loaded[inc][image]) {
++    if ((image == ELE) || (image == EDGE) || (image == PART)
++        || (image == ADJ)) {
++      if (!loaded[inc][NODE]) {
++        if (load_image(inc, NODE)) {
++          return;
++        }
++      }
++    }
++    if ((image == PART) || (image == ADJ)) {
++      if (!loaded[inc][ELE]) {
++        if (load_image(inc, ELE)) {
++          return;
++        }
++      }
++    }
++    if (image == ADJ) {
++      if (!loaded[inc][PART]) {
++        if (load_image(inc, PART)) {
++          return;
++        }
++      }
++    }
++    if (load_image(inc, image)) {
++      return;
++    }
++  }
++  current_inc = inc;
++  current_image = image;
++}
++
++Window make_button(name, x, y, width)
++char *name;
++int x;
++int y;
++int width;
++{
++  XSetWindowAttributes attr;
++  XSizeHints hints;
++  Window button;
++
++  attr.background_pixel = black;
++  attr.border_pixel = white;
++  attr.backing_store = NotUseful;
++  attr.event_mask = ExposureMask | ButtonReleaseMask | ButtonPressMask;
++  attr.bit_gravity = SouthWestGravity;
++  attr.win_gravity = SouthWestGravity;
++  attr.save_under = False;
++  button = XCreateWindow(display, mainwindow, x, y, width, BUTTONHEIGHT - 4,
++                         2, 0, InputOutput, CopyFromParent,
++                         CWBackPixel | CWBorderPixel | CWEventMask |
++                         CWBitGravity | CWWinGravity | CWBackingStore |
++                         CWSaveUnder, &attr);
++  hints.width = width;
++  hints.height = BUTTONHEIGHT - 4;
++  hints.min_width = 0;
++  hints.min_height = BUTTONHEIGHT - 4;
++  hints.max_width = width;
++  hints.max_height = BUTTONHEIGHT - 4;
++  hints.width_inc = 1;
++  hints.height_inc = 1;
++  hints.flags = PMinSize | PMaxSize | PSize | PResizeInc;
++  XSetStandardProperties(display, button, name, "showme", None, (char **) NULL,
++                         0, &hints);
++  return button;
++}
++
++void make_buttons(y)
++int y;
++{
++  int i;
++
++  for (i = 1; i >= 0; i--) {
++    nodewin[i] = make_button("node", 0, y + (1 - i) * BUTTONHEIGHT, 42);
++    XMapWindow(display, nodewin[i]);
++    polywin[i] = make_button("poly", 44, y + (1 - i) * BUTTONHEIGHT, 42);
++    XMapWindow(display, polywin[i]);
++    elewin[i] = make_button("ele", 88, y + (1 - i) * BUTTONHEIGHT, 33);
++    XMapWindow(display, elewin[i]);
++    edgewin[i] = make_button("edge", 123, y + (1 - i) * BUTTONHEIGHT, 42);
++    XMapWindow(display, edgewin[i]);
++    partwin[i] = make_button("part", 167, y + (1 - i) * BUTTONHEIGHT, 42);
++    XMapWindow(display, partwin[i]);
++    adjwin[i] = make_button("adj", 211, y + (1 - i) * BUTTONHEIGHT, 33);
++    XMapWindow(display, adjwin[i]);
++    voronoiwin[i] = make_button("voro", 246, y + (1 - i) * BUTTONHEIGHT, 42);
++    XMapWindow(display, voronoiwin[i]);
++  }
++  versionpluswin = make_button("    +", 290, y, 52);
++  XMapWindow(display, versionpluswin);
++  versionminuswin = make_button("    -", 290, y + BUTTONHEIGHT, 52);
++  XMapWindow(display, versionminuswin);
++
++  quitwin = make_button("Quit", 0, y + 2 * BUTTONHEIGHT, 42);
++  XMapWindow(display, quitwin);
++  leftwin = make_button("<", 44, y + 2 * BUTTONHEIGHT, 14);
++  XMapWindow(display, leftwin);
++  rightwin = make_button(">", 60, y + 2 * BUTTONHEIGHT, 14);
++  XMapWindow(display, rightwin);
++  upwin = make_button("^", 76, y + 2 * BUTTONHEIGHT, 14);
++  XMapWindow(display, upwin);
++  downwin = make_button("v", 92, y + 2 * BUTTONHEIGHT, 14);
++  XMapWindow(display, downwin);
++  resetwin = make_button("Reset", 108, y + 2 * BUTTONHEIGHT, 52);
++  XMapWindow(display, resetwin);
++  widthpluswin = make_button("Width+", 162, y + 2 * BUTTONHEIGHT, 61);
++  XMapWindow(display, widthpluswin);
++  widthminuswin = make_button("-", 225, y + 2 * BUTTONHEIGHT, 14);
++  XMapWindow(display, widthminuswin);
++  expwin = make_button("Exp", 241, y + 2 * BUTTONHEIGHT, 33);
++  XMapWindow(display, expwin);
++  exppluswin = make_button("+", 276, y + 2 * BUTTONHEIGHT, 14);
++  XMapWindow(display, exppluswin);
++  expminuswin = make_button("-", 292, y + 2 * BUTTONHEIGHT, 14);
++  XMapWindow(display, expminuswin);
++  fillwin = make_button("Fill", 308, y + 2 * BUTTONHEIGHT, 41);
++  XMapWindow(display, fillwin);
++  pswin = make_button("PS", 351, y + 2 * BUTTONHEIGHT, 24);
++  XMapWindow(display, pswin);
++  epswin = make_button("EPS", 377, y + 2 * BUTTONHEIGHT, 33);
++  XMapWindow(display, epswin);
++}
++
++void fill_button(button)
++Window button;
++{
++  int x, y;
++  unsigned int w, h, d, b;
++  Window rootw;
++
++  XGetGeometry(display, button, &rootw, &x, &y, &w, &h, &d, &b);
++  XFillRectangle(display, button, fontgc, 0, 0, w, h);
++}
++
++void draw_buttons()
++{
++  char numberstring[32];
++  char buttonstring[6];
++  int i;
++
++  for (i = 1; i >= 0; i--) {
++    if ((current_image == NODE) && (current_inc == i)) {
++      fill_button(nodewin[i]);
++      XDrawString(display, nodewin[i], blackfontgc, 2, 13, "node", 4);
++    } else {
++      XClearWindow(display, nodewin[i]);
++      XDrawString(display, nodewin[i], fontgc, 2, 13, "node", 4);
++    }
++    if ((current_image == POLY) && (current_inc == i)) {
++      fill_button(polywin[i]);
++      XDrawString(display, polywin[i], blackfontgc, 2, 13, "poly", 4);
++    } else {
++      XClearWindow(display, polywin[i]);
++      XDrawString(display, polywin[i], fontgc, 2, 13, "poly", 4);
++    }
++    if ((current_image == ELE) && (current_inc == i)) {
++      fill_button(elewin[i]);
++      XDrawString(display, elewin[i], blackfontgc, 2, 13, "ele", 3);
++    } else {
++      XClearWindow(display, elewin[i]);
++      XDrawString(display, elewin[i], fontgc, 2, 13, "ele", 3);
++    }
++    if ((current_image == EDGE) && (current_inc == i)) {
++      fill_button(edgewin[i]);
++      XDrawString(display, edgewin[i], blackfontgc, 2, 13, "edge", 4);
++    } else {
++      XClearWindow(display, edgewin[i]);
++      XDrawString(display, edgewin[i], fontgc, 2, 13, "edge", 4);
++    }
++    if ((current_image == PART) && (current_inc == i)) {
++      fill_button(partwin[i]);
++      XDrawString(display, partwin[i], blackfontgc, 2, 13, "part", 4);
++    } else {
++      XClearWindow(display, partwin[i]);
++      XDrawString(display, partwin[i], fontgc, 2, 13, "part", 4);
++    }
++    if ((current_image == ADJ) && (current_inc == i)) {
++      fill_button(adjwin[i]);
++      XDrawString(display, adjwin[i], blackfontgc, 2, 13, "adj", 3);
++    } else {
++      XClearWindow(display, adjwin[i]);
++      XDrawString(display, adjwin[i], fontgc, 2, 13, "adj", 3);
++    }
++    if ((current_image == VORO) && (current_inc == i)) {
++      fill_button(voronoiwin[i]);
++      XDrawString(display, voronoiwin[i], blackfontgc, 2, 13, "voro", 4);
++    } else {
++      XClearWindow(display, voronoiwin[i]);
++      XDrawString(display, voronoiwin[i], fontgc, 2, 13, "voro", 4);
++    }
++  }
++
++  XClearWindow(display, versionpluswin);
++  sprintf(numberstring, "%d", loweriteration + 1);
++  sprintf(buttonstring, "%-4.4s+", numberstring);
++  XDrawString(display, versionpluswin, fontgc, 2, 13, buttonstring, 5);
++  XClearWindow(display, versionminuswin);
++  sprintf(numberstring, "%d", loweriteration);
++  if (loweriteration == 0) {
++    sprintf(buttonstring, "%-4.4s", numberstring);
++  } else {
++    sprintf(buttonstring, "%-4.4s-", numberstring);
++  }
++  XDrawString(display, versionminuswin, fontgc, 2, 13, buttonstring, 5);
++
++  XClearWindow(display, quitwin);
++  XDrawString(display, quitwin, fontgc, 2, 13, "Quit", 4);
++  XClearWindow(display, leftwin);
++  XDrawString(display, leftwin, fontgc, 2, 13, "<", 1);
++  XClearWindow(display, rightwin);
++  XDrawString(display, rightwin, fontgc, 2, 13, ">", 1);
++  XClearWindow(display, upwin);
++  XDrawString(display, upwin, fontgc, 2, 13, "^", 1);
++  XClearWindow(display, downwin);
++  XDrawString(display, downwin, fontgc, 2, 13, "v", 1);
++  XClearWindow(display, resetwin);
++  XDrawString(display, resetwin, fontgc, 2, 13, "Reset", 6);
++  XClearWindow(display, widthpluswin);
++  if (line_width < 100) {
++    XDrawString(display, widthpluswin, fontgc, 2, 13, "Width+", 6);
++  } else {
++    XDrawString(display, widthpluswin, fontgc, 2, 13, "Width ", 6);
++  }
++  XClearWindow(display, widthminuswin);
++  if (line_width > 1) {
++    XDrawString(display, widthminuswin, fontgc, 2, 13, "-", 1);
++  }
++  XClearWindow(display, expwin);
++  XClearWindow(display, exppluswin);
++  XClearWindow(display, expminuswin);
++  XClearWindow(display, fillwin);
++  if (current_image == PART) {
++    if (explode) {
++      fill_button(expwin);
++      XDrawString(display, expwin, blackfontgc, 2, 13, "Exp", 3);
++    } else {
++      XDrawString(display, expwin, fontgc, 2, 13, "Exp", 3);
++    }
++    XDrawString(display, exppluswin, fontgc, 2, 13, "+", 1);
++    XDrawString(display, expminuswin, fontgc, 2, 13, "-", 1);
++    if (fillelem) {
++      fill_button(fillwin);
++      XDrawString(display, fillwin, blackfontgc, 2, 13, "Fill", 4);
++    } else {
++      XDrawString(display, fillwin, fontgc, 2, 13, "Fill", 4);
++    }
++  }
++  XClearWindow(display, pswin);
++  XDrawString(display, pswin, fontgc, 2, 13, "PS", 2);
++  XClearWindow(display, epswin);
++  XDrawString(display, epswin, fontgc, 2, 13, "EPS", 3);
++}
++
++void showme_window(argc, argv)
++int argc;
++char **argv;
++{
++  XSetWindowAttributes attr;
++  XSizeHints hints;
++  XGCValues fontvalues, linevalues;
++  XColor alloc_color, exact_color;
++  int i;
++
++  display = XOpenDisplay((char *) NULL);
++  if (!display) {
++    printf("Error:  Cannot open display.\n");
++    exit(1);
++  }
++  screen = DefaultScreen(display);
++  rootwindow = DefaultRootWindow(display);
++  black = BlackPixel(display, screen);
++  white = WhitePixel(display, screen);
++  windowdepth = DefaultDepth(display, screen);
++  rootmap = DefaultColormap(display, screen);
++  width = STARTWIDTH;
++  height = STARTHEIGHT;
++  attr.background_pixel = black;
++  attr.border_pixel = white;
++  attr.backing_store = NotUseful;
++  attr.event_mask = ExposureMask | ButtonReleaseMask | ButtonPressMask |
++                    StructureNotifyMask;
++  attr.bit_gravity = NorthWestGravity;
++  attr.win_gravity = NorthWestGravity;
++  attr.save_under = False;
++  mainwindow = XCreateWindow(display, rootwindow, 0, 0, width,
++                             height + PANELHEIGHT, 3, 0,
++                             InputOutput, CopyFromParent,
++                             CWBackPixel | CWBorderPixel | CWEventMask |
++                             CWBitGravity | CWWinGravity | CWBackingStore |
++                             CWSaveUnder, &attr);
++  hints.width = width;
++  hints.height = height + PANELHEIGHT;
++  hints.min_width = MINWIDTH;
++  hints.min_height = MINHEIGHT + PANELHEIGHT;
++  hints.width_inc = 1;
++  hints.height_inc = 1;
++  hints.flags = PMinSize | PSize | PResizeInc;
++  XSetStandardProperties(display, mainwindow, "Show Me", "showme", None,
++                         argv, argc, &hints);
++  XChangeProperty(display, mainwindow, XA_WM_CLASS, XA_STRING, 8,
++                  PropModeReplace, "showme\0Archimedes", 18);
++  XClearWindow(display, mainwindow);
++  XMapWindow(display, mainwindow);
++  if ((windowdepth > 1) &&
++      XAllocNamedColor(display, rootmap, "yellow", &alloc_color,
++                       &exact_color)) {
++    color = 1;
++    explode = bw_ps;
++    fontvalues.foreground = alloc_color.pixel;
++    linevalues.foreground = alloc_color.pixel;
++    showme_foreground = alloc_color.pixel;
++    for (i = 0; i < 64; i++) {
++      if (XAllocNamedColor(display, rootmap, colorname[i], &alloc_color,
++                           &rgb[i])) {
++        colors[i] = alloc_color.pixel;
++      } else {
++        colors[i] = white;
++        rgb[i].red = alloc_color.red;
++        rgb[i].green = alloc_color.green;
++        rgb[i].blue = alloc_color.blue;
++        if (!quiet) {
++          printf("Warning:  I could not allocate %s.\n", colorname[i]);
++        }
++      }
++    }
++  } else {
++    color = 0;
++    fillelem = 0;
++    explode = 1;
++    fontvalues.foreground = white;
++    linevalues.foreground = white;
++    showme_foreground = white;
++  }
++  font = XLoadQueryFont(display, "9x15");
++  fontvalues.background = black;
++  fontvalues.font = font->fid;
++  fontvalues.fill_style = FillSolid;
++  fontvalues.line_width = 2;
++  fontgc = XCreateGC(display, rootwindow, GCForeground | GCBackground |
++                      GCFont | GCLineWidth | GCFillStyle, &fontvalues);
++  fontvalues.foreground = black;
++  blackfontgc = XCreateGC(display, rootwindow, GCForeground | GCBackground |
++                         GCFont | GCLineWidth | GCFillStyle, &fontvalues);
++  linevalues.background = black;
++  linevalues.line_width = line_width;
++  linevalues.cap_style = CapRound;
++  linevalues.join_style = JoinRound;
++  linevalues.fill_style = FillSolid;
++  linegc = XCreateGC(display, rootwindow, GCForeground | GCBackground |
++                     GCLineWidth | GCCapStyle | GCJoinStyle | GCFillStyle,
++                     &linevalues);
++  trianglegc = XCreateGC(display, rootwindow, GCForeground | GCBackground |
++                         GCLineWidth | GCCapStyle | GCJoinStyle | GCFillStyle,
++                         &linevalues);
++  make_buttons(height);
++  XFlush(display);
++}
++
++void draw_node(nodes, dim, ptr, xscale, yscale, xoffset, yoffset)
++int nodes;
++int dim;
++REAL *ptr;
++REAL xscale;
++REAL yscale;
++REAL xoffset;
++REAL yoffset;
++{
++  int i;
++  int index;
++
++  index = dim;
++  for (i = 1; i <= nodes; i++) {
++    XFillRectangle(display, mainwindow, linegc,
++                   (int) (ptr[index] * xscale + xoffset) - (line_width >> 1),
++                   (int) (ptr[index + 1] * yscale + yoffset) -
++                         (line_width >> 1), line_width, line_width);
++    index += dim;
++  }
++}
++
++void draw_poly(nodes, dim, edges, holes, nodeptr, edgeptr, holeptr,
++               xscale, yscale, xoffset, yoffset)
++int nodes;
++int dim;
++int edges;
++int holes;
++REAL *nodeptr;
++int *edgeptr;
++REAL *holeptr;
++REAL xscale;
++REAL yscale;
++REAL xoffset;
++REAL yoffset;
++{
++  int i;
++  int index;
++  REAL *point1, *point2;
++  int x1, y1, x2, y2;
++
++  index = dim;
++  for (i = 1; i <= nodes; i++) {
++    XFillRectangle(display, mainwindow, linegc,
++                   (int) (nodeptr[index] * xscale + xoffset) -
++                         (line_width >> 1),
++                   (int) (nodeptr[index + 1] * yscale + yoffset) -
++                         (line_width >> 1), line_width, line_width);
++    index += dim;
++  }
++  index = 2;
++  for (i = 1; i <= edges; i++) {
++    point1 = &nodeptr[edgeptr[index++] * dim];
++    point2 = &nodeptr[edgeptr[index++] * dim];
++    XDrawLine(display, mainwindow, linegc,
++              (int) (point1[0] * xscale + xoffset),
++              (int) (point1[1] * yscale + yoffset),
++              (int) (point2[0] * xscale + xoffset),
++              (int) (point2[1] * yscale + yoffset));
++  }
++  index = dim;
++  if (color) {
++    XSetForeground(display, linegc, colors[0]);
++  }
++  for (i = 1; i <= holes; i++) {
++    x1 = (int) (holeptr[index] * xscale + xoffset) - 3;
++    y1 = (int) (holeptr[index + 1] * yscale + yoffset) - 3;
++    x2 = x1 + 6;
++    y2 = y1 + 6;
++    XDrawLine(display, mainwindow, linegc, x1, y1, x2, y2);
++    XDrawLine(display, mainwindow, linegc, x1, y2, x2, y1);
++    index += dim;
++  }
++  XSetForeground(display, linegc, showme_foreground);
++}
++
++void draw_ele(inc, elems, corners, ptr, partition, shift,
++              xscale, yscale, xoffset, yoffset)
++int inc;
++int elems;
++int corners;
++int *ptr;
++int *partition;
++REAL *shift;
++REAL xscale;
++REAL yscale;
++REAL xoffset;
++REAL yoffset;
++{
++  int i, j;
++  int index;
++  REAL shiftx, shifty;
++  REAL *prevpoint, *nowpoint;
++  XPoint *vertices;
++
++  if (color && fillelem && (partition != (int *) NULL)) {
++    vertices = (XPoint *) malloc(3 * sizeof(XPoint));
++    if (vertices == (XPoint *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  index = 3;
++  for (i = 1; i <= elems; i++) {
++    if ((partition != (int *) NULL) && explode) {
++      shiftx = shift[partition[i] << 1];
++      shifty = shift[(partition[i] << 1) + 1];
++    }
++    if (color && (partition != (int *) NULL)) {
++      if (fillelem) {
++        XSetForeground(display, trianglegc, colors[partition[i] & 63]);
++      } else {
++        XSetForeground(display, linegc, colors[partition[i] & 63]);
++      }
++    }
++    if (color && fillelem && (partition != (int *) NULL)) {
++      if ((partition != (int *) NULL) && explode) {
++        for (j = 0; j < 3; j++) {
++          nowpoint = &nodeptr[inc][ptr[index + j] * node_dim[inc]];
++          vertices[j].x = (nowpoint[0] + shiftx) * xscale + xoffset;
++          vertices[j].y = (nowpoint[1] + shifty) * yscale + yoffset;
++        }
++      } else {
++        for (j = 0; j < 3; j++) {
++          nowpoint = &nodeptr[inc][ptr[index + j] * node_dim[inc]];
++          vertices[j].x = nowpoint[0] * xscale + xoffset;
++          vertices[j].y = nowpoint[1] * yscale + yoffset;
++        }
++      }
++      XFillPolygon(display, mainwindow, trianglegc, vertices, 3,
++                   Convex, CoordModeOrigin);
++    }
++    prevpoint = &nodeptr[inc][ptr[index + 2] * node_dim[inc]];
++    if ((partition != (int *) NULL) && explode) {
++      for (j = 0; j < 3; j++) {
++        nowpoint = &nodeptr[inc][ptr[index++] * node_dim[inc]];
++        XDrawLine(display, mainwindow, linegc,
++                  (int) ((prevpoint[0] + shiftx) * xscale + xoffset),
++                  (int) ((prevpoint[1] + shifty) * yscale + yoffset),
++                  (int) ((nowpoint[0] + shiftx) * xscale + xoffset),
++                  (int) ((nowpoint[1] + shifty) * yscale + yoffset));
++        prevpoint = nowpoint;
++      }
++    } else {
++      for (j = 0; j < 3; j++) {
++        nowpoint = &nodeptr[inc][ptr[index++] * node_dim[inc]];
++        XDrawLine(display, mainwindow, linegc,
++                  (int) (prevpoint[0] * xscale + xoffset),
++                  (int) (prevpoint[1] * yscale + yoffset),
++                  (int) (nowpoint[0] * xscale + xoffset),
++                  (int) (nowpoint[1] * yscale + yoffset));
++        prevpoint = nowpoint;
++      }
++    }
++  }
++  if (color && fillelem && (partition != (int *) NULL)) {
++    free(vertices);
++  }
++  XSetForeground(display, linegc, showme_foreground);
++}
++
++void draw_edge(nodes, dim, edges, nodeptr, edgeptr, normptr,
++               xscale, yscale, xoffset, yoffset)
++int nodes;
++int dim;
++int edges;
++REAL *nodeptr;
++int *edgeptr;
++REAL *normptr;
++REAL xscale;
++REAL yscale;
++REAL xoffset;
++REAL yoffset;
++{
++  int i;
++  int index;
++  REAL *point1, *point2;
++  REAL normx, normy;
++  REAL normmult, normmultx, normmulty;
++  REAL windowxmin, windowymin, windowxmax, windowymax;
++
++  index = 2;
++  for (i = 1; i <= edges; i++) {
++    point1 = &nodeptr[edgeptr[index++] * dim];
++    if (edgeptr[index] == -1) {
++      normx = normptr[index - 1];
++      normy = normptr[index++];
++      normmultx = 0.0;
++      if (normx > 0) {
++        windowxmax = (width - 1 - xoffset) / xscale;
++        normmultx = (windowxmax - point1[0]) / normx;
++      } else if (normx < 0) {
++        windowxmin = -xoffset / xscale;
++        normmultx = (windowxmin - point1[0]) / normx;
++      }
++      normmulty = 0.0;
++      if (normy > 0) {
++        windowymax = -yoffset / yscale;
++        normmulty = (windowymax - point1[1]) / normy;
++      } else if (normy < 0) {
++        windowymin = (height - 1 - yoffset) / yscale;
++        normmulty = (windowymin - point1[1]) / normy;
++      }
++      if (normmultx == 0.0) {
++        normmult = normmulty;
++      } else if (normmulty == 0.0) {
++        normmult = normmultx;
++      } else if (normmultx < normmulty) {
++        normmult = normmultx;
++      } else {
++        normmult = normmulty;
++      }
++      if (normmult > 0.0) {
++        XDrawLine(display, mainwindow, linegc,
++                  (int) (point1[0] * xscale + xoffset),
++                  (int) (point1[1] * yscale + yoffset),
++                  (int) ((point1[0] + normmult * normx) * xscale + xoffset),
++                  (int) ((point1[1] + normmult * normy) * yscale + yoffset));
++      }
++    } else {
++      point2 = &nodeptr[edgeptr[index++] * dim];
++      XDrawLine(display, mainwindow, linegc,
++                (int) (point1[0] * xscale + xoffset),
++                (int) (point1[1] * yscale + yoffset),
++                (int) (point2[0] * xscale + xoffset),
++                (int) (point2[1] * yscale + yoffset));
++    }
++  }
++}
++
++void draw_adj(dim, subdomains, ptr, center, xscale, yscale,
++              xoffset, yoffset)
++int dim;
++int subdomains;
++int *ptr;
++REAL *center;
++REAL xscale;
++REAL yscale;
++REAL xoffset;
++REAL yoffset;
++{
++  int i, j;
++  REAL *point1, *point2;
++
++  for (i = 0; i < subdomains; i++) {
++    for (j = i + 1; j < subdomains; j++) {
++      if (ptr[i * subdomains + j]) {
++        point1 = &center[i * dim];
++        point2 = &center[j * dim];
++        XDrawLine(display, mainwindow, linegc,
++                  (int) (point1[0] * xscale + xoffset),
++                  (int) (point1[1] * yscale + yoffset),
++                  (int) (point2[0] * xscale + xoffset),
++                  (int) (point2[1] * yscale + yoffset));
++      }
++    }
++  }
++  for (i = 0; i < subdomains; i++) {
++    point1 = &center[i * dim];
++    if (color) {
++      XSetForeground(display, linegc, colors[i & 63]);
++    }
++    XFillArc(display, mainwindow, linegc,
++             (int) (point1[0] * xscale + xoffset) - 5 - (line_width >> 1),
++             (int) (point1[1] * yscale + yoffset) - 5 - (line_width >> 1),
++             line_width + 10, line_width + 10, 0, 23040);
++  }
++  XSetForeground(display, linegc, showme_foreground);
++}
++
++void draw(inc, image, xmin, ymin, xmax, ymax)
++int inc;
++int image;
++REAL xmin;
++REAL ymin;
++REAL xmax;
++REAL ymax;
++{
++  draw_buttons();
++  XClearWindow(display, mainwindow);
++  if (image == NOTHING) {
++    return;
++  }
++  if (!loaded[inc][image]) {
++    return;
++  }
++  if ((image == PART) && explode) {
++    xmin += (xmin - partcenter[inc][subdomains[inc] << 1]) * explosion;
++    xmax += (xmax - partcenter[inc][subdomains[inc] << 1]) * explosion;
++    ymin += (ymin - partcenter[inc][(subdomains[inc] << 1) + 1]) * explosion;
++    ymax += (ymax - partcenter[inc][(subdomains[inc] << 1) + 1]) * explosion;
++  }
++  xscale = (REAL) (width - line_width - 4) / (xmax - xmin);
++  yscale = (REAL) (height - line_width - 4) / (ymax - ymin);
++  if (xscale > yscale) {
++    xscale = yscale;
++  } else {
++    yscale = xscale;
++  }
++  xoffset = 0.5 * ((REAL) width - xscale * (xmax - xmin)) -
++            xscale * xmin;
++  yoffset = (REAL) height - 0.5 * ((REAL) height - yscale * (ymax - ymin)) +
++            yscale * ymin;
++  yscale = - yscale;
++  switch(image) {
++    case NODE:
++      draw_node(nodes[inc], node_dim[inc], nodeptr[inc],
++                xscale, yscale, xoffset, yoffset);
++      break;
++    case POLY:
++      if (polynodes[inc] > 0) {
++        draw_poly(polynodes[inc], poly_dim[inc], polyedges[inc],
++                  polyholes[inc], polynodeptr[inc], polyedgeptr[inc],
++                  polyholeptr[inc],
++                  xscale, yscale, xoffset, yoffset);
++      } else {
++        draw_poly(nodes[inc], node_dim[inc], polyedges[inc],
++                  polyholes[inc], nodeptr[inc], polyedgeptr[inc],
++                  polyholeptr[inc],
++                  xscale, yscale, xoffset, yoffset);
++      }
++      break;
++    case ELE:
++      draw_ele(inc, elems[inc], ele_corners[inc], eleptr[inc],
++               (int *) NULL, (REAL *) NULL,
++               xscale, yscale, xoffset, yoffset);
++      break;
++    case EDGE:
++      draw_edge(nodes[inc], node_dim[inc], edges[inc],
++                nodeptr[inc], edgeptr[inc], normptr[inc],
++                xscale, yscale, xoffset, yoffset);
++      break;
++    case PART:
++      draw_ele(inc, elems[inc], ele_corners[inc], eleptr[inc],
++               partpart[inc], partshift[inc],
++               xscale, yscale, xoffset, yoffset);
++      break;
++    case ADJ:
++      draw_adj(node_dim[inc], adjsubdomains[inc], adjptr[inc], partcenter[inc],
++               xscale, yscale, xoffset, yoffset);
++      break;
++    case VORO:
++      if (loaded[inc][NODE]) {
++        draw_node(nodes[inc], node_dim[inc], nodeptr[inc],
++                  xscale, yscale, xoffset, yoffset);
++      }
++      draw_edge(vnodes[inc], vnode_dim[inc], vedges[inc],
++                vnodeptr[inc], vedgeptr[inc], vnormptr[inc],
++                xscale, yscale, xoffset, yoffset);
++      break;
++    default:
++      break;
++  }
++}
++
++void addps(instring, outstring, eps)
++char *instring;
++char *outstring;
++int eps;
++{
++  strcpy(outstring, instring);
++  if (eps) {
++    strcat(outstring, ".eps");
++  } else {
++    strcat(outstring, ".ps");
++  }
++}
++
++int print_head(fname, file, llcornerx, llcornery, eps)
++char *fname;
++FILE **file;
++int llcornerx;
++int llcornery;
++int eps;
++{
++  if (!quiet) {
++    printf("Writing %s\n", fname);
++  }
++  *file = fopen(fname, "w");
++  if (*file == (FILE *) NULL) {
++    printf("  Error:  Could not open %s\n", fname);
++    return 1;
++  }
++  if (eps) {
++    fprintf(*file, "%%!PS-Adobe-2.0 EPSF-2.0\n");
++  } else {
++    fprintf(*file, "%%!PS-Adobe-2.0\n");
++  }
++  fprintf(*file, "%%%%BoundingBox: %d %d %d %d\n", llcornerx, llcornery,
++          612 - llcornerx, 792 - llcornery);
++  fprintf(*file, "%%%%Creator: Show Me\n");
++  fprintf(*file, "%%%%EndComments\n\n");
++  fprintf(*file, "1 setlinecap\n");
++  fprintf(*file, "1 setlinejoin\n");
++  fprintf(*file, "%d setlinewidth\n", line_width);
++  fprintf(*file, "%d %d moveto\n", llcornerx, llcornery);
++  fprintf(*file, "%d %d lineto\n", 612 - llcornerx, llcornery);
++  fprintf(*file, "%d %d lineto\n", 612 - llcornerx, 792 - llcornery);
++  fprintf(*file, "%d %d lineto\n", llcornerx, 792 - llcornery);
++  fprintf(*file, "closepath\nclip\nnewpath\n");
++  return 0;
++}
++
++void print_node(nodefile, nodes, dim, ptr, xscale, yscale,
++                xoffset, yoffset)
++FILE *nodefile;
++int nodes;
++int dim;
++REAL *ptr;
++REAL xscale;
++REAL yscale;
++REAL xoffset;
++REAL yoffset;
++{
++  int i;
++  int index;
++
++  index = dim;
++  for (i = 1; i <= nodes; i++) {
++    fprintf(nodefile, "%d %d %d 0 360 arc\nfill\n",
++            (int) (ptr[index] * xscale + xoffset),
++            (int) (ptr[index + 1] * yscale + yoffset),
++            1 + (line_width >> 1));
++    index += dim;
++  }
++}
++
++void print_poly(polyfile, nodes, dim, edges, holes, nodeptr, edgeptr, holeptr,
++                xscale, yscale, xoffset, yoffset)
++FILE *polyfile;
++int nodes;
++int dim;
++int edges;
++int holes;
++REAL *nodeptr;
++int *edgeptr;
++REAL *holeptr;
++REAL xscale;
++REAL yscale;
++REAL xoffset;
++REAL yoffset;
++{
++  int i;
++  int index;
++  REAL *point1, *point2;
++
++  index = dim;
++  for (i = 1; i <= nodes; i++) {
++    fprintf(polyfile, "%d %d %d 0 360 arc\nfill\n",
++            (int) (nodeptr[index] * xscale + xoffset),
++            (int) (nodeptr[index + 1] * yscale + yoffset),
++            1 + (line_width >> 1));
++    index += dim;
++  }
++  index = 2;
++  for (i = 1; i <= edges; i++) {
++    point1 = &nodeptr[edgeptr[index++] * dim];
++    point2 = &nodeptr[edgeptr[index++] * dim];
++    fprintf(polyfile, "%d %d moveto\n",
++            (int) (point1[0] * xscale + xoffset),
++            (int) (point1[1] * yscale + yoffset));
++    fprintf(polyfile, "%d %d lineto\nstroke\n",
++            (int) (point2[0] * xscale + xoffset),
++            (int) (point2[1] * yscale + yoffset));
++  }
++}
++
++void print_ele(elefile, nodes, dim, elems, corners, nodeptr, eleptr,
++               partition, shift,
++               xscale, yscale, xoffset, yoffset, llcornerx, llcornery)
++FILE *elefile;
++int nodes;
++int dim;
++int elems;
++int corners;
++REAL *nodeptr;
++int *eleptr;
++int *partition;
++REAL *shift;
++REAL xscale;
++REAL yscale;
++REAL xoffset;
++REAL yoffset;
++int llcornerx;
++int llcornery;
++{
++  int i, j;
++  int index, colorindex;
++  REAL shiftx, shifty;
++  REAL *nowpoint;
++
++  index = 3;
++  if ((partition != (int *) NULL) && !bw_ps) {
++    fprintf(elefile, "0 0 0 setrgbcolor\n");
++    fprintf(elefile, "%d %d moveto\n", llcornerx, llcornery);
++    fprintf(elefile, "%d %d lineto\n", 612 - llcornerx, llcornery);
++    fprintf(elefile, "%d %d lineto\n", 612 - llcornerx, 792 - llcornery);
++    fprintf(elefile, "%d %d lineto\n", llcornerx, 792 - llcornery);
++    fprintf(elefile, "fill\n");
++  }
++  for (i = 1; i <= elems; i++) {
++    if ((partition != (int *) NULL) && !bw_ps) {
++      colorindex = partition[i] & 63;
++      fprintf(elefile, "%6.3f %6.3f %6.3f setrgbcolor\n",
++              (REAL) rgb[colorindex].red / 65535.0,
++              (REAL) rgb[colorindex].green / 65535.0,
++              (REAL) rgb[colorindex].blue / 65535.0);
++    }
++    nowpoint = &nodeptr[eleptr[index + 2] * dim];
++    if ((partition != (int *) NULL) && (explode || bw_ps)) {
++      shiftx = shift[partition[i] << 1];
++      shifty = shift[(partition[i] << 1) + 1];
++      fprintf(elefile, "%d %d moveto\n",
++              (int) ((nowpoint[0] + shiftx) * xscale + xoffset),
++              (int) ((nowpoint[1] + shifty) * yscale + yoffset));
++      for (j = 0; j < 3; j++) {
++        nowpoint = &nodeptr[eleptr[index++] * dim];
++        fprintf(elefile, "%d %d lineto\n",
++                (int) ((nowpoint[0] + shiftx) * xscale + xoffset),
++                (int) ((nowpoint[1] + shifty) * yscale + yoffset));
++      }
++    } else {
++      fprintf(elefile, "%d %d moveto\n",
++              (int) (nowpoint[0] * xscale + xoffset),
++              (int) (nowpoint[1] * yscale + yoffset));
++      for (j = 0; j < 3; j++) {
++        nowpoint = &nodeptr[eleptr[index++] * dim];
++        fprintf(elefile, "%d %d lineto\n",
++                (int) (nowpoint[0] * xscale + xoffset),
++                (int) (nowpoint[1] * yscale + yoffset));
++      }
++    }
++    if (fillelem && !bw_ps) {
++      fprintf(elefile, "gsave\nfill\ngrestore\n1 1 0 setrgbcolor\n");
++    }
++    fprintf(elefile, "stroke\n");
++  }
++}
++
++void print_edge(edgefile, nodes, dim, edges, nodeptr, edgeptr, normptr,
++                xscale, yscale, xoffset, yoffset, llcornerx, llcornery)
++FILE *edgefile;
++int nodes;
++int dim;
++int edges;
++REAL *nodeptr;
++int *edgeptr;
++REAL *normptr;
++REAL xscale;
++REAL yscale;
++REAL xoffset;
++REAL yoffset;
++int llcornerx;
++int llcornery;
++{
++  int i;
++  int index;
++  REAL *point1, *point2;
++  REAL normx, normy;
++  REAL normmult, normmultx, normmulty;
++  REAL windowxmin, windowymin, windowxmax, windowymax;
++
++  index = 2;
++  for (i = 1; i <= edges; i++) {
++    point1 = &nodeptr[edgeptr[index++] * dim];
++    if (edgeptr[index] == -1) {
++      normx = normptr[index - 1];
++      normy = normptr[index++];
++      normmultx = 0.0;
++      if (normx > 0) {
++        windowxmax = ((REAL) (612 - llcornerx) - xoffset) / xscale;
++        normmultx = (windowxmax - point1[0]) / normx;
++      } else if (normx < 0) {
++        windowxmin = ((REAL) llcornerx - xoffset) / xscale;
++        normmultx = (windowxmin - point1[0]) / normx;
++      }
++      normmulty = 0.0;
++      if (normy > 0) {
++        windowymax = ((REAL) (792 - llcornery) - yoffset) / yscale;
++        normmulty = (windowymax - point1[1]) / normy;
++      } else if (normy < 0) {
++        windowymin = ((REAL) llcornery - yoffset) / yscale;
++        normmulty = (windowymin - point1[1]) / normy;
++      }
++      if (normmultx == 0.0) {
++        normmult = normmulty;
++      } else if (normmulty == 0.0) {
++        normmult = normmultx;
++      } else if (normmultx < normmulty) {
++        normmult = normmultx;
++      } else {
++        normmult = normmulty;
++      }
++      if (normmult > 0.0) {
++        fprintf(edgefile, "%d %d moveto\n",
++                (int) (point1[0] * xscale + xoffset),
++                (int) (point1[1] * yscale + yoffset));
++        fprintf(edgefile, "%d %d lineto\nstroke\n",
++                (int) ((point1[0] + normmult * normx) * xscale + xoffset),
++                (int) ((point1[1] + normmult * normy) * yscale + yoffset));
++      }
++    } else {
++      point2 = &nodeptr[edgeptr[index++] * dim];
++      fprintf(edgefile, "%d %d moveto\n",
++              (int) (point1[0] * xscale + xoffset),
++              (int) (point1[1] * yscale + yoffset));
++      fprintf(edgefile, "%d %d lineto\nstroke\n",
++              (int) (point2[0] * xscale + xoffset),
++              (int) (point2[1] * yscale + yoffset));
++    }
++  }
++}
++
++void print_adj(adjfile, dim, subdomains, ptr, center, xscale, yscale,
++               xoffset, yoffset, llcornerx, llcornery)
++FILE *adjfile;
++int dim;
++int subdomains;
++int *ptr;
++REAL *center;
++REAL xscale;
++REAL yscale;
++REAL xoffset;
++REAL yoffset;
++int llcornerx;
++int llcornery;
++{
++  int i, j;
++  REAL *point1, *point2;
++  int colorindex;
++
++  if (!bw_ps) {
++    fprintf(adjfile, "0 0 0 setrgbcolor\n");
++    fprintf(adjfile, "%d %d moveto\n", llcornerx, llcornery);
++    fprintf(adjfile, "%d %d lineto\n", 612 - llcornerx, llcornery);
++    fprintf(adjfile, "%d %d lineto\n", 612 - llcornerx, 792 - llcornery);
++    fprintf(adjfile, "%d %d lineto\n", llcornerx, 792 - llcornery);
++    fprintf(adjfile, "fill\n");
++    fprintf(adjfile, "1 1 0 setrgbcolor\n");
++  }
++  for (i = 0; i < subdomains; i++) {
++    for (j = i + 1; j < subdomains; j++) {
++      if (ptr[i * subdomains + j]) {
++        point1 = &center[i * dim];
++        point2 = &center[j * dim];
++        fprintf(adjfile, "%d %d moveto\n",
++                (int) (point1[0] * xscale + xoffset),
++                (int) (point1[1] * yscale + yoffset));
++        fprintf(adjfile, "%d %d lineto\nstroke\n",
++                (int) (point2[0] * xscale + xoffset),
++                (int) (point2[1] * yscale + yoffset));
++      }
++    }
++  }
++  for (i = 0; i < subdomains; i++) {
++    point1 = &center[i * dim];
++    if (!bw_ps) {
++      colorindex = i & 63;
++      fprintf(adjfile, "%6.3f %6.3f %6.3f setrgbcolor\n",
++              (REAL) rgb[colorindex].red / 65535.0,
++              (REAL) rgb[colorindex].green / 65535.0,
++              (REAL) rgb[colorindex].blue / 65535.0);
++      fprintf(adjfile, "%d %d %d 0 360 arc\nfill\n",
++              (int) (point1[0] * xscale + xoffset),
++              (int) (point1[1] * yscale + yoffset),
++              5 + (line_width >> 1));
++    } else {
++      fprintf(adjfile, "%d %d %d 0 360 arc\nfill\n",
++              (int) (point1[0] * xscale + xoffset),
++              (int) (point1[1] * yscale + yoffset),
++              3 + (line_width >> 1));
++    }
++  }
++}
++
++void print(inc, image, xmin, ymin, xmax, ymax, eps)
++int inc;
++int image;
++REAL xmin;
++REAL ymin;
++REAL xmax;
++REAL ymax;
++int eps;
++{
++  REAL xxscale, yyscale, xxoffset, yyoffset;
++  char psfilename[FILENAMESIZE];
++  int llcornerx, llcornery;
++  FILE *psfile;
++
++  if (image == NOTHING) {
++    return;
++  }
++  if (!loaded[inc][image]) {
++    return;
++  }
++  if ((image == PART) && (explode || bw_ps)) {
++    xmin += (xmin - partcenter[inc][subdomains[inc] << 1]) * explosion;
++    xmax += (xmax - partcenter[inc][subdomains[inc] << 1]) * explosion;
++    ymin += (ymin - partcenter[inc][(subdomains[inc] << 1) + 1]) * explosion;
++    ymax += (ymax - partcenter[inc][(subdomains[inc] << 1) + 1]) * explosion;
++  }
++  xxscale = (460.0 - (REAL) line_width) / (xmax - xmin);
++  yyscale = (640.0 - (REAL) line_width) / (ymax - ymin);
++  if (xxscale > yyscale) {
++    xxscale = yyscale;
++    llcornerx = (604 - (int) (yyscale * (xmax - xmin)) - line_width) >> 1;
++    llcornery = 72;
++  } else {
++    yyscale = xxscale;
++    llcornerx = 72;
++    llcornery = (784 - (int) (xxscale * (ymax - ymin)) - line_width) >> 1;
++  }
++  xxoffset = 0.5 * (612.0 - xxscale * (xmax - xmin)) - xxscale * xmin +
++             (line_width >> 1);
++  yyoffset = 0.5 * (792.0 - yyscale * (ymax - ymin)) - yyscale * ymin +
++             (line_width >> 1);
++  switch(image) {
++    case NODE:
++      addps(nodefilename[inc], psfilename, eps);
++      break;
++    case POLY:
++      addps(polyfilename[inc], psfilename, eps);
++      break;
++    case ELE:
++      addps(elefilename[inc], psfilename, eps);
++      break;
++    case EDGE:
++      addps(edgefilename[inc], psfilename, eps);
++      break;
++    case PART:
++      addps(partfilename[inc], psfilename, eps);
++      break;
++    case ADJ:
++      addps(adjfilename[inc], psfilename, eps);
++      break;
++    case VORO:
++      addps(vedgefilename[inc], psfilename, eps);
++      break;
++    default:
++      break;
++  }
++  if (print_head(psfilename, &psfile, llcornerx, llcornery, eps)) {
++    return;
++  }
++  switch(image) {
++    case NODE:
++      print_node(psfile, nodes[inc], node_dim[inc], nodeptr[inc],
++                 xxscale, yyscale, xxoffset, yyoffset);
++      break;
++    case POLY:
++      if (polynodes[inc] > 0) {
++        print_poly(psfile, polynodes[inc], poly_dim[inc], polyedges[inc],
++                   polyholes[inc], polynodeptr[inc], polyedgeptr[inc],
++                   polyholeptr[inc], xxscale, yyscale, xxoffset, yyoffset);
++      } else {
++        print_poly(psfile, nodes[inc], node_dim[inc], polyedges[inc],
++                   polyholes[inc], nodeptr[inc], polyedgeptr[inc],
++                   polyholeptr[inc], xxscale, yyscale, xxoffset, yyoffset);
++      }
++      break;
++    case ELE:
++      print_ele(psfile, nodes[inc], node_dim[inc], elems[inc],
++                ele_corners[inc], nodeptr[inc], eleptr[inc],
++                (int *) NULL, (REAL *) NULL,
++                xxscale, yyscale, xxoffset, yyoffset, llcornerx, llcornery);
++      break;
++    case EDGE:
++      print_edge(psfile, nodes[inc], node_dim[inc], edges[inc],
++                 nodeptr[inc], edgeptr[inc], normptr[inc],
++                 xxscale, yyscale, xxoffset, yyoffset, llcornerx, llcornery);
++      break;
++    case PART:
++      print_ele(psfile, nodes[inc], node_dim[inc], elems[inc],
++                ele_corners[inc], nodeptr[inc], eleptr[inc],
++                partpart[inc], partshift[inc],
++                xxscale, yyscale, xxoffset, yyoffset, llcornerx, llcornery);
++      break;
++    case ADJ:
++      print_adj(psfile, node_dim[inc], adjsubdomains[inc], adjptr[inc],
++                partcenter[inc],
++                xxscale, yyscale, xxoffset, yyoffset, llcornerx, llcornery);
++      break;
++    case VORO:
++      print_edge(psfile, vnodes[inc], vnode_dim[inc], vedges[inc],
++                 vnodeptr[inc], vedgeptr[inc], vnormptr[inc],
++                 xxscale, yyscale, xxoffset, yyoffset, llcornerx, llcornery);
++      break;
++    default:
++      break;
++  }
++  if (!eps) {
++    fprintf(psfile, "showpage\n");
++  }
++  fclose(psfile);
++}
++
++int main(argc, argv)
++int argc;
++char **argv;
++{
++  REAL xmin, ymin, xmax, ymax;
++  REAL xptr, yptr, xspan, yspan;
++  int past_image;
++  int new_image;
++  int new_inc;
++
++  parsecommandline(argc, argv);
++  showme_init();
++  choose_image(start_inc, start_image);
++  showme_window(argc, argv);
++
++  if (current_image != NOTHING) {
++    xmin = xlo[current_inc][current_image];
++    ymin = ylo[current_inc][current_image];
++    xmax = xhi[current_inc][current_image];
++    ymax = yhi[current_inc][current_image];
++    zoom = 0;
++  }
++
++  XMaskEvent(display, ExposureMask, &event);
++  while (1) {
++    switch (event.type) {
++      case ButtonRelease:
++        if (event.xany.window == quitwin) {
++          XDestroyWindow(display, mainwindow);
++          XCloseDisplay(display);
++          return 0;
++        } else if (event.xany.window == leftwin) {
++          xspan = 0.25 * (xmax - xmin);
++          xmin += xspan;
++          xmax += xspan;
++          draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++        } else if (event.xany.window == rightwin) {
++          xspan = 0.25 * (xmax - xmin);
++          xmin -= xspan;
++          xmax -= xspan;
++          draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++        } else if (event.xany.window == upwin) {
++          yspan = 0.25 * (ymax - ymin);
++          ymin -= yspan;
++          ymax -= yspan;
++          draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++        } else if (event.xany.window == downwin) {
++          yspan = 0.25 * (ymax - ymin);
++          ymin += yspan;
++          ymax += yspan;
++          draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++        } else if (event.xany.window == resetwin) {
++          xmin = xlo[current_inc][current_image];
++          ymin = ylo[current_inc][current_image];
++          xmax = xhi[current_inc][current_image];
++          ymax = yhi[current_inc][current_image];
++          zoom = 0;
++          draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++        } else if (event.xany.window == widthpluswin) {
++          if (line_width < 100) {
++            line_width++;
++            XSetLineAttributes(display, linegc, line_width, LineSolid,
++                               CapRound, JoinRound);
++            XSetLineAttributes(display, trianglegc, line_width, LineSolid,
++                               CapRound, JoinRound);
++            draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++          }
++        } else if (event.xany.window == widthminuswin) {
++          if (line_width > 1) {
++            line_width--;
++            XSetLineAttributes(display, linegc, line_width, LineSolid,
++                               CapRound, JoinRound);
++            XSetLineAttributes(display, trianglegc, line_width, LineSolid,
++                               CapRound, JoinRound);
++            draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++          }
++        } else if (event.xany.window == expwin) {
++          if ((current_image == PART) && loaded[current_inc][PART]) {
++            explode = !explode;
++            draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++          }
++        } else if (event.xany.window == exppluswin) {
++          if ((current_image == PART) && loaded[PART] && explode) {
++            explosion += 0.125;
++            findpartshift(subdomains[current_inc], explosion,
++                          partcenter[current_inc], partshift[current_inc]);
++            draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++          }
++        } else if (event.xany.window == expminuswin) {
++          if ((current_image == PART) && loaded[PART] && explode &&
++              (explosion >= 0.125)) {
++            explosion -= 0.125;
++            findpartshift(subdomains[current_inc], explosion,
++                          partcenter[current_inc], partshift[current_inc]);
++            draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++          }
++        } else if (event.xany.window == fillwin) {
++          if ((current_image == PART) && loaded[PART]) {
++            fillelem = !fillelem;
++            draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++          }
++        } else if (event.xany.window == pswin) {
++          fill_button(pswin);
++          XFlush(display);
++          print(current_inc, current_image, xmin, ymin, xmax, ymax, 0);
++          XClearWindow(display, pswin);
++          XDrawString(display, pswin, fontgc, 2, 13, "PS", 2);
++        } else if (event.xany.window == epswin) {
++          fill_button(epswin);
++          XFlush(display);
++          print(current_inc, current_image, xmin, ymin, xmax, ymax, 1);
++          XClearWindow(display, epswin);
++          XDrawString(display, epswin, fontgc, 2, 13, "EPS", 3);
++        } else if (event.xany.window == versionpluswin) {
++          move_inc(1);
++          loweriteration++;
++          set_filenames(filename, loweriteration);
++          if (current_inc == 1) {
++            current_inc = 0;
++          } else {
++            current_image = NOTHING;
++            XClearWindow(display, mainwindow);
++          }
++          draw_buttons();
++        } else if (event.xany.window == versionminuswin) {
++          if (loweriteration > 0) {
++            move_inc(0);
++            loweriteration--;
++            set_filenames(filename, loweriteration);
++            if (current_inc == 0) {
++              current_inc = 1;
++            } else {
++              current_image = NOTHING;
++              XClearWindow(display, mainwindow);
++            }
++            draw_buttons();
++          }
++        } else if ((event.xany.window == nodewin[0]) ||
++                   (event.xany.window == polywin[0]) ||
++                   (event.xany.window == elewin[0]) ||
++                   (event.xany.window == edgewin[0]) ||
++                   (event.xany.window == partwin[0]) ||
++                   (event.xany.window == adjwin[0]) ||
++                   (event.xany.window == voronoiwin[0]) ||
++                   (event.xany.window == nodewin[1]) ||
++                   (event.xany.window == polywin[1]) ||
++                   (event.xany.window == elewin[1]) ||
++                   (event.xany.window == edgewin[1]) ||
++                   (event.xany.window == partwin[1]) ||
++                   (event.xany.window == adjwin[1]) ||
++                   (event.xany.window == voronoiwin[1])) {
++          if (event.xany.window == nodewin[0]) {
++            new_inc = 0;
++            new_image = NODE;
++          }
++          if (event.xany.window == polywin[0]) {
++            new_inc = 0;
++            new_image = POLY;
++          }
++          if (event.xany.window == elewin[0]) {
++            new_inc = 0;
++            new_image = ELE;
++          }
++          if (event.xany.window == edgewin[0]) {
++            new_inc = 0;
++            new_image = EDGE;
++          }
++          if (event.xany.window == partwin[0]) {
++            new_inc = 0;
++            new_image = PART;
++          }
++          if (event.xany.window == adjwin[0]) {
++            new_inc = 0;
++            new_image = ADJ;
++          }
++          if (event.xany.window == voronoiwin[0]) {
++            new_inc = 0;
++            new_image = VORO;
++          }
++          if (event.xany.window == nodewin[1]) {
++            new_inc = 1;
++            new_image = NODE;
++          }
++          if (event.xany.window == polywin[1]) {
++            new_inc = 1;
++            new_image = POLY;
++          }
++          if (event.xany.window == elewin[1]) {
++            new_inc = 1;
++            new_image = ELE;
++          }
++          if (event.xany.window == edgewin[1]) {
++            new_inc = 1;
++            new_image = EDGE;
++          }
++          if (event.xany.window == partwin[1]) {
++            new_inc = 1;
++            new_image = PART;
++          }
++          if (event.xany.window == adjwin[1]) {
++            new_inc = 1;
++            new_image = ADJ;
++          }
++          if (event.xany.window == voronoiwin[1]) {
++            new_inc = 1;
++            new_image = VORO;
++          }
++          past_image = current_image;
++          if ((current_inc == new_inc) && (current_image == new_image)) {
++            free_inc(new_inc);
++            unload_inc(new_inc);
++          }
++          choose_image(new_inc, new_image);
++          if ((past_image == NOTHING) && (current_image != NOTHING)) {
++            xmin = xlo[current_inc][current_image];
++            ymin = ylo[current_inc][current_image];
++            xmax = xhi[current_inc][current_image];
++            ymax = yhi[current_inc][current_image];
++            zoom = 0;
++          }
++          draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++        } else {
++          xptr = ((REAL) event.xbutton.x - xoffset) / xscale;
++          yptr = ((REAL) event.xbutton.y - yoffset) / yscale;
++          if ((current_image == PART) && loaded[PART] && explode) {
++            xptr = (xptr + partcenter[current_inc]
++                                     [subdomains[current_inc] << 1]
++                    * explosion) / (1.0 + explosion);
++            yptr = (yptr + partcenter[current_inc]
++                                     [(subdomains[current_inc] << 1) + 1]
++                    * explosion) / (1.0 + explosion);
++          }
++          if ((event.xbutton.button == Button1)
++              || (event.xbutton.button == Button3)) {
++            if (event.xbutton.button == Button1) {
++              xspan = 0.25 * (xmax - xmin);
++              yspan = 0.25 * (ymax - ymin);
++              zoom++;
++            } else {
++              xspan = xmax - xmin;
++              yspan = ymax - ymin;
++              zoom--;
++            }
++            xmin = xptr - xspan;
++            ymin = yptr - yspan;
++            xmax = xptr + xspan;
++            ymax = yptr + yspan;
++            draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++          } else if (event.xbutton.button == Button2) {
++            printf("x = %.9f, y = %.9f\n", xptr, yptr);
++          }
++        }
++        break;
++      case DestroyNotify:
++        XDestroyWindow(display, mainwindow);
++        XCloseDisplay(display);
++        return 0;
++      case ConfigureNotify:
++        if ((width != event.xconfigure.width) ||
++            (height != event.xconfigure.height - PANELHEIGHT)) {
++          width = event.xconfigure.width;
++          height = event.xconfigure.height - PANELHEIGHT;
++          draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++          while (XCheckMaskEvent(display, ExposureMask, &event));
++        }
++        break;
++      case Expose:
++        draw(current_inc, current_image, xmin, ymin, xmax, ymax);
++        while (XCheckMaskEvent(display, ExposureMask, &event));
++        break;
++      default:
++        break;
++    }
++    XNextEvent(display, &event);
++  }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9af47a493076e40da059a594fff31009d821193e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,13241 @@@
++/*****************************************************************************/
++/*                                                                           */
++/*      888888888        ,o,                          / 888                  */
++/*         888    88o88o  "    o8888o  88o8888o o88888o 888  o88888o         */
++/*         888    888    888       88b 888  888 888 888 888 d888  88b        */
++/*         888    888    888  o88^o888 888  888 "88888" 888 8888oo888        */
++/*         888    888    888 C888  888 888  888  /      888 q888             */
++/*         888    888    888  "88o^888 888  888 Cb      888  "88oooo"        */
++/*                                              "8oo8D                       */
++/*                                                                           */
++/*  A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.      */
++/*  (triangle.c)                                                             */
++/*                                                                           */
++/*  Version 1.3                                                              */
++/*  July 19, 1996                                                            */
++/*                                                                           */
++/*  Copyright 1996                                                           */
++/*  Jonathan Richard Shewchuk                                                */
++/*  School of Computer Science                                               */
++/*  Carnegie Mellon University                                               */
++/*  5000 Forbes Avenue                                                       */
++/*  Pittsburgh, Pennsylvania  15213-3891                                     */
++/*  jrs@cs.cmu.edu                                                           */
++/*                                                                           */
++/*  This program may be freely redistributed under the condition that the    */
++/*    copyright notices (including this entire header and the copyright      */
++/*    notice printed when the `-h' switch is selected) are not removed, and  */
++/*    no compensation is received.  Private, research, and institutional     */
++/*    use is free.  You may distribute modified versions of this code UNDER  */
++/*    THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE   */
++/*    SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE   */
++/*    AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR    */
++/*    NOTICE IS GIVEN OF THE MODIFICATIONS.  Distribution of this code as    */
++/*    part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT  */
++/*    WITH THE AUTHOR.  (If you are not directly supplying this code to a    */
++/*    customer, and you are instead telling them how they can obtain it for  */
++/*    free, then you are not required to make any arrangement with me.)      */
++/*                                                                           */
++/*  Hypertext instructions for Triangle are available on the Web at          */
++/*                                                                           */
++/*      http://www.cs.cmu.edu/~quake/triangle.html                           */
++/*                                                                           */
++/*  Some of the references listed below are marked [*].  These are available */
++/*    for downloading from the Web page                                      */
++/*                                                                           */
++/*      http://www.cs.cmu.edu/~quake/triangle.research.html                  */
++/*                                                                           */
++/*  A paper discussing some aspects of Triangle is available.  See Jonathan  */
++/*    Richard Shewchuk, "Triangle:  Engineering a 2D Quality Mesh Generator  */
++/*    and Delaunay Triangulator," First Workshop on Applied Computational    */
++/*    Geometry, ACM, May 1996.  [*]                                          */
++/*                                                                           */
++/*  Triangle was created as part of the Archimedes project in the School of  */
++/*    Computer Science at Carnegie Mellon University.  Archimedes is a       */
++/*    system for compiling parallel finite element solvers.  For further     */
++/*    information, see Anja Feldmann, Omar Ghattas, John R. Gilbert, Gary L. */
++/*    Miller, David R. O'Hallaron, Eric J. Schwabe, Jonathan R. Shewchuk,    */
++/*    and Shang-Hua Teng, "Automated Parallel Solution of Unstructured PDE   */
++/*    Problems."  To appear in Communications of the ACM, we hope.           */
++/*                                                                           */
++/*  The quality mesh generation algorithm is due to Jim Ruppert, "A          */
++/*    Delaunay Refinement Algorithm for Quality 2-Dimensional Mesh           */
++/*    Generation," Journal of Algorithms 18(3):548-585, May 1995.  [*]       */
++/*                                                                           */
++/*  My implementation of the divide-and-conquer and incremental Delaunay     */
++/*    triangulation algorithms follows closely the presentation of Guibas    */
++/*    and Stolfi, even though I use a triangle-based data structure instead  */
++/*    of their quad-edge data structure.  (In fact, I originally implemented */
++/*    Triangle using the quad-edge data structure, but switching to a        */
++/*    triangle-based data structure sped Triangle by a factor of two.)  The  */
++/*    mesh manipulation primitives and the two aforementioned Delaunay       */
++/*    triangulation algorithms are described by Leonidas J. Guibas and Jorge */
++/*    Stolfi, "Primitives for the Manipulation of General Subdivisions and   */
++/*    the Computation of Voronoi Diagrams," ACM Transactions on Graphics     */
++/*    4(2):74-123, April 1985.                                               */
++/*                                                                           */
++/*  Their O(n log n) divide-and-conquer algorithm is adapted from Der-Tsai   */
++/*    Lee and Bruce J. Schachter, "Two Algorithms for Constructing the       */
++/*    Delaunay Triangulation," International Journal of Computer and         */
++/*    Information Science 9(3):219-242, 1980.  The idea to improve the       */
++/*    divide-and-conquer algorithm by alternating between vertical and       */
++/*    horizontal cuts was introduced by Rex A. Dwyer, "A Faster Divide-and-  */
++/*    Conquer Algorithm for Constructing Delaunay Triangulations,"           */
++/*    Algorithmica 2(2):137-151, 1987.                                       */
++/*                                                                           */
++/*  The incremental insertion algorithm was first proposed by C. L. Lawson,  */
++/*    "Software for C1 Surface Interpolation," in Mathematical Software III, */
++/*    John R. Rice, editor, Academic Press, New York, pp. 161-194, 1977.     */
++/*    For point location, I use the algorithm of Ernst P. Mucke, Isaac       */
++/*    Saias, and Binhai Zhu, "Fast Randomized Point Location Without         */
++/*    Preprocessing in Two- and Three-dimensional Delaunay Triangulations,"  */
++/*    Proceedings of the Twelfth Annual Symposium on Computational Geometry, */
++/*    ACM, May 1996.  [*]  If I were to randomize the order of point         */
++/*    insertion (I currently don't bother), their result combined with the   */
++/*    result of Leonidas J. Guibas, Donald E. Knuth, and Micha Sharir,       */
++/*    "Randomized Incremental Construction of Delaunay and Voronoi           */
++/*    Diagrams," Algorithmica 7(4):381-413, 1992, would yield an expected    */
++/*    O(n^{4/3}) bound on running time.                                      */
++/*                                                                           */
++/*  The O(n log n) sweepline Delaunay triangulation algorithm is taken from  */
++/*    Steven Fortune, "A Sweepline Algorithm for Voronoi Diagrams",          */
++/*    Algorithmica 2(2):153-174, 1987.  A random sample of edges on the      */
++/*    boundary of the triangulation are maintained in a splay tree for the   */
++/*    purpose of point location.  Splay trees are described by Daniel        */
++/*    Dominic Sleator and Robert Endre Tarjan, "Self-Adjusting Binary Search */
++/*    Trees," Journal of the ACM 32(3):652-686, July 1985.                   */
++/*                                                                           */
++/*  The algorithms for exact computation of the signs of determinants are    */
++/*    described in Jonathan Richard Shewchuk, "Adaptive Precision Floating-  */
++/*    Point Arithmetic and Fast Robust Geometric Predicates," Technical      */
++/*    Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon      */
++/*    University, Pittsburgh, Pennsylvania, May 1996.  [*]  (Submitted to    */
++/*    Discrete & Computational Geometry.)  An abbreviated version appears as */
++/*    Jonathan Richard Shewchuk, "Robust Adaptive Floating-Point Geometric   */
++/*    Predicates," Proceedings of the Twelfth Annual Symposium on Computa-   */
++/*    tional Geometry, ACM, May 1996.  [*]  Many of the ideas for my exact   */
++/*    arithmetic routines originate with Douglas M. Priest, "Algorithms for  */
++/*    Arbitrary Precision Floating Point Arithmetic," Tenth Symposium on     */
++/*    Computer Arithmetic, 132-143, IEEE Computer Society Press, 1991.  [*]  */
++/*    Many of the ideas for the correct evaluation of the signs of           */
++/*    determinants are taken from Steven Fortune and Christopher J. Van Wyk, */
++/*    "Efficient Exact Arithmetic for Computational Geometry," Proceedings   */
++/*    of the Ninth Annual Symposium on Computational Geometry, ACM,          */
++/*    pp. 163-172, May 1993, and from Steven Fortune, "Numerical Stability   */
++/*    of Algorithms for 2D Delaunay Triangulations," International Journal   */
++/*    of Computational Geometry & Applications 5(1-2):193-213, March-June    */
++/*    1995.                                                                  */
++/*                                                                           */
++/*  For definitions of and results involving Delaunay triangulations,        */
++/*    constrained and conforming versions thereof, and other aspects of      */
++/*    triangular mesh generation, see the excellent survey by Marshall Bern  */
++/*    and David Eppstein, "Mesh Generation and Optimal Triangulation," in    */
++/*    Computing and Euclidean Geometry, Ding-Zhu Du and Frank Hwang,         */
++/*    editors, World Scientific, Singapore, pp. 23-90, 1992.                 */
++/*                                                                           */
++/*  The time for incrementally adding PSLG (planar straight line graph)      */
++/*    segments to create a constrained Delaunay triangulation is probably    */
++/*    O(n^2) per segment in the worst case and O(n) per edge in the common   */
++/*    case, where n is the number of triangles that intersect the segment    */
++/*    before it is inserted.  This doesn't count point location, which can   */
++/*    be much more expensive.  (This note does not apply to conforming       */
++/*    Delaunay triangulations, for which a different method is used to       */
++/*    insert segments.)                                                      */
++/*                                                                           */
++/*  The time for adding segments to a conforming Delaunay triangulation is   */
++/*    not clear, but does not depend upon n alone.  In some cases, very      */
++/*    small features (like a point lying next to a segment) can cause a      */
++/*    single segment to be split an arbitrary number of times.  Of course,   */
++/*    floating-point precision is a practical barrier to how much this can   */
++/*    happen.                                                                */
++/*                                                                           */
++/*  The time for deleting a point from a Delaunay triangulation is O(n^2) in */
++/*    the worst case and O(n) in the common case, where n is the degree of   */
++/*    the point being deleted.  I could improve this to expected O(n) time   */
++/*    by "inserting" the neighboring vertices in random order, but n is      */
++/*    usually quite small, so it's not worth the bother.  (The O(n) time     */
++/*    for random insertion follows from L. Paul Chew, "Building Voronoi      */
++/*    Diagrams for Convex Polygons in Linear Expected Time," Technical       */
++/*    Report PCS-TR90-147, Department of Mathematics and Computer Science,   */
++/*    Dartmouth College, 1990.                                               */
++/*                                                                           */
++/*  Ruppert's Delaunay refinement algorithm typically generates triangles    */
++/*    at a linear rate (constant time per triangle) after the initial        */
++/*    triangulation is formed.  There may be pathological cases where more   */
++/*    time is required, but these never arise in practice.                   */
++/*                                                                           */
++/*  The segment intersection formulae are straightforward.  If you want to   */
++/*    see them derived, see Franklin Antonio.  "Faster Line Segment          */
++/*    Intersection."  In Graphics Gems III (David Kirk, editor), pp. 199-    */
++/*    202.  Academic Press, Boston, 1992.                                    */
++/*                                                                           */
++/*  If you make any improvements to this code, please please please let me   */
++/*    know, so that I may obtain the improvements.  Even if you don't change */
++/*    the code, I'd still love to hear what it's being used for.             */
++/*                                                                           */
++/*  Disclaimer:  Neither I nor Carnegie Mellon warrant this code in any way  */
++/*    whatsoever.  This code is provided "as-is".  Use at your own risk.     */
++/*                                                                           */
++/*****************************************************************************/
++
++/* For single precision (which will save some memory and reduce paging),     */
++/*   define the symbol SINGLE by using the -DSINGLE compiler switch or by    */
++/*   writing "#define SINGLE" below.                                         */
++/*                                                                           */
++/* For double precision (which will allow you to refine meshes to a smaller  */
++/*   edge length), leave SINGLE undefined.                                   */
++/*                                                                           */
++/* Double precision uses more memory, but improves the resolution of the     */
++/*   meshes you can generate with Triangle.  It also reduces the likelihood  */
++/*   of a floating exception due to overflow.  Finally, it is much faster    */
++/*   than single precision on 64-bit architectures like the DEC Alpha.  I    */
++/*   recommend double precision unless you want to generate a mesh for which */
++/*   you do not have enough memory.                                          */
++
++/* #define SINGLE */
++
++#ifdef SINGLE
++#define REAL float
++#else /* not SINGLE */
++#define REAL double
++#endif /* not SINGLE */
++
++/* If yours is not a Unix system, define the NO_TIMER compiler switch to     */
++/*   remove the Unix-specific timing code.                                   */
++
++/* #define NO_TIMER */
++
++/* To insert lots of self-checks for internal errors, define the SELF_CHECK  */
++/*   symbol.  This will slow down the program significantly.  It is best to  */
++/*   define the symbol using the -DSELF_CHECK compiler switch, but you could */
++/*   write "#define SELF_CHECK" below.  If you are modifying this code, I    */
++/*   recommend you turn self-checks on.                                      */
++
++/* #define SELF_CHECK */
++
++/* To compile Triangle as a callable object library (triangle.o), define the */
++/*   TRILIBRARY symbol.  Read the file triangle.h for details on how to call */
++/*   the procedure triangulate() that results.                               */
++
++/* #define TRILIBRARY */
++
++/* It is possible to generate a smaller version of Triangle using one or     */
++/*   both of the following symbols.  Define the REDUCED symbol to eliminate  */
++/*   all features that are primarily of research interest; specifically, the */
++/*   -i, -F, -s, and -C switches.  Define the CDT_ONLY symbol to eliminate   */
++/*   all meshing algorithms above and beyond constrained Delaunay            */
++/*   triangulation; specifically, the -r, -q, -a, -S, and -s switches.       */
++/*   These reductions are most likely to be useful when generating an object */
++/*   library (triangle.o) by defining the TRILIBRARY symbol.                 */
++
++/* #define REDUCED */
++/* #define CDT_ONLY */
++
++/* On some machines, the exact arithmetic routines might be defeated by the  */
++/*   use of internal extended precision floating-point registers.  Sometimes */
++/*   this problem can be fixed by defining certain values to be volatile,    */
++/*   thus forcing them to be stored to memory and rounded off.  This isn't   */
++/*   a great solution, though, as it slows Triangle down.                    */
++/*                                                                           */
++/* To try this out, write "#define INEXACT volatile" below.  Normally,       */
++/*   however, INEXACT should be defined to be nothing.  ("#define INEXACT".) */
++
++#define INEXACT /* Nothing */
++/* #define INEXACT volatile */
++
++/* Maximum number of characters in a file name (including the null).         */
++
++#define FILENAMESIZE 512
++
++/* Maximum number of characters in a line read from a file (including the    */
++/*   null).                                                                  */
++
++#define INPUTLINESIZE 512
++
++/* For efficiency, a variety of data structures are allocated in bulk.  The  */
++/*   following constants determine how many of each structure is allocated   */
++/*   at once.                                                                */
++
++#define TRIPERBLOCK 4092           /* Number of triangles allocated at once. */
++#define SHELLEPERBLOCK 508       /* Number of shell edges allocated at once. */
++#define POINTPERBLOCK 4092            /* Number of points allocated at once. */
++#define VIRUSPERBLOCK 1020   /* Number of virus triangles allocated at once. */
++/* Number of encroached segments allocated at once. */
++#define BADSEGMENTPERBLOCK 252
++/* Number of skinny triangles allocated at once. */
++#define BADTRIPERBLOCK 4092
++/* Number of splay tree nodes allocated at once. */
++#define SPLAYNODEPERBLOCK 508
++
++/* The point marker DEADPOINT is an arbitrary number chosen large enough to  */
++/*   (hopefully) not conflict with user boundary markers.  Make sure that it */
++/*   is small enough to fit into your machine's integer size.                */
++
++#define DEADPOINT -1073741824
++
++/* The next line is used to outsmart some very stupid compilers.  If your    */
++/*   compiler is smarter, feel free to replace the "int" with "void".        */
++/*   Not that it matters.                                                    */
++
++#define VOID int
++
++/* Two constants for algorithms based on random sampling.  Both constants    */
++/*   have been chosen empirically to optimize their respective algorithms.   */
++
++/* Used for the point location scheme of Mucke, Saias, and Zhu, to decide    */
++/*   how large a random sample of triangles to inspect.                      */
++#define SAMPLEFACTOR 11
++/* Used in Fortune's sweepline Delaunay algorithm to determine what fraction */
++/*   of boundary edges should be maintained in the splay tree for point      */
++/*   location on the front.                                                  */
++#define SAMPLERATE 10
++
++/* A number that speaks for itself, every kissable digit.                    */
++
++#define PI 3.141592653589793238462643383279502884197169399375105820974944592308
++
++/* Another fave.                                                             */
++
++#define SQUAREROOTTWO 1.4142135623730950488016887242096980785696718753769480732
++
++/* And here's one for those of you who are intimidated by math.              */
++
++#define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333
++
++#include <stdio.h>
++#include <string.h>
++#include <math.h>
++#ifndef NO_TIMER
++#include <sys/time.h>
++#endif /* NO_TIMER */
++#ifdef TRILIBRARY
++#include "triangle.h"
++#endif /* TRILIBRARY */
++
++/* The following obscenity seems to be necessary to ensure that this program */
++/* will port to Dec Alphas running OSF/1, because their stdio.h file commits */
++/* the unpardonable sin of including stdlib.h.  Hence, malloc(), free(), and */
++/* exit() may or may not already be defined at this point.  I declare these  */
++/* functions explicitly because some non-ANSI C compilers lack stdlib.h.     */
++
++#ifndef _STDLIB_H_
++extern void *malloc();
++extern void free();
++extern void exit();
++extern double strtod();
++extern long strtol();
++#endif /* _STDLIB_H_ */
++
++/* A few forward declarations.                                               */
++
++void poolrestart();
++#ifndef TRILIBRARY
++char *readline();
++char *findfield();
++#endif /* not TRILIBRARY */
++
++/* Labels that signify whether a record consists primarily of pointers or of */
++/*   floating-point words.  Used to make decisions about data alignment.     */
++
++enum wordtype {POINTER, FLOATINGPOINT};
++
++/* Labels that signify the result of point location.  The result of a        */
++/*   search indicates that the point falls in the interior of a triangle, on */
++/*   an edge, on a vertex, or outside the mesh.                              */
++
++enum locateresult {INTRIANGLE, ONEDGE, ONVERTEX, OUTSIDE};
++
++/* Labels that signify the result of site insertion.  The result indicates   */
++/*   that the point was inserted with complete success, was inserted but     */
++/*   encroaches on a segment, was not inserted because it lies on a segment, */
++/*   or was not inserted because another point occupies the same location.   */
++
++enum insertsiteresult {SUCCESSFULPOINT, ENCROACHINGPOINT, VIOLATINGPOINT,
++                       DUPLICATEPOINT};
++
++/* Labels that signify the result of direction finding.  The result          */
++/*   indicates that a segment connecting the two query points falls within   */
++/*   the direction triangle, along the left edge of the direction triangle,  */
++/*   or along the right edge of the direction triangle.                      */
++
++enum finddirectionresult {WITHIN, LEFTCOLLINEAR, RIGHTCOLLINEAR};
++
++/* Labels that signify the result of the circumcenter computation routine.   */
++/*   The return value indicates which edge of the triangle is shortest.      */
++
++enum circumcenterresult {OPPOSITEORG, OPPOSITEDEST, OPPOSITEAPEX};
++
++/*****************************************************************************/
++/*                                                                           */
++/*  The basic mesh data structures                                           */
++/*                                                                           */
++/*  There are three:  points, triangles, and shell edges (abbreviated        */
++/*  `shelle').  These three data structures, linked by pointers, comprise    */
++/*  the mesh.  A point simply represents a point in space and its properties.*/
++/*  A triangle is a triangle.  A shell edge is a special data structure used */
++/*  to represent impenetrable segments in the mesh (including the outer      */
++/*  boundary, boundaries of holes, and internal boundaries separating two    */
++/*  triangulated regions).  Shell edges represent boundaries defined by the  */
++/*  user that triangles may not lie across.                                  */
++/*                                                                           */
++/*  A triangle consists of a list of three vertices, a list of three         */
++/*  adjoining triangles, a list of three adjoining shell edges (when shell   */
++/*  edges are used), an arbitrary number of optional user-defined floating-  */
++/*  point attributes, and an optional area constraint.  The latter is an     */
++/*  upper bound on the permissible area of each triangle in a region, used   */
++/*  for mesh refinement.                                                     */
++/*                                                                           */
++/*  For a triangle on a boundary of the mesh, some or all of the neighboring */
++/*  triangles may not be present.  For a triangle in the interior of the     */
++/*  mesh, often no neighboring shell edges are present.  Such absent         */
++/*  triangles and shell edges are never represented by NULL pointers; they   */
++/*  are represented by two special records:  `dummytri', the triangle that   */
++/*  fills "outer space", and `dummysh', the omnipresent shell edge.          */
++/*  `dummytri' and `dummysh' are used for several reasons; for instance,     */
++/*  they can be dereferenced and their contents examined without causing the */
++/*  memory protection exception that would occur if NULL were dereferenced.  */
++/*                                                                           */
++/*  However, it is important to understand that a triangle includes other    */
++/*  information as well.  The pointers to adjoining vertices, triangles, and */
++/*  shell edges are ordered in a way that indicates their geometric relation */
++/*  to each other.  Furthermore, each of these pointers contains orientation */
++/*  information.  Each pointer to an adjoining triangle indicates which face */
++/*  of that triangle is contacted.  Similarly, each pointer to an adjoining  */
++/*  shell edge indicates which side of that shell edge is contacted, and how */
++/*  the shell edge is oriented relative to the triangle.                     */
++/*                                                                           */
++/*  Shell edges are found abutting edges of triangles; either sandwiched     */
++/*  between two triangles, or resting against one triangle on an exterior    */
++/*  boundary or hole boundary.                                               */
++/*                                                                           */
++/*  A shell edge consists of a list of two vertices, a list of two           */
++/*  adjoining shell edges, and a list of two adjoining triangles.  One of    */
++/*  the two adjoining triangles may not be present (though there should      */
++/*  always be one), and neighboring shell edges might not be present.        */
++/*  Shell edges also store a user-defined integer "boundary marker".         */
++/*  Typically, this integer is used to indicate what sort of boundary        */
++/*  conditions are to be applied at that location in a finite element        */
++/*  simulation.                                                              */
++/*                                                                           */
++/*  Like triangles, shell edges maintain information about the relative      */
++/*  orientation of neighboring objects.                                      */
++/*                                                                           */
++/*  Points are relatively simple.  A point is a list of floating point       */
++/*  numbers, starting with the x, and y coordinates, followed by an          */
++/*  arbitrary number of optional user-defined floating-point attributes,     */
++/*  followed by an integer boundary marker.  During the segment insertion    */
++/*  phase, there is also a pointer from each point to a triangle that may    */
++/*  contain it.  Each pointer is not always correct, but when one is, it     */
++/*  speeds up segment insertion.  These pointers are assigned values once    */
++/*  at the beginning of the segment insertion phase, and are not used or     */
++/*  updated at any other time.  Edge swapping during segment insertion will  */
++/*  render some of them incorrect.  Hence, don't rely upon them for          */
++/*  anything.  For the most part, points do not have any information about   */
++/*  what triangles or shell edges they are linked to.                        */
++/*                                                                           */
++/*****************************************************************************/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  Handles                                                                  */
++/*                                                                           */
++/*  The oriented triangle (`triedge') and oriented shell edge (`edge') data  */
++/*  structures defined below do not themselves store any part of the mesh.   */
++/*  The mesh itself is made of `triangle's, `shelle's, and `point's.         */
++/*                                                                           */
++/*  Oriented triangles and oriented shell edges will usually be referred to  */
++/*  as "handles".  A handle is essentially a pointer into the mesh; it       */
++/*  allows you to "hold" one particular part of the mesh.  Handles are used  */
++/*  to specify the regions in which one is traversing and modifying the mesh.*/
++/*  A single `triangle' may be held by many handles, or none at all.  (The   */
++/*  latter case is not a memory leak, because the triangle is still          */
++/*  connected to other triangles in the mesh.)                               */
++/*                                                                           */
++/*  A `triedge' is a handle that holds a triangle.  It holds a specific side */
++/*  of the triangle.  An `edge' is a handle that holds a shell edge.  It     */
++/*  holds either the left or right side of the edge.                         */
++/*                                                                           */
++/*  Navigation about the mesh is accomplished through a set of mesh          */
++/*  manipulation primitives, further below.  Many of these primitives take   */
++/*  a handle and produce a new handle that holds the mesh near the first     */
++/*  handle.  Other primitives take two handles and glue the corresponding    */
++/*  parts of the mesh together.  The exact position of the handles is        */
++/*  important.  For instance, when two triangles are glued together by the   */
++/*  bond() primitive, they are glued by the sides on which the handles lie.  */
++/*                                                                           */
++/*  Because points have no information about which triangles they are        */
++/*  attached to, I commonly represent a point by use of a handle whose       */
++/*  origin is the point.  A single handle can simultaneously represent a     */
++/*  triangle, an edge, and a point.                                          */
++/*                                                                           */
++/*****************************************************************************/
++
++/* The triangle data structure.  Each triangle contains three pointers to    */
++/*   adjoining triangles, plus three pointers to vertex points, plus three   */
++/*   pointers to shell edges (defined below; these pointers are usually      */
++/*   `dummysh').  It may or may not also contain user-defined attributes     */
++/*   and/or a floating-point "area constraint".  It may also contain extra   */
++/*   pointers for nodes, when the user asks for high-order elements.         */
++/*   Because the size and structure of a `triangle' is not decided until     */
++/*   runtime, I haven't simply defined the type `triangle' to be a struct.   */
++
++typedef REAL **triangle;            /* Really:  typedef triangle *triangle   */
++
++/* An oriented triangle:  includes a pointer to a triangle and orientation.  */
++/*   The orientation denotes an edge of the triangle.  Hence, there are      */
++/*   three possible orientations.  By convention, each edge is always        */
++/*   directed to point counterclockwise about the corresponding triangle.    */
++
++struct triedge {
++  triangle *tri;
++  int orient;                                         /* Ranges from 0 to 2. */
++};
++
++/* The shell data structure.  Each shell edge contains two pointers to       */
++/*   adjoining shell edges, plus two pointers to vertex points, plus two     */
++/*   pointers to adjoining triangles, plus one shell marker.                 */
++
++typedef REAL **shelle;                  /* Really:  typedef shelle *shelle   */
++
++/* An oriented shell edge:  includes a pointer to a shell edge and an        */
++/*   orientation.  The orientation denotes a side of the edge.  Hence, there */
++/*   are two possible orientations.  By convention, the edge is always       */
++/*   directed so that the "side" denoted is the right side of the edge.      */
++
++struct edge {
++  shelle *sh;
++  int shorient;                                       /* Ranges from 0 to 1. */
++};
++
++/* The point data structure.  Each point is actually an array of REALs.      */
++/*   The number of REALs is unknown until runtime.  An integer boundary      */
++/*   marker, and sometimes a pointer to a triangle, is appended after the    */
++/*   REALs.                                                                  */
++
++typedef REAL *point;
++
++/* A queue used to store encroached segments.  Each segment's vertices are   */
++/*   stored so that one can check whether a segment is still the same.       */
++
++struct badsegment {
++  struct edge encsegment;                          /* An encroached segment. */
++  point segorg, segdest;                                /* The two vertices. */
++  struct badsegment *nextsegment;     /* Pointer to next encroached segment. */
++};
++
++/* A queue used to store bad triangles.  The key is the square of the cosine */
++/*   of the smallest angle of the triangle.  Each triangle's vertices are    */
++/*   stored so that one can check whether a triangle is still the same.      */
++
++struct badface {
++  struct triedge badfacetri;                              /* A bad triangle. */
++  REAL key;                             /* cos^2 of smallest (apical) angle. */
++  point faceorg, facedest, faceapex;                  /* The three vertices. */
++  struct badface *nextface;                 /* Pointer to next bad triangle. */
++};
++
++/* A node in a heap used to store events for the sweepline Delaunay          */
++/*   algorithm.  Nodes do not point directly to their parents or children in */
++/*   the heap.  Instead, each node knows its position in the heap, and can   */
++/*   look up its parent and children in a separate array.  The `eventptr'    */
++/*   points either to a `point' or to a triangle (in encoded format, so that */
++/*   an orientation is included).  In the latter case, the origin of the     */
++/*   oriented triangle is the apex of a "circle event" of the sweepline      */
++/*   algorithm.  To distinguish site events from circle events, all circle   */
++/*   events are given an invalid (smaller than `xmin') x-coordinate `xkey'.  */
++
++struct event {
++  REAL xkey, ykey;                              /* Coordinates of the event. */
++  VOID *eventptr;       /* Can be a point or the location of a circle event. */
++  int heapposition;              /* Marks this event's position in the heap. */
++};
++
++/* A node in the splay tree.  Each node holds an oriented ghost triangle     */
++/*   that represents a boundary edge of the growing triangulation.  When a   */
++/*   circle event covers two boundary edges with a triangle, so that they    */
++/*   are no longer boundary edges, those edges are not immediately deleted   */
++/*   from the tree; rather, they are lazily deleted when they are next       */
++/*   encountered.  (Since only a random sample of boundary edges are kept    */
++/*   in the tree, lazy deletion is faster.)  `keydest' is used to verify     */
++/*   that a triangle is still the same as when it entered the splay tree; if */
++/*   it has been rotated (due to a circle event), it no longer represents a  */
++/*   boundary edge and should be deleted.                                    */
++
++struct splaynode {
++  struct triedge keyedge;                  /* Lprev of an edge on the front. */
++  point keydest;            /* Used to verify that splay node is still live. */
++  struct splaynode *lchild, *rchild;              /* Children in splay tree. */
++};
++
++/* A type used to allocate memory.  firstblock is the first block of items.  */
++/*   nowblock is the block from which items are currently being allocated.   */
++/*   nextitem points to the next slab of free memory for an item.            */
++/*   deaditemstack is the head of a linked list (stack) of deallocated items */
++/*   that can be recycled.  unallocateditems is the number of items that     */
++/*   remain to be allocated from nowblock.                                   */
++/*                                                                           */
++/* Traversal is the process of walking through the entire list of items, and */
++/*   is separate from allocation.  Note that a traversal will visit items on */
++/*   the "deaditemstack" stack as well as live items.  pathblock points to   */
++/*   the block currently being traversed.  pathitem points to the next item  */
++/*   to be traversed.  pathitemsleft is the number of items that remain to   */
++/*   be traversed in pathblock.                                              */
++/*                                                                           */
++/* itemwordtype is set to POINTER or FLOATINGPOINT, and is used to suggest   */
++/*   what sort of word the record is primarily made up of.  alignbytes       */
++/*   determines how new records should be aligned in memory.  itembytes and  */
++/*   itemwords are the length of a record in bytes (after rounding up) and   */
++/*   words.  itemsperblock is the number of items allocated at once in a     */
++/*   single block.  items is the number of currently allocated items.        */
++/*   maxitems is the maximum number of items that have been allocated at     */
++/*   once; it is the current number of items plus the number of records kept */
++/*   on deaditemstack.                                                       */
++
++struct memorypool {
++  VOID **firstblock, **nowblock;
++  VOID *nextitem;
++  VOID *deaditemstack;
++  VOID **pathblock;
++  VOID *pathitem;
++  enum wordtype itemwordtype;
++  int alignbytes;
++  int itembytes, itemwords;
++  int itemsperblock;
++  long items, maxitems;
++  int unallocateditems;
++  int pathitemsleft;
++};
++
++/* Variables used to allocate memory for triangles, shell edges, points,     */
++/*   viri (triangles being eaten), bad (encroached) segments, bad (skinny    */
++/*   or too large) triangles, and splay tree nodes.                          */
++
++struct memorypool triangles;
++struct memorypool shelles;
++struct memorypool points;
++struct memorypool viri;
++struct memorypool badsegments;
++struct memorypool badtriangles;
++struct memorypool splaynodes;
++
++/* Variables that maintain the bad triangle queues.  The tails are pointers  */
++/*   to the pointers that have to be filled in to enqueue an item.           */
++
++struct badface *queuefront[64];
++struct badface **queuetail[64];
++
++REAL xmin, xmax, ymin, ymax;                              /* x and y bounds. */
++REAL xminextreme;        /* Nonexistent x value used as a flag in sweepline. */
++int inpoints;                                     /* Number of input points. */
++int inelements;                                /* Number of input triangles. */
++int insegments;                                 /* Number of input segments. */
++int holes;                                         /* Number of input holes. */
++int regions;                                     /* Number of input regions. */
++long edges;                                       /* Number of output edges. */
++int mesh_dim;                                  /* Dimension (ought to be 2). */
++int nextras;                              /* Number of attributes per point. */
++int eextras;                           /* Number of attributes per triangle. */
++long hullsize;                            /* Number of edges of convex hull. */
++int triwords;                                   /* Total words per triangle. */
++int shwords;                                  /* Total words per shell edge. */
++int pointmarkindex;             /* Index to find boundary marker of a point. */
++int point2triindex;         /* Index to find a triangle adjacent to a point. */
++int highorderindex;    /* Index to find extra nodes for high-order elements. */
++int elemattribindex;              /* Index to find attributes of a triangle. */
++int areaboundindex;               /* Index to find area bound of a triangle. */
++int checksegments;           /* Are there segments in the triangulation yet? */
++int readnodefile;                             /* Has a .node file been read? */
++long samples;                /* Number of random samples for point location. */
++unsigned long randomseed;                     /* Current random number seed. */
++
++REAL splitter;       /* Used to split REAL factors for exact multiplication. */
++REAL epsilon;                             /* Floating-point machine epsilon. */
++REAL resulterrbound;
++REAL ccwerrboundA, ccwerrboundB, ccwerrboundC;
++REAL iccerrboundA, iccerrboundB, iccerrboundC;
++
++long incirclecount;                   /* Number of incircle tests performed. */
++long counterclockcount;       /* Number of counterclockwise tests performed. */
++long hyperbolacount;        /* Number of right-of-hyperbola tests performed. */
++long circumcentercount;    /* Number of circumcenter calculations performed. */
++long circletopcount;         /* Number of circle top calculations performed. */
++
++/* Switches for the triangulator.                                            */
++/*   poly: -p switch.  refine: -r switch.                                    */
++/*   quality: -q switch.                                                     */
++/*     minangle: minimum angle bound, specified after -q switch.             */
++/*     goodangle: cosine squared of minangle.                                */
++/*   vararea: -a switch without number.                                      */
++/*   fixedarea: -a switch with number.                                       */
++/*     maxarea: maximum area bound, specified after -a switch.               */
++/*   regionattrib: -A switch.  convex: -c switch.                            */
++/*   firstnumber: inverse of -z switch.  All items are numbered starting     */
++/*     from firstnumber.                                                     */
++/*   edgesout: -e switch.  voronoi: -v switch.                               */
++/*   neighbors: -n switch.  geomview: -g switch.                             */
++/*   nobound: -B switch.  nopolywritten: -P switch.                          */
++/*   nonodewritten: -N switch.  noelewritten: -E switch.                     */
++/*   noiterationnum: -I switch.  noholes: -O switch.                         */
++/*   noexact: -X switch.                                                     */
++/*   order: element order, specified after -o switch.                        */
++/*   nobisect: count of how often -Y switch is selected.                     */
++/*   steiner: maximum number of Steiner points, specified after -S switch.   */
++/*     steinerleft: number of Steiner points not yet used.                   */
++/*   incremental: -i switch.  sweepline: -F switch.                          */
++/*   dwyer: inverse of -l switch.                                            */
++/*   splitseg: -s switch.                                                    */
++/*   docheck: -C switch.                                                     */
++/*   quiet: -Q switch.  verbose: count of how often -V switch is selected.   */
++/*   useshelles: -p, -r, -q, or -c switch; determines whether shell edges    */
++/*     are used at all.                                                      */
++/*                                                                           */
++/* Read the instructions to find out the meaning of these switches.          */
++
++int poly, refine, quality, vararea, fixedarea, regionattrib, convex;
++int firstnumber;
++int edgesout, voronoi, neighbors, geomview;
++int nobound, nopolywritten, nonodewritten, noelewritten, noiterationnum;
++int noholes, noexact;
++int incremental, sweepline, dwyer;
++int splitseg;
++int docheck;
++int quiet, verbose;
++int useshelles;
++int order;
++int nobisect;
++int steiner, steinerleft;
++REAL minangle, goodangle;
++REAL maxarea;
++
++/* Variables for file names.                                                 */
++
++#ifndef TRILIBRARY
++char innodefilename[FILENAMESIZE];
++char inelefilename[FILENAMESIZE];
++char inpolyfilename[FILENAMESIZE];
++char areafilename[FILENAMESIZE];
++char outnodefilename[FILENAMESIZE];
++char outelefilename[FILENAMESIZE];
++char outpolyfilename[FILENAMESIZE];
++char edgefilename[FILENAMESIZE];
++char vnodefilename[FILENAMESIZE];
++char vedgefilename[FILENAMESIZE];
++char neighborfilename[FILENAMESIZE];
++char offfilename[FILENAMESIZE];
++#endif /* not TRILIBRARY */
++
++/* Triangular bounding box points.                                           */
++
++point infpoint1, infpoint2, infpoint3;
++
++/* Pointer to the `triangle' that occupies all of "outer space".             */
++
++triangle *dummytri;
++triangle *dummytribase;      /* Keep base address so we can free() it later. */
++
++/* Pointer to the omnipresent shell edge.  Referenced by any triangle or     */
++/*   shell edge that isn't really connected to a shell edge at that          */
++/*   location.                                                               */
++
++shelle *dummysh;
++shelle *dummyshbase;         /* Keep base address so we can free() it later. */
++
++/* Pointer to a recently visited triangle.  Improves point location if       */
++/*   proximate points are inserted sequentially.                             */
++
++struct triedge recenttri;
++
++/*****************************************************************************/
++/*                                                                           */
++/*  Mesh manipulation primitives.  Each triangle contains three pointers to  */
++/*  other triangles, with orientations.  Each pointer points not to the      */
++/*  first byte of a triangle, but to one of the first three bytes of a       */
++/*  triangle.  It is necessary to extract both the triangle itself and the   */
++/*  orientation.  To save memory, I keep both pieces of information in one   */
++/*  pointer.  To make this possible, I assume that all triangles are aligned */
++/*  to four-byte boundaries.  The `decode' routine below decodes a pointer,  */
++/*  extracting an orientation (in the range 0 to 2) and a pointer to the     */
++/*  beginning of a triangle.  The `encode' routine compresses a pointer to a */
++/*  triangle and an orientation into a single pointer.  My assumptions that  */
++/*  triangles are four-byte-aligned and that the `unsigned long' type is     */
++/*  long enough to hold a pointer are two of the few kludges in this program.*/
++/*                                                                           */
++/*  Shell edges are manipulated similarly.  A pointer to a shell edge        */
++/*  carries both an address and an orientation in the range 0 to 1.          */
++/*                                                                           */
++/*  The other primitives take an oriented triangle or oriented shell edge,   */
++/*  and return an oriented triangle or oriented shell edge or point; or they */
++/*  change the connections in the data structure.                            */
++/*                                                                           */
++/*****************************************************************************/
++
++/********* Mesh manipulation primitives begin here                   *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/* Fast lookup arrays to speed some of the mesh manipulation primitives.     */
++
++int plus1mod3[3] = {1, 2, 0};
++int minus1mod3[3] = {2, 0, 1};
++
++/********* Primitives for triangles                                  *********/
++/*                                                                           */
++/*                                                                           */
++
++/* decode() converts a pointer to an oriented triangle.  The orientation is  */
++/*   extracted from the two least significant bits of the pointer.           */
++
++#define decode(ptr, triedge)                                                  \
++  (triedge).orient = (int) ((unsigned long) (ptr) & (unsigned long) 3l);      \
++  (triedge).tri = (triangle *)                                                \
++                  ((unsigned long) (ptr) ^ (unsigned long) (triedge).orient)
++
++/* encode() compresses an oriented triangle into a single pointer.  It       */
++/*   relies on the assumption that all triangles are aligned to four-byte    */
++/*   boundaries, so the two least significant bits of (triedge).tri are zero.*/
++
++#define encode(triedge)                                                       \
++  (triangle) ((unsigned long) (triedge).tri | (unsigned long) (triedge).orient)
++
++/* The following edge manipulation primitives are all described by Guibas    */
++/*   and Stolfi.  However, they use an edge-based data structure, whereas I  */
++/*   am using a triangle-based data structure.                               */
++
++/* sym() finds the abutting triangle, on the same edge.  Note that the       */
++/*   edge direction is necessarily reversed, because triangle/edge handles   */
++/*   are always directed counterclockwise around the triangle.               */
++
++#define sym(triedge1, triedge2)                                               \
++  ptr = (triedge1).tri[(triedge1).orient];                                    \
++  decode(ptr, triedge2);
++
++#define symself(triedge)                                                      \
++  ptr = (triedge).tri[(triedge).orient];                                      \
++  decode(ptr, triedge);
++
++/* lnext() finds the next edge (counterclockwise) of a triangle.             */
++
++#define lnext(triedge1, triedge2)                                             \
++  (triedge2).tri = (triedge1).tri;                                            \
++  (triedge2).orient = plus1mod3[(triedge1).orient]
++
++#define lnextself(triedge)                                                    \
++  (triedge).orient = plus1mod3[(triedge).orient]
++
++/* lprev() finds the previous edge (clockwise) of a triangle.                */
++
++#define lprev(triedge1, triedge2)                                             \
++  (triedge2).tri = (triedge1).tri;                                            \
++  (triedge2).orient = minus1mod3[(triedge1).orient]
++
++#define lprevself(triedge)                                                    \
++  (triedge).orient = minus1mod3[(triedge).orient]
++
++/* onext() spins counterclockwise around a point; that is, it finds the next */
++/*   edge with the same origin in the counterclockwise direction.  This edge */
++/*   will be part of a different triangle.                                   */
++
++#define onext(triedge1, triedge2)                                             \
++  lprev(triedge1, triedge2);                                                  \
++  symself(triedge2);
++
++#define onextself(triedge)                                                    \
++  lprevself(triedge);                                                         \
++  symself(triedge);
++
++/* oprev() spins clockwise around a point; that is, it finds the next edge   */
++/*   with the same origin in the clockwise direction.  This edge will be     */
++/*   part of a different triangle.                                           */
++
++#define oprev(triedge1, triedge2)                                             \
++  sym(triedge1, triedge2);                                                    \
++  lnextself(triedge2);
++
++#define oprevself(triedge)                                                    \
++  symself(triedge);                                                           \
++  lnextself(triedge);
++
++/* dnext() spins counterclockwise around a point; that is, it finds the next */
++/*   edge with the same destination in the counterclockwise direction.  This */
++/*   edge will be part of a different triangle.                              */
++
++#define dnext(triedge1, triedge2)                                             \
++  sym(triedge1, triedge2);                                                    \
++  lprevself(triedge2);
++
++#define dnextself(triedge)                                                    \
++  symself(triedge);                                                           \
++  lprevself(triedge);
++
++/* dprev() spins clockwise around a point; that is, it finds the next edge   */
++/*   with the same destination in the clockwise direction.  This edge will   */
++/*   be part of a different triangle.                                        */
++
++#define dprev(triedge1, triedge2)                                             \
++  lnext(triedge1, triedge2);                                                  \
++  symself(triedge2);
++
++#define dprevself(triedge)                                                    \
++  lnextself(triedge);                                                         \
++  symself(triedge);
++
++/* rnext() moves one edge counterclockwise about the adjacent triangle.      */
++/*   (It's best understood by reading Guibas and Stolfi.  It involves        */
++/*   changing triangles twice.)                                              */
++
++#define rnext(triedge1, triedge2)                                             \
++  sym(triedge1, triedge2);                                                    \
++  lnextself(triedge2);                                                        \
++  symself(triedge2);
++
++#define rnextself(triedge)                                                    \
++  symself(triedge);                                                           \
++  lnextself(triedge);                                                         \
++  symself(triedge);
++
++/* rnext() moves one edge clockwise about the adjacent triangle.             */
++/*   (It's best understood by reading Guibas and Stolfi.  It involves        */
++/*   changing triangles twice.)                                              */
++
++#define rprev(triedge1, triedge2)                                             \
++  sym(triedge1, triedge2);                                                    \
++  lprevself(triedge2);                                                        \
++  symself(triedge2);
++
++#define rprevself(triedge)                                                    \
++  symself(triedge);                                                           \
++  lprevself(triedge);                                                         \
++  symself(triedge);
++
++/* These primitives determine or set the origin, destination, or apex of a   */
++/* triangle.                                                                 */
++
++#define org(triedge, pointptr)                                                \
++  pointptr = (point) (triedge).tri[plus1mod3[(triedge).orient] + 3]
++
++#define dest(triedge, pointptr)                                               \
++  pointptr = (point) (triedge).tri[minus1mod3[(triedge).orient] + 3]
++
++#define apex(triedge, pointptr)                                               \
++  pointptr = (point) (triedge).tri[(triedge).orient + 3]
++
++#define setorg(triedge, pointptr)                                             \
++  (triedge).tri[plus1mod3[(triedge).orient] + 3] = (triangle) pointptr
++
++#define setdest(triedge, pointptr)                                            \
++  (triedge).tri[minus1mod3[(triedge).orient] + 3] = (triangle) pointptr
++
++#define setapex(triedge, pointptr)                                            \
++  (triedge).tri[(triedge).orient + 3] = (triangle) pointptr
++
++#define setvertices2null(triedge)                                             \
++  (triedge).tri[3] = (triangle) NULL;                                         \
++  (triedge).tri[4] = (triangle) NULL;                                         \
++  (triedge).tri[5] = (triangle) NULL;
++
++/* Bond two triangles together.                                              */
++
++#define bond(triedge1, triedge2)                                              \
++  (triedge1).tri[(triedge1).orient] = encode(triedge2);                       \
++  (triedge2).tri[(triedge2).orient] = encode(triedge1)
++
++/* Dissolve a bond (from one side).  Note that the other triangle will still */
++/*   think it's connected to this triangle.  Usually, however, the other     */
++/*   triangle is being deleted entirely, or bonded to another triangle, so   */
++/*   it doesn't matter.                                                      */
++
++#define dissolve(triedge)                                                     \
++  (triedge).tri[(triedge).orient] = (triangle) dummytri
++
++/* Copy a triangle/edge handle.                                              */
++
++#define triedgecopy(triedge1, triedge2)                                       \
++  (triedge2).tri = (triedge1).tri;                                            \
++  (triedge2).orient = (triedge1).orient
++
++/* Test for equality of triangle/edge handles.                               */
++
++#define triedgeequal(triedge1, triedge2)                                      \
++  (((triedge1).tri == (triedge2).tri) &&                                      \
++   ((triedge1).orient == (triedge2).orient))
++
++/* Primitives to infect or cure a triangle with the virus.  These rely on    */
++/*   the assumption that all shell edges are aligned to four-byte boundaries.*/
++
++#define infect(triedge)                                                       \
++  (triedge).tri[6] = (triangle)                                               \
++                     ((unsigned long) (triedge).tri[6] | (unsigned long) 2l)
++
++#define uninfect(triedge)                                                     \
++  (triedge).tri[6] = (triangle)                                               \
++                     ((unsigned long) (triedge).tri[6] & ~ (unsigned long) 2l)
++
++/* Test a triangle for viral infection.                                      */
++
++#define infected(triedge)                                                     \
++  (((unsigned long) (triedge).tri[6] & (unsigned long) 2l) != 0)
++
++/* Check or set a triangle's attributes.                                     */
++
++#define elemattribute(triedge, attnum)                                        \
++  ((REAL *) (triedge).tri)[elemattribindex + (attnum)]
++
++#define setelemattribute(triedge, attnum, value)                              \
++  ((REAL *) (triedge).tri)[elemattribindex + (attnum)] = value
++
++/* Check or set a triangle's maximum area bound.                             */
++
++#define areabound(triedge)  ((REAL *) (triedge).tri)[areaboundindex]
++
++#define setareabound(triedge, value)                                          \
++  ((REAL *) (triedge).tri)[areaboundindex] = value
++
++/********* Primitives for shell edges                                *********/
++/*                                                                           */
++/*                                                                           */
++
++/* sdecode() converts a pointer to an oriented shell edge.  The orientation  */
++/*   is extracted from the least significant bit of the pointer.  The two    */
++/*   least significant bits (one for orientation, one for viral infection)   */
++/*   are masked out to produce the real pointer.                             */
++
++#define sdecode(sptr, edge)                                                   \
++  (edge).shorient = (int) ((unsigned long) (sptr) & (unsigned long) 1l);      \
++  (edge).sh = (shelle *)                                                      \
++              ((unsigned long) (sptr) & ~ (unsigned long) 3l)
++
++/* sencode() compresses an oriented shell edge into a single pointer.  It    */
++/*   relies on the assumption that all shell edges are aligned to two-byte   */
++/*   boundaries, so the least significant bit of (edge).sh is zero.          */
++
++#define sencode(edge)                                                         \
++  (shelle) ((unsigned long) (edge).sh | (unsigned long) (edge).shorient)
++
++/* ssym() toggles the orientation of a shell edge.                           */
++
++#define ssym(edge1, edge2)                                                    \
++  (edge2).sh = (edge1).sh;                                                    \
++  (edge2).shorient = 1 - (edge1).shorient
++
++#define ssymself(edge)                                                        \
++  (edge).shorient = 1 - (edge).shorient
++
++/* spivot() finds the other shell edge (from the same segment) that shares   */
++/*   the same origin.                                                        */
++
++#define spivot(edge1, edge2)                                                  \
++  sptr = (edge1).sh[(edge1).shorient];                                        \
++  sdecode(sptr, edge2)
++
++#define spivotself(edge)                                                      \
++  sptr = (edge).sh[(edge).shorient];                                          \
++  sdecode(sptr, edge)
++
++/* snext() finds the next shell edge (from the same segment) in sequence;    */
++/*   one whose origin is the input shell edge's destination.                 */
++
++#define snext(edge1, edge2)                                                   \
++  sptr = (edge1).sh[1 - (edge1).shorient];                                    \
++  sdecode(sptr, edge2)
++
++#define snextself(edge)                                                       \
++  sptr = (edge).sh[1 - (edge).shorient];                                      \
++  sdecode(sptr, edge)
++
++/* These primitives determine or set the origin or destination of a shell    */
++/*   edge.                                                                   */
++
++#define sorg(edge, pointptr)                                                  \
++  pointptr = (point) (edge).sh[2 + (edge).shorient]
++
++#define sdest(edge, pointptr)                                                 \
++  pointptr = (point) (edge).sh[3 - (edge).shorient]
++
++#define setsorg(edge, pointptr)                                               \
++  (edge).sh[2 + (edge).shorient] = (shelle) pointptr
++
++#define setsdest(edge, pointptr)                                              \
++  (edge).sh[3 - (edge).shorient] = (shelle) pointptr
++
++/* These primitives read or set a shell marker.  Shell markers are used to   */
++/*   hold user boundary information.                                         */
++
++#define mark(edge)  (* (int *) ((edge).sh + 6))
++
++#define setmark(edge, value)                                                  \
++  * (int *) ((edge).sh + 6) = value
++
++/* Bond two shell edges together.                                            */
++
++#define sbond(edge1, edge2)                                                   \
++  (edge1).sh[(edge1).shorient] = sencode(edge2);                              \
++  (edge2).sh[(edge2).shorient] = sencode(edge1)
++
++/* Dissolve a shell edge bond (from one side).  Note that the other shell    */
++/*   edge will still think it's connected to this shell edge.                */
++
++#define sdissolve(edge)                                                       \
++  (edge).sh[(edge).shorient] = (shelle) dummysh
++
++/* Copy a shell edge.                                                        */
++
++#define shellecopy(edge1, edge2)                                              \
++  (edge2).sh = (edge1).sh;                                                    \
++  (edge2).shorient = (edge1).shorient
++
++/* Test for equality of shell edges.                                         */
++
++#define shelleequal(edge1, edge2)                                             \
++  (((edge1).sh == (edge2).sh) &&                                              \
++   ((edge1).shorient == (edge2).shorient))
++
++/********* Primitives for interacting triangles and shell edges      *********/
++/*                                                                           */
++/*                                                                           */
++
++/* tspivot() finds a shell edge abutting a triangle.                         */
++
++#define tspivot(triedge, edge)                                                \
++  sptr = (shelle) (triedge).tri[6 + (triedge).orient];                        \
++  sdecode(sptr, edge)
++
++/* stpivot() finds a triangle abutting a shell edge.  It requires that the   */
++/*   variable `ptr' of type `triangle' be defined.                           */
++
++#define stpivot(edge, triedge)                                                \
++  ptr = (triangle) (edge).sh[4 + (edge).shorient];                            \
++  decode(ptr, triedge)
++
++/* Bond a triangle to a shell edge.                                          */
++
++#define tsbond(triedge, edge)                                                 \
++  (triedge).tri[6 + (triedge).orient] = (triangle) sencode(edge);             \
++  (edge).sh[4 + (edge).shorient] = (shelle) encode(triedge)
++
++/* Dissolve a bond (from the triangle side).                                 */
++
++#define tsdissolve(triedge)                                                   \
++  (triedge).tri[6 + (triedge).orient] = (triangle) dummysh
++
++/* Dissolve a bond (from the shell edge side).                               */
++
++#define stdissolve(edge)                                                      \
++  (edge).sh[4 + (edge).shorient] = (shelle) dummytri
++
++/********* Primitives for points                                     *********/
++/*                                                                           */
++/*                                                                           */
++
++#define pointmark(pt)  ((int *) (pt))[pointmarkindex]
++
++#define setpointmark(pt, value)                                               \
++  ((int *) (pt))[pointmarkindex] = value
++
++#define point2tri(pt)  ((triangle *) (pt))[point2triindex]
++
++#define setpoint2tri(pt, value)                                               \
++  ((triangle *) (pt))[point2triindex] = value
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Mesh manipulation primitives end here                     *********/
++
++/********* User interaction routines begin here                      *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  syntax()   Print list of command line switches.                          */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef TRILIBRARY
++
++void syntax()
++{
++#ifdef CDT_ONLY
++#ifdef REDUCED
++  printf("triangle [-pAcevngBPNEIOXzo_lQVh] input_file\n");
++#else /* not REDUCED */
++  printf("triangle [-pAcevngBPNEIOXzo_iFlCQVh] input_file\n");
++#endif /* not REDUCED */
++#else /* not CDT_ONLY */
++#ifdef REDUCED
++  printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__lQVh] input_file\n");
++#else /* not REDUCED */
++  printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__iFlsCQVh] input_file\n");
++#endif /* not REDUCED */
++#endif /* not CDT_ONLY */
++
++  printf("    -p  Triangulates a Planar Straight Line Graph (.poly file).\n");
++#ifndef CDT_ONLY
++  printf("    -r  Refines a previously generated mesh.\n");
++  printf(
++    "    -q  Quality mesh generation.  A minimum angle may be specified.\n");
++  printf("    -a  Applies a maximum triangle area constraint.\n");
++#endif /* not CDT_ONLY */
++  printf(
++    "    -A  Applies attributes to identify elements in certain regions.\n");
++  printf("    -c  Encloses the convex hull with segments.\n");
++  printf("    -e  Generates an edge list.\n");
++  printf("    -v  Generates a Voronoi diagram.\n");
++  printf("    -n  Generates a list of triangle neighbors.\n");
++  printf("    -g  Generates an .off file for Geomview.\n");
++  printf("    -B  Suppresses output of boundary information.\n");
++  printf("    -P  Suppresses output of .poly file.\n");
++  printf("    -N  Suppresses output of .node file.\n");
++  printf("    -E  Suppresses output of .ele file.\n");
++  printf("    -I  Suppresses mesh iteration numbers.\n");
++  printf("    -O  Ignores holes in .poly file.\n");
++  printf("    -X  Suppresses use of exact arithmetic.\n");
++  printf("    -z  Numbers all items starting from zero (rather than one).\n");
++  printf("    -o2 Generates second-order subparametric elements.\n");
++#ifndef CDT_ONLY
++  printf("    -Y  Suppresses boundary segment splitting.\n");
++  printf("    -S  Specifies maximum number of added Steiner points.\n");
++#endif /* not CDT_ONLY */
++#ifndef REDUCED
++  printf("    -i  Uses incremental method, rather than divide-and-conquer.\n");
++  printf("    -F  Uses Fortune's sweepline algorithm, rather than d-and-c.\n");
++#endif /* not REDUCED */
++  printf("    -l  Uses vertical cuts only, rather than alternating cuts.\n");
++#ifndef REDUCED
++#ifndef CDT_ONLY
++  printf(
++    "    -s  Force segments into mesh by splitting (instead of using CDT).\n");
++#endif /* not CDT_ONLY */
++  printf("    -C  Check consistency of final mesh.\n");
++#endif /* not REDUCED */
++  printf("    -Q  Quiet:  No terminal output except errors.\n");
++  printf("    -V  Verbose:  Detailed information on what I'm doing.\n");
++  printf("    -h  Help:  Detailed instructions for Triangle.\n");
++  exit(0);
++}
++
++#endif /* not TRILIBRARY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  info()   Print out complete instructions.                                */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef TRILIBRARY
++
++void info()
++{
++  printf("Triangle\n");
++  printf(
++"A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.\n");
++  printf("Version 1.3\n\n");
++  printf(
++"Copyright 1996 Jonathan Richard Shewchuk  (bugs/comments to jrs@cs.cmu.edu)\n"
++);
++  printf("School of Computer Science / Carnegie Mellon University\n");
++  printf("5000 Forbes Avenue / Pittsburgh, Pennsylvania  15213-3891\n");
++  printf(
++"Created as part of the Archimedes project (tools for parallel FEM).\n");
++  printf(
++"Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.\n");
++  printf("There is no warranty whatsoever.  Use at your own risk.\n");
++#ifdef SINGLE
++  printf("This executable is compiled for single precision arithmetic.\n\n\n");
++#else /* not SINGLE */
++  printf("This executable is compiled for double precision arithmetic.\n\n\n");
++#endif /* not SINGLE */
++  printf(
++"Triangle generates exact Delaunay triangulations, constrained Delaunay\n");
++  printf(
++"triangulations, and quality conforming Delaunay triangulations.  The latter\n"
++);
++  printf(
++"can be generated with no small angles, and are thus suitable for finite\n");
++  printf(
++"element analysis.  If no command line switches are specified, your .node\n");
++  printf(
++"input file will be read, and the Delaunay triangulation will be returned in\n"
++);
++  printf(".node and .ele output files.  The command syntax is:\n\n");
++#ifdef CDT_ONLY
++#ifdef REDUCED
++  printf("triangle [-pAcevngBPNEIOXzo_lQVh] input_file\n\n");
++#else /* not REDUCED */
++  printf("triangle [-pAcevngBPNEIOXzo_iFlCQVh] input_file\n\n");
++#endif /* not REDUCED */
++#else /* not CDT_ONLY */
++#ifdef REDUCED
++  printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__lQVh] input_file\n\n");
++#else /* not REDUCED */
++  printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__iFlsCQVh] input_file\n\n");
++#endif /* not REDUCED */
++#endif /* not CDT_ONLY */
++  printf(
++"Underscores indicate that numbers may optionally follow certain switches;\n");
++  printf(
++"do not leave any space between a switch and its numeric parameter.\n");
++  printf(
++"input_file must be a file with extension .node, or extension .poly if the\n");
++  printf(
++"-p switch is used.  If -r is used, you must supply .node and .ele files,\n");
++  printf(
++"and possibly a .poly file and .area file as well.  The formats of these\n");
++  printf("files are described below.\n\n");
++  printf("Command Line Switches:\n\n");
++  printf(
++"    -p  Reads a Planar Straight Line Graph (.poly file), which can specify\n"
++);
++  printf(
++"        points, segments, holes, and regional attributes and area\n");
++  printf(
++"        constraints.  Will generate a constrained Delaunay triangulation\n");
++  printf(
++"        fitting the input; or, if -s, -q, or -a is used, a conforming\n");
++  printf(
++"        Delaunay triangulation.  If -p is not used, Triangle reads a .node\n"
++);
++  printf("        file by default.\n");
++  printf(
++"    -r  Refines a previously generated mesh.  The mesh is read from a .node\n"
++);
++  printf(
++"        file and an .ele file.  If -p is also used, a .poly file is read\n");
++  printf(
++"        and used to constrain edges in the mesh.  Further details on\n");
++  printf("        refinement are given below.\n");
++  printf(
++"    -q  Quality mesh generation by Jim Ruppert's Delaunay refinement\n");
++  printf(
++"        algorithm.  Adds points to the mesh to ensure that no angles\n");
++  printf(
++"        smaller than 20 degrees occur.  An alternative minimum angle may be\n"
++);
++  printf(
++"        specified after the `q'.  If the minimum angle is 20.7 degrees or\n");
++  printf(
++"        smaller, the triangulation algorithm is theoretically guaranteed to\n"
++);
++  printf(
++"        terminate (assuming infinite precision arithmetic - Triangle may\n");
++  printf(
++"        fail to terminate if you run out of precision).  In practice, the\n");
++  printf(
++"        algorithm often succeeds for minimum angles up to 33.8 degrees.\n");
++  printf(
++"        For highly refined meshes, however, it may be necessary to reduce\n");
++  printf(
++"        the minimum angle to well below 20 to avoid problems associated\n");
++  printf(
++"        with insufficient floating-point precision.  The specified angle\n");
++  printf("        may include a decimal point.\n");
++  printf(
++"    -a  Imposes a maximum triangle area.  If a number follows the `a', no\n");
++  printf(
++"        triangle will be generated whose area is larger than that number.\n");
++  printf(
++"        If no number is specified, an .area file (if -r is used) or .poly\n");
++  printf(
++"        file (if -r is not used) specifies a number of maximum area\n");
++  printf(
++"        constraints.  An .area file contains a separate area constraint for\n"
++);
++  printf(
++"        each triangle, and is useful for refining a finite element mesh\n");
++  printf(
++"        based on a posteriori error estimates.  A .poly file can optionally\n"
++);
++  printf(
++"        contain an area constraint for each segment-bounded region, thereby\n"
++);
++  printf(
++"        enforcing triangle densities in a first triangulation.  You can\n");
++  printf(
++"        impose both a fixed area constraint and a varying area constraint\n");
++  printf(
++"        by invoking the -a switch twice, once with and once without a\n");
++  printf(
++"        number following.  Each area specified may include a decimal point.\n"
++);
++  printf(
++"    -A  Assigns an additional attribute to each triangle that identifies\n");
++  printf(
++"        what segment-bounded region each triangle belongs to.  Attributes\n");
++  printf(
++"        are assigned to regions by the .poly file.  If a region is not\n");
++  printf(
++"        explicitly marked by the .poly file, triangles in that region are\n");
++  printf(
++"        assigned an attribute of zero.  The -A switch has an effect only\n");
++  printf("        when the -p switch is used and the -r switch is not.\n");
++  printf(
++"    -c  Creates segments on the convex hull of the triangulation.  If you\n");
++  printf(
++"        are triangulating a point set, this switch causes a .poly file to\n");
++  printf(
++"        be written, containing all edges in the convex hull.  (By default,\n"
++);
++  printf(
++"        a .poly file is written only if a .poly file is read.)  If you are\n"
++);
++  printf(
++"        triangulating a PSLG, this switch specifies that the interior of\n");
++  printf(
++"        the convex hull of the PSLG should be triangulated.  If you do not\n"
++);
++  printf(
++"        use this switch when triangulating a PSLG, it is assumed that you\n");
++  printf(
++"        have identified the region to be triangulated by surrounding it\n");
++  printf(
++"        with segments of the input PSLG.  Beware:  if you are not careful,\n"
++);
++  printf(
++"        this switch can cause the introduction of an extremely thin angle\n");
++  printf(
++"        between a PSLG segment and a convex hull segment, which can cause\n");
++  printf(
++"        overrefinement or failure if Triangle runs out of precision.  If\n");
++  printf(
++"        you are refining a mesh, the -c switch works differently; it\n");
++  printf(
++"        generates the set of boundary edges of the mesh, rather than the\n");
++  printf("        convex hull.\n");
++  printf(
++"    -e  Outputs (to an .edge file) a list of edges of the triangulation.\n");
++  printf(
++"    -v  Outputs the Voronoi diagram associated with the triangulation.\n");
++  printf("        Does not attempt to detect degeneracies.\n");
++  printf(
++"    -n  Outputs (to a .neigh file) a list of triangles neighboring each\n");
++  printf("        triangle.\n");
++  printf(
++"    -g  Outputs the mesh to an Object File Format (.off) file, suitable for\n"
++);
++  printf("        viewing with the Geometry Center's Geomview package.\n");
++  printf(
++"    -B  No boundary markers in the output .node, .poly, and .edge output\n");
++  printf(
++"        files.  See the detailed discussion of boundary markers below.\n");
++  printf(
++"    -P  No output .poly file.  Saves disk space, but you lose the ability\n");
++  printf(
++"        to impose segment constraints on later refinements of the mesh.\n");
++  printf("    -N  No output .node file.\n");
++  printf("    -E  No output .ele file.\n");
++  printf(
++"    -I  No iteration numbers.  Suppresses the output of .node and .poly\n");
++  printf(
++"        files, so your input files won't be overwritten.  (If your input is\n"
++);
++  printf(
++"        a .poly file only, a .node file will be written.)  Cannot be used\n");
++  printf(
++"        with the -r switch, because that would overwrite your input .ele\n");
++  printf(
++"        file.  Shouldn't be used with the -s, -q, or -a switch if you are\n");
++  printf(
++"        using a .node file for input, because no .node file will be\n");
++  printf("        written, so there will be no record of any added points.\n");
++  printf("    -O  No holes.  Ignores the holes in the .poly file.\n");
++  printf(
++"    -X  No exact arithmetic.  Normally, Triangle uses exact floating-point\n"
++);
++  printf(
++"        arithmetic for certain tests if it thinks the inexact tests are not\n"
++);
++  printf(
++"        accurate enough.  Exact arithmetic ensures the robustness of the\n");
++  printf(
++"        triangulation algorithms, despite floating-point roundoff error.\n");
++  printf(
++"        Disabling exact arithmetic with the -X switch will cause a small\n");
++  printf(
++"        improvement in speed and create the possibility (albeit small) that\n"
++);
++  printf(
++"        Triangle will fail to produce a valid mesh.  Not recommended.\n");
++  printf(
++"    -z  Numbers all items starting from zero (rather than one).  Note that\n"
++);
++  printf(
++"        this switch is normally overrided by the value used to number the\n");
++  printf(
++"        first point of the input .node or .poly file.  However, this switch\n"
++);
++  printf("        is useful when calling Triangle from another program.\n");
++  printf(
++"    -o2 Generates second-order subparametric elements with six nodes each.\n"
++);
++  printf(
++"    -Y  No new points on the boundary.  This switch is useful when the mesh\n"
++);
++  printf(
++"        boundary must be preserved so that it conforms to some adjacent\n");
++  printf(
++"        mesh.  Be forewarned that you will probably sacrifice some of the\n");
++  printf(
++"        quality of the mesh; Triangle will try, but the resulting mesh may\n"
++);
++  printf(
++"        contain triangles of poor aspect ratio.  Works well if all the\n");
++  printf(
++"        boundary points are closely spaced.  Specify this switch twice\n");
++  printf(
++"        (`-YY') to prevent all segment splitting, including internal\n");
++  printf("        boundaries.\n");
++  printf(
++"    -S  Specifies the maximum number of Steiner points (points that are not\n"
++);
++  printf(
++"        in the input, but are added to meet the constraints of minimum\n");
++  printf(
++"        angle and maximum area).  The default is to allow an unlimited\n");
++  printf(
++"        number.  If you specify this switch with no number after it,\n");
++  printf(
++"        the limit is set to zero.  Triangle always adds points at segment\n");
++  printf(
++"        intersections, even if it needs to use more points than the limit\n");
++  printf(
++"        you set.  When Triangle inserts segments by splitting (-s), it\n");
++  printf(
++"        always adds enough points to ensure that all the segments appear in\n"
++);
++  printf(
++"        the triangulation, again ignoring the limit.  Be forewarned that\n");
++  printf(
++"        the -S switch may result in a conforming triangulation that is not\n"
++);
++  printf(
++"        truly Delaunay, because Triangle may be forced to stop adding\n");
++  printf(
++"        points when the mesh is in a state where a segment is non-Delaunay\n"
++);
++  printf(
++"        and needs to be split.  If so, Triangle will print a warning.\n");
++  printf(
++"    -i  Uses an incremental rather than divide-and-conquer algorithm to\n");
++  printf(
++"        form a Delaunay triangulation.  Try it if the divide-and-conquer\n");
++  printf("        algorithm fails.\n");
++  printf(
++"    -F  Uses Steven Fortune's sweepline algorithm to form a Delaunay\n");
++  printf(
++"        triangulation.  Warning:  does not use exact arithmetic for all\n");
++  printf("        calculations.  An exact result is not guaranteed.\n");
++  printf(
++"    -l  Uses only vertical cuts in the divide-and-conquer algorithm.  By\n");
++  printf(
++"        default, Triangle uses alternating vertical and horizontal cuts,\n");
++  printf(
++"        which usually improve the speed except with point sets that are\n");
++  printf(
++"        small or short and wide.  This switch is primarily of theoretical\n");
++  printf("        interest.\n");
++  printf(
++"    -s  Specifies that segments should be forced into the triangulation by\n"
++);
++  printf(
++"        recursively splitting them at their midpoints, rather than by\n");
++  printf(
++"        generating a constrained Delaunay triangulation.  Segment splitting\n"
++);
++  printf(
++"        is true to Ruppert's original algorithm, but can create needlessly\n"
++);
++  printf("        small triangles near external small features.\n");
++  printf(
++"    -C  Check the consistency of the final mesh.  Uses exact arithmetic for\n"
++);
++  printf(
++"        checking, even if the -X switch is used.  Useful if you suspect\n");
++  printf("        Triangle is buggy.\n");
++  printf(
++"    -Q  Quiet: Suppresses all explanation of what Triangle is doing, unless\n"
++);
++  printf("        an error occurs.\n");
++  printf(
++"    -V  Verbose: Gives detailed information about what Triangle is doing.\n");
++  printf(
++"        Add more `V's for increasing amount of detail.  `-V' gives\n");
++  printf(
++"        information on algorithmic progress and more detailed statistics.\n");
++  printf(
++"        `-VV' gives point-by-point details, and will print so much that\n");
++  printf(
++"        Triangle will run much more slowly.  `-VVV' gives information only\n"
++);
++  printf("        a debugger could love.\n");
++  printf("    -h  Help:  Displays these instructions.\n");
++  printf("\n");
++  printf("Definitions:\n");
++  printf("\n");
++  printf(
++"  A Delaunay triangulation of a point set is a triangulation whose vertices\n"
++);
++  printf(
++"  are the point set, having the property that no point in the point set\n");
++  printf(
++"  falls in the interior of the circumcircle (circle that passes through all\n"
++);
++  printf("  three vertices) of any triangle in the triangulation.\n\n");
++  printf(
++"  A Voronoi diagram of a point set is a subdivision of the plane into\n");
++  printf(
++"  polygonal regions (some of which may be infinite), where each region is\n");
++  printf(
++"  the set of points in the plane that are closer to some input point than\n");
++  printf(
++"  to any other input point.  (The Voronoi diagram is the geometric dual of\n"
++);
++  printf("  the Delaunay triangulation.)\n\n");
++  printf(
++"  A Planar Straight Line Graph (PSLG) is a collection of points and\n");
++  printf(
++"  segments.  Segments are simply edges, whose endpoints are points in the\n");
++  printf(
++"  PSLG.  The file format for PSLGs (.poly files) is described below.\n");
++  printf("\n");
++  printf(
++"  A constrained Delaunay triangulation of a PSLG is similar to a Delaunay\n");
++  printf(
++"  triangulation, but each PSLG segment is present as a single edge in the\n");
++  printf(
++"  triangulation.  (A constrained Delaunay triangulation is not truly a\n");
++  printf("  Delaunay triangulation.)\n\n");
++  printf(
++"  A conforming Delaunay triangulation of a PSLG is a true Delaunay\n");
++  printf(
++"  triangulation in which each PSLG segment may have been subdivided into\n");
++  printf(
++"  several edges by the insertion of additional points.  These inserted\n");
++  printf(
++"  points are necessary to allow the segments to exist in the mesh while\n");
++  printf("  maintaining the Delaunay property.\n\n");
++  printf("File Formats:\n\n");
++  printf(
++"  All files may contain comments prefixed by the character '#'.  Points,\n");
++  printf(
++"  triangles, edges, holes, and maximum area constraints must be numbered\n");
++  printf(
++"  consecutively, starting from either 1 or 0.  Whichever you choose, all\n");
++  printf(
++"  input files must be consistent; if the nodes are numbered from 1, so must\n"
++);
++  printf(
++"  be all other objects.  Triangle automatically detects your choice while\n");
++  printf(
++"  reading the .node (or .poly) file.  (When calling Triangle from another\n");
++  printf(
++"  program, use the -z switch if you wish to number objects from zero.)\n");
++  printf("  Examples of these file formats are given below.\n\n");
++  printf("  .node files:\n");
++  printf(
++"    First line:  <# of points> <dimension (must be 2)> <# of attributes>\n");
++  printf(
++"                                           <# of boundary markers (0 or 1)>\n"
++);
++  printf(
++"    Remaining lines:  <point #> <x> <y> [attributes] [boundary marker]\n");
++  printf("\n");
++  printf(
++"    The attributes, which are typically floating-point values of physical\n");
++  printf(
++"    quantities (such as mass or conductivity) associated with the nodes of\n"
++);
++  printf(
++"    a finite element mesh, are copied unchanged to the output mesh.  If -s,\n"
++);
++  printf(
++"    -q, or -a is selected, each new Steiner point added to the mesh will\n");
++  printf("    have attributes assigned to it by linear interpolation.\n\n");
++  printf(
++"    If the fourth entry of the first line is `1', the last column of the\n");
++  printf(
++"    remainder of the file is assumed to contain boundary markers.  Boundary\n"
++);
++  printf(
++"    markers are used to identify boundary points and points resting on PSLG\n"
++);
++  printf(
++"    segments; a complete description appears in a section below.  The .node\n"
++);
++  printf(
++"    file produced by Triangle will contain boundary markers in the last\n");
++  printf("    column unless they are suppressed by the -B switch.\n\n");
++  printf("  .ele files:\n");
++  printf(
++"    First line:  <# of triangles> <points per triangle> <# of attributes>\n");
++  printf(
++"    Remaining lines:  <triangle #> <point> <point> <point> ... [attributes]\n"
++);
++  printf("\n");
++  printf(
++"    Points are indices into the corresponding .node file.  The first three\n"
++);
++  printf(
++"    points are the corners, and are listed in counterclockwise order around\n"
++);
++  printf(
++"    each triangle.  (The remaining points, if any, depend on the type of\n");
++  printf(
++"    finite element used.)  The attributes are just like those of .node\n");
++  printf(
++"    files.  Because there is no simple mapping from input to output\n");
++  printf(
++"    triangles, an attempt is made to interpolate attributes, which may\n");
++  printf(
++"    result in a good deal of diffusion of attributes among nearby triangles\n"
++);
++  printf(
++"    as the triangulation is refined.  Diffusion does not occur across\n");
++  printf(
++"    segments, so attributes used to identify segment-bounded regions remain\n"
++);
++  printf(
++"    intact.  In output .ele files, all triangles have three points each\n");
++  printf(
++"    unless the -o2 switch is used, in which case they have six, and the\n");
++  printf(
++"    fourth, fifth, and sixth points lie on the midpoints of the edges\n");
++  printf("    opposite the first, second, and third corners.\n\n");
++  printf("  .poly files:\n");
++  printf(
++"    First line:  <# of points> <dimension (must be 2)> <# of attributes>\n");
++  printf(
++"                                           <# of boundary markers (0 or 1)>\n"
++);
++  printf(
++"    Following lines:  <point #> <x> <y> [attributes] [boundary marker]\n");
++  printf("    One line:  <# of segments> <# of boundary markers (0 or 1)>\n");
++  printf(
++"    Following lines:  <segment #> <endpoint> <endpoint> [boundary marker]\n");
++  printf("    One line:  <# of holes>\n");
++  printf("    Following lines:  <hole #> <x> <y>\n");
++  printf(
++"    Optional line:  <# of regional attributes and/or area constraints>\n");
++  printf(
++"    Optional following lines:  <constraint #> <x> <y> <attrib> <max area>\n");
++  printf("\n");
++  printf(
++"    A .poly file represents a PSLG, as well as some additional information.\n"
++);
++  printf(
++"    The first section lists all the points, and is identical to the format\n"
++);
++  printf(
++"    of .node files.  <# of points> may be set to zero to indicate that the\n"
++);
++  printf(
++"    points are listed in a separate .node file; .poly files produced by\n");
++  printf(
++"    Triangle always have this format.  This has the advantage that a point\n"
++);
++  printf(
++"    set may easily be triangulated with or without segments.  (The same\n");
++  printf(
++"    effect can be achieved, albeit using more disk space, by making a copy\n"
++);
++  printf(
++"    of the .poly file with the extension .node; all sections of the file\n");
++  printf("    but the first are ignored.)\n\n");
++  printf(
++"    The second section lists the segments.  Segments are edges whose\n");
++  printf(
++"    presence in the triangulation is enforced.  Each segment is specified\n");
++  printf(
++"    by listing the indices of its two endpoints.  This means that you must\n"
++);
++  printf(
++"    include its endpoints in the point list.  If -s, -q, and -a are not\n");
++  printf(
++"    selected, Triangle will produce a constrained Delaunay triangulation,\n");
++  printf(
++"    in which each segment appears as a single edge in the triangulation.\n");
++  printf(
++"    If -q or -a is selected, Triangle will produce a conforming Delaunay\n");
++  printf(
++"    triangulation, in which segments may be subdivided into smaller edges.\n"
++);
++  printf("    Each segment, like each point, may have a boundary marker.\n\n");
++  printf(
++"    The third section lists holes (and concavities, if -c is selected) in\n");
++  printf(
++"    the triangulation.  Holes are specified by identifying a point inside\n");
++  printf(
++"    each hole.  After the triangulation is formed, Triangle creates holes\n");
++  printf(
++"    by eating triangles, spreading out from each hole point until its\n");
++  printf(
++"    progress is blocked by PSLG segments; you must be careful to enclose\n");
++  printf(
++"    each hole in segments, or your whole triangulation may be eaten away.\n");
++  printf(
++"    If the two triangles abutting a segment are eaten, the segment itself\n");
++  printf(
++"    is also eaten.  Do not place a hole directly on a segment; if you do,\n");
++  printf("    Triangle will choose one side of the segment arbitrarily.\n\n");
++  printf(
++"    The optional fourth section lists regional attributes (to be assigned\n");
++  printf(
++"    to all triangles in a region) and regional constraints on the maximum\n");
++  printf(
++"    triangle area.  Triangle will read this section only if the -A switch\n");
++  printf(
++"    is used or the -a switch is used without a number following it, and the\n"
++);
++  printf(
++"    -r switch is not used.  Regional attributes and area constraints are\n");
++  printf(
++"    propagated in the same manner as holes; you specify a point for each\n");
++  printf(
++"    attribute and/or constraint, and the attribute and/or constraint will\n");
++  printf(
++"    affect the whole region (bounded by segments) containing the point.  If\n"
++);
++  printf(
++"    two values are written on a line after the x and y coordinate, the\n");
++  printf(
++"    former is assumed to be a regional attribute (but will only be applied\n"
++);
++  printf(
++"    if the -A switch is selected), and the latter is assumed to be a\n");
++  printf(
++"    regional area constraint (but will only be applied if the -a switch is\n"
++);
++  printf(
++"    selected).  You may also specify just one value after the coordinates,\n"
++);
++  printf(
++"    which can serve as both an attribute and an area constraint, depending\n"
++);
++  printf(
++"    on the choice of switches.  If you are using the -A and -a switches\n");
++  printf(
++"    simultaneously and wish to assign an attribute to some region without\n");
++  printf("    imposing an area constraint, use a negative maximum area.\n\n");
++  printf(
++"    When a triangulation is created from a .poly file, you must either\n");
++  printf(
++"    enclose the entire region to be triangulated in PSLG segments, or\n");
++  printf(
++"    use the -c switch, which encloses the convex hull of the input point\n");
++  printf(
++"    set.  If you do not use the -c switch, Triangle will eat all triangles\n"
++);
++  printf(
++"    on the outer boundary that are not protected by segments; if you are\n");
++  printf(
++"    not careful, your whole triangulation may be eaten away.  If you do\n");
++  printf(
++"    use the -c switch, you can still produce concavities by appropriate\n");
++  printf("    placement of holes just inside the convex hull.\n\n");
++  printf(
++"    An ideal PSLG has no intersecting segments, nor any points that lie\n");
++  printf(
++"    upon segments (except, of course, the endpoints of each segment.)  You\n"
++);
++  printf(
++"    aren't required to make your .poly files ideal, but you should be aware\n"
++);
++  printf(
++"    of what can go wrong.  Segment intersections are relatively safe -\n");
++  printf(
++"    Triangle will calculate the intersection points for you and add them to\n"
++);
++  printf(
++"    the triangulation - as long as your machine's floating-point precision\n"
++);
++  printf(
++"    doesn't become a problem.  You are tempting the fates if you have three\n"
++);
++  printf(
++"    segments that cross at the same location, and expect Triangle to figure\n"
++);
++  printf(
++"    out where the intersection point is.  Thanks to floating-point roundoff\n"
++);
++  printf(
++"    error, Triangle will probably decide that the three segments intersect\n"
++);
++  printf(
++"    at three different points, and you will find a minuscule triangle in\n");
++  printf(
++"    your output - unless Triangle tries to refine the tiny triangle, uses\n");
++  printf(
++"    up the last bit of machine precision, and fails to terminate at all.\n");
++  printf(
++"    You're better off putting the intersection point in the input files,\n");
++  printf(
++"    and manually breaking up each segment into two.  Similarly, if you\n");
++  printf(
++"    place a point at the middle of a segment, and hope that Triangle will\n");
++  printf(
++"    break up the segment at that point, you might get lucky.  On the other\n"
++);
++  printf(
++"    hand, Triangle might decide that the point doesn't lie precisely on the\n"
++);
++  printf(
++"    line, and you'll have a needle-sharp triangle in your output - or a lot\n"
++);
++  printf("    of tiny triangles if you're generating a quality mesh.\n\n");
++  printf(
++"    When Triangle reads a .poly file, it also writes a .poly file, which\n");
++  printf(
++"    includes all edges that are part of input segments.  If the -c switch\n");
++  printf(
++"    is used, the output .poly file will also include all of the edges on\n");
++  printf(
++"    the convex hull.  Hence, the output .poly file is useful for finding\n");
++  printf(
++"    edges associated with input segments and setting boundary conditions in\n"
++);
++  printf(
++"    finite element simulations.  More importantly, you will need it if you\n"
++);
++  printf(
++"    plan to refine the output mesh, and don't want segments to be missing\n");
++  printf("    in later triangulations.\n\n");
++  printf("  .area files:\n");
++  printf("    First line:  <# of triangles>\n");
++  printf("    Following lines:  <triangle #> <maximum area>\n\n");
++  printf(
++"    An .area file associates with each triangle a maximum area that is used\n"
++);
++  printf(
++"    for mesh refinement.  As with other file formats, every triangle must\n");
++  printf(
++"    be represented, and they must be numbered consecutively.  A triangle\n");
++  printf(
++"    may be left unconstrained by assigning it a negative maximum area.\n");
++  printf("\n");
++  printf("  .edge files:\n");
++  printf("    First line:  <# of edges> <# of boundary markers (0 or 1)>\n");
++  printf(
++"    Following lines:  <edge #> <endpoint> <endpoint> [boundary marker]\n");
++  printf("\n");
++  printf(
++"    Endpoints are indices into the corresponding .node file.  Triangle can\n"
++);
++  printf(
++"    produce .edge files (use the -e switch), but cannot read them.  The\n");
++  printf(
++"    optional column of boundary markers is suppressed by the -B switch.\n");
++  printf("\n");
++  printf(
++"    In Voronoi diagrams, one also finds a special kind of edge that is an\n");
++  printf(
++"    infinite ray with only one endpoint.  For these edges, a different\n");
++  printf("    format is used:\n\n");
++  printf("        <edge #> <endpoint> -1 <direction x> <direction y>\n\n");
++  printf(
++"    The `direction' is a floating-point vector that indicates the direction\n"
++);
++  printf("    of the infinite ray.\n\n");
++  printf("  .neigh files:\n");
++  printf(
++"    First line:  <# of triangles> <# of neighbors per triangle (always 3)>\n"
++);
++  printf(
++"    Following lines:  <triangle #> <neighbor> <neighbor> <neighbor>\n");
++  printf("\n");
++  printf(
++"    Neighbors are indices into the corresponding .ele file.  An index of -1\n"
++);
++  printf(
++"    indicates a mesh boundary, and therefore no neighbor.  Triangle can\n");
++  printf(
++"    produce .neigh files (use the -n switch), but cannot read them.\n");
++  printf("\n");
++  printf(
++"    The first neighbor of triangle i is opposite the first corner of\n");
++  printf("    triangle i, and so on.\n\n");
++  printf("Boundary Markers:\n\n");
++  printf(
++"  Boundary markers are tags used mainly to identify which output points and\n"
++);
++  printf(
++"  edges are associated with which PSLG segment, and to identify which\n");
++  printf(
++"  points and edges occur on a boundary of the triangulation.  A common use\n"
++);
++  printf(
++"  is to determine where boundary conditions should be applied to a finite\n");
++  printf(
++"  element mesh.  You can prevent boundary markers from being written into\n");
++  printf("  files produced by Triangle by using the -B switch.\n\n");
++  printf(
++"  The boundary marker associated with each segment in an output .poly file\n"
++);
++  printf("  or edge in an output .edge file is chosen as follows:\n");
++  printf(
++"    - If an output edge is part or all of a PSLG segment with a nonzero\n");
++  printf(
++"      boundary marker, then the edge is assigned the same marker.\n");
++  printf(
++"    - Otherwise, if the edge occurs on a boundary of the triangulation\n");
++  printf(
++"      (including boundaries of holes), then the edge is assigned the marker\n"
++);
++  printf("      one (1).\n");
++  printf("    - Otherwise, the edge is assigned the marker zero (0).\n");
++  printf(
++"  The boundary marker associated with each point in an output .node file is\n"
++);
++  printf("  chosen as follows:\n");
++  printf(
++"    - If a point is assigned a nonzero boundary marker in the input file,\n");
++  printf(
++"      then it is assigned the same marker in the output .node file.\n");
++  printf(
++"    - Otherwise, if the point lies on a PSLG segment (including the\n");
++  printf(
++"      segment's endpoints) with a nonzero boundary marker, then the point\n");
++  printf(
++"      is assigned the same marker.  If the point lies on several such\n");
++  printf("      segments, one of the markers is chosen arbitrarily.\n");
++  printf(
++"    - Otherwise, if the point occurs on a boundary of the triangulation,\n");
++  printf("      then the point is assigned the marker one (1).\n");
++  printf("    - Otherwise, the point is assigned the marker zero (0).\n");
++  printf("\n");
++  printf(
++"  If you want Triangle to determine for you which points and edges are on\n");
++  printf(
++"  the boundary, assign them the boundary marker zero (or use no markers at\n"
++);
++  printf(
++"  all) in your input files.  Alternatively, you can mark some of them and\n");
++  printf("  leave others marked zero, allowing Triangle to label them.\n\n");
++  printf("Triangulation Iteration Numbers:\n\n");
++  printf(
++"  Because Triangle can read and refine its own triangulations, input\n");
++  printf(
++"  and output files have iteration numbers.  For instance, Triangle might\n");
++  printf(
++"  read the files mesh.3.node, mesh.3.ele, and mesh.3.poly, refine the\n");
++  printf(
++"  triangulation, and output the files mesh.4.node, mesh.4.ele, and\n");
++  printf("  mesh.4.poly.  Files with no iteration number are treated as if\n");
++  printf(
++"  their iteration number is zero; hence, Triangle might read the file\n");
++  printf(
++"  points.node, triangulate it, and produce the files points.1.node and\n");
++  printf("  points.1.ele.\n\n");
++  printf(
++"  Iteration numbers allow you to create a sequence of successively finer\n");
++  printf(
++"  meshes suitable for multigrid methods.  They also allow you to produce a\n"
++);
++  printf(
++"  sequence of meshes using error estimate-driven mesh refinement.\n");
++  printf("\n");
++  printf(
++"  If you're not using refinement or quality meshing, and you don't like\n");
++  printf(
++"  iteration numbers, use the -I switch to disable them.  This switch will\n");
++  printf(
++"  also disable output of .node and .poly files to prevent your input files\n"
++);
++  printf(
++"  from being overwritten.  (If the input is a .poly file that contains its\n"
++);
++  printf("  own points, a .node file will be written.)\n\n");
++  printf("Examples of How to Use Triangle:\n\n");
++  printf(
++"  `triangle dots' will read points from dots.node, and write their Delaunay\n"
++);
++  printf(
++"  triangulation to dots.1.node and dots.1.ele.  (dots.1.node will be\n");
++  printf(
++"  identical to dots.node.)  `triangle -I dots' writes the triangulation to\n"
++);
++  printf(
++"  dots.ele instead.  (No additional .node file is needed, so none is\n");
++  printf("  written.)\n\n");
++  printf(
++"  `triangle -pe object.1' will read a PSLG from object.1.poly (and possibly\n"
++);
++  printf(
++"  object.1.node, if the points are omitted from object.1.poly) and write\n");
++  printf("  their constrained Delaunay triangulation to object.2.node and\n");
++  printf(
++"  object.2.ele.  The segments will be copied to object.2.poly, and all\n");
++  printf("  edges will be written to object.2.edge.\n\n");
++  printf(
++"  `triangle -pq31.5a.1 object' will read a PSLG from object.poly (and\n");
++  printf(
++"  possibly object.node), generate a mesh whose angles are all greater than\n"
++);
++  printf(
++"  31.5 degrees and whose triangles all have area smaller than 0.1, and\n");
++  printf(
++"  write the mesh to object.1.node and object.1.ele.  Each segment may have\n"
++);
++  printf(
++"  been broken up into multiple edges; the resulting constrained edges are\n");
++  printf("  written to object.1.poly.\n\n");
++  printf(
++"  Here is a sample file `box.poly' describing a square with a square hole:\n"
++);
++  printf("\n");
++  printf(
++"    # A box with eight points in 2D, no attributes, one boundary marker.\n");
++  printf("    8 2 0 1\n");
++  printf("    # Outer box has these vertices:\n");
++  printf("     1   0 0   0\n");
++  printf("     2   0 3   0\n");
++  printf("     3   3 0   0\n");
++  printf("     4   3 3   33     # A special marker for this point.\n");
++  printf("    # Inner square has these vertices:\n");
++  printf("     5   1 1   0\n");
++  printf("     6   1 2   0\n");
++  printf("     7   2 1   0\n");
++  printf("     8   2 2   0\n");
++  printf("    # Five segments with boundary markers.\n");
++  printf("    5 1\n");
++  printf("     1   1 2   5      # Left side of outer box.\n");
++  printf("     2   5 7   0      # Segments 2 through 5 enclose the hole.\n");
++  printf("     3   7 8   0\n");
++  printf("     4   8 6   10\n");
++  printf("     5   6 5   0\n");
++  printf("    # One hole in the middle of the inner square.\n");
++  printf("    1\n");
++  printf("     1   1.5 1.5\n\n");
++  printf(
++"  Note that some segments are missing from the outer square, so one must\n");
++  printf(
++"  use the `-c' switch.  After `triangle -pqc box.poly', here is the output\n"
++);
++  printf(
++"  file `box.1.node', with twelve points.  The last four points were added\n");
++  printf(
++"  to meet the angle constraint.  Points 1, 2, and 9 have markers from\n");
++  printf(
++"  segment 1.  Points 6 and 8 have markers from segment 4.  All the other\n");
++  printf(
++"  points but 4 have been marked to indicate that they lie on a boundary.\n");
++  printf("\n");
++  printf("    12  2  0  1\n");
++  printf("       1    0   0      5\n");
++  printf("       2    0   3      5\n");
++  printf("       3    3   0      1\n");
++  printf("       4    3   3     33\n");
++  printf("       5    1   1      1\n");
++  printf("       6    1   2     10\n");
++  printf("       7    2   1      1\n");
++  printf("       8    2   2     10\n");
++  printf("       9    0   1.5    5\n");
++  printf("      10    1.5   0    1\n");
++  printf("      11    3   1.5    1\n");
++  printf("      12    1.5   3    1\n");
++  printf("    # Generated by triangle -pqc box.poly\n\n");
++  printf("  Here is the output file `box.1.ele', with twelve triangles.\n\n");
++  printf("    12  3  0\n");
++  printf("       1     5   6   9\n");
++  printf("       2    10   3   7\n");
++  printf("       3     6   8  12\n");
++  printf("       4     9   1   5\n");
++  printf("       5     6   2   9\n");
++  printf("       6     7   3  11\n");
++  printf("       7    11   4   8\n");
++  printf("       8     7   5  10\n");
++  printf("       9    12   2   6\n");
++  printf("      10     8   7  11\n");
++  printf("      11     5   1  10\n");
++  printf("      12     8   4  12\n");
++  printf("    # Generated by triangle -pqc box.poly\n\n");
++  printf(
++"  Here is the output file `box.1.poly'.  Note that segments have been added\n"
++);
++  printf(
++"  to represent the convex hull, and some segments have been split by newly\n"
++);
++  printf(
++"  added points.  Note also that <# of points> is set to zero to indicate\n");
++  printf("  that the points should be read from the .node file.\n\n");
++  printf("    0  2  0  1\n");
++  printf("    12  1\n");
++  printf("       1     1   9     5\n");
++  printf("       2     5   7     1\n");
++  printf("       3     8   7     1\n");
++  printf("       4     6   8    10\n");
++  printf("       5     5   6     1\n");
++  printf("       6     3  10     1\n");
++  printf("       7     4  11     1\n");
++  printf("       8     2  12     1\n");
++  printf("       9     9   2     5\n");
++  printf("      10    10   1     1\n");
++  printf("      11    11   3     1\n");
++  printf("      12    12   4     1\n");
++  printf("    1\n");
++  printf("       1   1.5 1.5\n");
++  printf("    # Generated by triangle -pqc box.poly\n\n");
++  printf("Refinement and Area Constraints:\n\n");
++  printf(
++"  The -r switch causes a mesh (.node and .ele files) to be read and\n");
++  printf(
++"  refined.  If the -p switch is also used, a .poly file is read and used to\n"
++);
++  printf(
++"  specify edges that are constrained and cannot be eliminated (although\n");
++  printf(
++"  they can be divided into smaller edges) by the refinement process.\n");
++  printf("\n");
++  printf(
++"  When you refine a mesh, you generally want to impose tighter quality\n");
++  printf(
++"  constraints.  One way to accomplish this is to use -q with a larger\n");
++  printf(
++"  angle, or -a followed by a smaller area than you used to generate the\n");
++  printf(
++"  mesh you are refining.  Another way to do this is to create an .area\n");
++  printf(
++"  file, which specifies a maximum area for each triangle, and use the -a\n");
++  printf(
++"  switch (without a number following).  Each triangle's area constraint is\n"
++);
++  printf(
++"  applied to that triangle.  Area constraints tend to diffuse as the mesh\n");
++  printf(
++"  is refined, so if there are large variations in area constraint between\n");
++  printf("  adjacent triangles, you may not get the results you want.\n\n");
++  printf(
++"  If you are refining a mesh composed of linear (three-node) elements, the\n"
++);
++  printf(
++"  output mesh will contain all the nodes present in the input mesh, in the\n"
++);
++  printf(
++"  same order, with new nodes added at the end of the .node file.  However,\n"
++);
++  printf(
++"  there is no guarantee that each output element is contained in a single\n");
++  printf(
++"  input element.  Often, output elements will overlap two input elements,\n");
++  printf(
++"  and input edges are not present in the output mesh.  Hence, a sequence of\n"
++);
++  printf(
++"  refined meshes will form a hierarchy of nodes, but not a hierarchy of\n");
++  printf(
++"  elements.  If you a refining a mesh of higher-order elements, the\n");
++  printf(
++"  hierarchical property applies only to the nodes at the corners of an\n");
++  printf("  element; other nodes may not be present in the refined mesh.\n\n");
++  printf(
++"  It is important to understand that maximum area constraints in .poly\n");
++  printf(
++"  files are handled differently from those in .area files.  A maximum area\n"
++);
++  printf(
++"  in a .poly file applies to the whole (segment-bounded) region in which a\n"
++);
++  printf(
++"  point falls, whereas a maximum area in an .area file applies to only one\n"
++);
++  printf(
++"  triangle.  Area constraints in .poly files are used only when a mesh is\n");
++  printf(
++"  first generated, whereas area constraints in .area files are used only to\n"
++);
++  printf(
++"  refine an existing mesh, and are typically based on a posteriori error\n");
++  printf(
++"  estimates resulting from a finite element simulation on that mesh.\n");
++  printf("\n");
++  printf(
++"  `triangle -rq25 object.1' will read object.1.node and object.1.ele, then\n"
++);
++  printf(
++"  refine the triangulation to enforce a 25 degree minimum angle, and then\n");
++  printf(
++"  write the refined triangulation to object.2.node and object.2.ele.\n");
++  printf("\n");
++  printf(
++"  `triangle -rpaa6.2 z.3' will read z.3.node, z.3.ele, z.3.poly, and\n");
++  printf(
++"  z.3.area.  After reconstructing the mesh and its segments, Triangle will\n"
++);
++  printf(
++"  refine the mesh so that no triangle has area greater than 6.2, and\n");
++  printf(
++"  furthermore the triangles satisfy the maximum area constraints in\n");
++  printf(
++"  z.3.area.  The output is written to z.4.node, z.4.ele, and z.4.poly.\n");
++  printf("\n");
++  printf(
++"  The sequence `triangle -qa1 x', `triangle -rqa.3 x.1', `triangle -rqa.1\n");
++  printf(
++"  x.2' creates a sequence of successively finer meshes x.1, x.2, and x.3,\n");
++  printf("  suitable for multigrid.\n\n");
++  printf("Convex Hulls and Mesh Boundaries:\n\n");
++  printf(
++"  If the input is a point set (rather than a PSLG), Triangle produces its\n");
++  printf(
++"  convex hull as a by-product in the output .poly file if you use the -c\n");
++  printf(
++"  switch.  There are faster algorithms for finding a two-dimensional convex\n"
++);
++  printf(
++"  hull than triangulation, of course, but this one comes for free.  If the\n"
++);
++  printf(
++"  input is an unconstrained mesh (you are using the -r switch but not the\n");
++  printf(
++"  -p switch), Triangle produces a list of its boundary edges (including\n");
++  printf("  hole boundaries) as a by-product if you use the -c switch.\n\n");
++  printf("Voronoi Diagrams:\n\n");
++  printf(
++"  The -v switch produces a Voronoi diagram, in files suffixed .v.node and\n");
++  printf(
++"  .v.edge.  For example, `triangle -v points' will read points.node,\n");
++  printf(
++"  produce its Delaunay triangulation in points.1.node and points.1.ele,\n");
++  printf(
++"  and produce its Voronoi diagram in points.1.v.node and points.1.v.edge.\n");
++  printf(
++"  The .v.node file contains a list of all Voronoi vertices, and the .v.edge\n"
++);
++  printf(
++"  file contains a list of all Voronoi edges, some of which may be infinite\n"
++);
++  printf(
++"  rays.  (The choice of filenames makes it easy to run the set of Voronoi\n");
++  printf("  vertices through Triangle, if so desired.)\n\n");
++  printf(
++"  This implementation does not use exact arithmetic to compute the Voronoi\n"
++);
++  printf(
++"  vertices, and does not check whether neighboring vertices are identical.\n"
++);
++  printf(
++"  Be forewarned that if the Delaunay triangulation is degenerate or\n");
++  printf(
++"  near-degenerate, the Voronoi diagram may have duplicate points, crossing\n"
++);
++  printf(
++"  edges, or infinite rays whose direction vector is zero.  Also, if you\n");
++  printf(
++"  generate a constrained (as opposed to conforming) Delaunay triangulation,\n"
++);
++  printf(
++"  or if the triangulation has holes, the corresponding Voronoi diagram is\n");
++  printf("  likely to have crossing edges and unlikely to make sense.\n\n");
++  printf("Mesh Topology:\n\n");
++  printf(
++"  You may wish to know which triangles are adjacent to a certain Delaunay\n");
++  printf(
++"  edge in an .edge file, which Voronoi regions are adjacent to a certain\n");
++  printf(
++"  Voronoi edge in a .v.edge file, or which Voronoi regions are adjacent to\n"
++);
++  printf(
++"  each other.  All of this information can be found by cross-referencing\n");
++  printf(
++"  output files with the recollection that the Delaunay triangulation and\n");
++  printf("  the Voronoi diagrams are planar duals.\n\n");
++  printf(
++"  Specifically, edge i of an .edge file is the dual of Voronoi edge i of\n");
++  printf(
++"  the corresponding .v.edge file, and is rotated 90 degrees counterclock-\n");
++  printf(
++"  wise from the Voronoi edge.  Triangle j of an .ele file is the dual of\n");
++  printf(
++"  vertex j of the corresponding .v.node file; and Voronoi region k is the\n");
++  printf("  dual of point k of the corresponding .node file.\n\n");
++  printf(
++"  Hence, to find the triangles adjacent to a Delaunay edge, look at the\n");
++  printf(
++"  vertices of the corresponding Voronoi edge; their dual triangles are on\n");
++  printf(
++"  the left and right of the Delaunay edge, respectively.  To find the\n");
++  printf(
++"  Voronoi regions adjacent to a Voronoi edge, look at the endpoints of the\n"
++);
++  printf(
++"  corresponding Delaunay edge; their dual regions are on the right and left\n"
++);
++  printf(
++"  of the Voronoi edge, respectively.  To find which Voronoi regions are\n");
++  printf("  adjacent to each other, just read the list of Delaunay edges.\n");
++  printf("\n");
++  printf("Statistics:\n");
++  printf("\n");
++  printf(
++"  After generating a mesh, Triangle prints a count of the number of points,\n"
++);
++  printf(
++"  triangles, edges, boundary edges, and segments in the output mesh.  If\n");
++  printf(
++"  you've forgotten the statistics for an existing mesh, the -rNEP switches\n"
++);
++  printf(
++"  (or -rpNEP if you've got a .poly file for the existing mesh) will\n");
++  printf("  regenerate these statistics without writing any output.\n\n");
++  printf(
++"  The -V switch produces extended statistics, including a rough estimate\n");
++  printf(
++"  of memory use and a histogram of triangle aspect ratios and angles in the\n"
++);
++  printf("  mesh.\n\n");
++  printf("Exact Arithmetic:\n\n");
++  printf(
++"  Triangle uses adaptive exact arithmetic to perform what computational\n");
++  printf(
++"  geometers call the `orientation' and `incircle' tests.  If the floating-\n"
++);
++  printf(
++"  point arithmetic of your machine conforms to the IEEE 754 standard (as\n");
++  printf(
++"  most workstations do), and does not use extended precision internal\n");
++  printf(
++"  registers, then your output is guaranteed to be an absolutely true\n");
++  printf("  Delaunay or conforming Delaunay triangulation, roundoff error\n");
++  printf(
++"  notwithstanding.  The word `adaptive' implies that these arithmetic\n");
++  printf(
++"  routines compute the result only to the precision necessary to guarantee\n"
++);
++  printf(
++"  correctness, so they are usually nearly as fast as their approximate\n");
++  printf(
++"  counterparts.  The exact tests can be disabled with the -X switch.  On\n");
++  printf(
++"  most inputs, this switch will reduce the computation time by about eight\n"
++);
++  printf(
++"  percent - it's not worth the risk.  There are rare difficult inputs\n");
++  printf(
++"  (having many collinear and cocircular points), however, for which the\n");
++  printf(
++"  difference could be a factor of two.  These are precisely the inputs most\n"
++);
++  printf("  likely to cause errors if you use the -X switch.\n\n");
++  printf(
++"  Unfortunately, these routines don't solve every numerical problem.  Exact\n"
++);
++  printf(
++"  arithmetic is not used to compute the positions of points, because the\n");
++  printf(
++"  bit complexity of point coordinates would grow without bound.  Hence,\n");
++  printf(
++"  segment intersections aren't computed exactly; in very unusual cases,\n");
++  printf(
++"  roundoff error in computing an intersection point might actually lead to\n"
++);
++  printf(
++"  an inverted triangle and an invalid triangulation.  (This is one reason\n");
++  printf(
++"  to compute your own intersection points in your .poly files.)  Similarly,\n"
++);
++  printf(
++"  exact arithmetic is not used to compute the vertices of the Voronoi\n");
++  printf("  diagram.\n\n");
++  printf(
++"  Underflow and overflow can also cause difficulties; the exact arithmetic\n"
++);
++  printf(
++"  routines do not ameliorate out-of-bounds exponents, which can arise\n");
++  printf(
++"  during the orientation and incircle tests.  As a rule of thumb, you\n");
++  printf(
++"  should ensure that your input values are within a range such that their\n");
++  printf(
++"  third powers can be taken without underflow or overflow.  Underflow can\n");
++  printf(
++"  silently prevent the tests from being performed exactly, while overflow\n");
++  printf("  will typically cause a floating exception.\n\n");
++  printf("Calling Triangle from Another Program:\n\n");
++  printf("  Read the file triangle.h for details.\n\n");
++  printf("Troubleshooting:\n\n");
++  printf("  Please read this section before mailing me bugs.\n\n");
++  printf("  `My output mesh has no triangles!'\n\n");
++  printf(
++"    If you're using a PSLG, you've probably failed to specify a proper set\n"
++);
++  printf(
++"    of bounding segments, or forgotten to use the -c switch.  Or you may\n");
++  printf(
++"    have placed a hole badly.  To test these possibilities, try again with\n"
++);
++  printf(
++"    the -c and -O switches.  Alternatively, all your input points may be\n");
++  printf(
++"    collinear, in which case you can hardly expect to triangulate them.\n");
++  printf("\n");
++  printf("  `Triangle doesn't terminate, or just crashes.'\n");
++  printf("\n");
++  printf(
++"    Bad things can happen when triangles get so small that the distance\n");
++  printf(
++"    between their vertices isn't much larger than the precision of your\n");
++  printf(
++"    machine's arithmetic.  If you've compiled Triangle for single-precision\n"
++);
++  printf(
++"    arithmetic, you might do better by recompiling it for double-precision.\n"
++);
++  printf(
++"    Then again, you might just have to settle for more lenient constraints\n"
++);
++  printf(
++"    on the minimum angle and the maximum area than you had planned.\n");
++  printf("\n");
++  printf(
++"    You can minimize precision problems by ensuring that the origin lies\n");
++  printf(
++"    inside your point set, or even inside the densest part of your\n");
++  printf(
++"    mesh.  On the other hand, if you're triangulating an object whose x\n");
++  printf(
++"    coordinates all fall between 6247133 and 6247134, you're not leaving\n");
++  printf("    much floating-point precision for Triangle to work with.\n\n");
++  printf(
++"    Precision problems can occur covertly if the input PSLG contains two\n");
++  printf(
++"    segments that meet (or intersect) at a very small angle, or if such an\n"
++);
++  printf(
++"    angle is introduced by the -c switch, which may occur if a point lies\n");
++  printf(
++"    ever-so-slightly inside the convex hull, and is connected by a PSLG\n");
++  printf(
++"    segment to a point on the convex hull.  If you don't realize that a\n");
++  printf(
++"    small angle is being formed, you might never discover why Triangle is\n");
++  printf(
++"    crashing.  To check for this possibility, use the -S switch (with an\n");
++  printf(
++"    appropriate limit on the number of Steiner points, found by trial-and-\n"
++);
++  printf(
++"    error) to stop Triangle early, and view the output .poly file with\n");
++  printf(
++"    Show Me (described below).  Look carefully for small angles between\n");
++  printf(
++"    segments; zoom in closely, as such segments might look like a single\n");
++  printf("    segment from a distance.\n\n");
++  printf(
++"    If some of the input values are too large, Triangle may suffer a\n");
++  printf(
++"    floating exception due to overflow when attempting to perform an\n");
++  printf(
++"    orientation or incircle test.  (Read the section on exact arithmetic\n");
++  printf(
++"    above.)  Again, I recommend compiling Triangle for double (rather\n");
++  printf("    than single) precision arithmetic.\n\n");
++  printf(
++"  `The numbering of the output points doesn't match the input points.'\n");
++  printf("\n");
++  printf(
++"    You may have eaten some of your input points with a hole, or by placing\n"
++);
++  printf("    them outside the area enclosed by segments.\n\n");
++  printf(
++"  `Triangle executes without incident, but when I look at the resulting\n");
++  printf(
++"  mesh, it has overlapping triangles or other geometric inconsistencies.'\n");
++  printf("\n");
++  printf(
++"    If you select the -X switch, Triangle's divide-and-conquer Delaunay\n");
++  printf(
++"    triangulation algorithm occasionally makes mistakes due to floating-\n");
++  printf(
++"    point roundoff error.  Although these errors are rare, don't use the -X\n"
++);
++  printf("    switch.  If you still have problems, please report the bug.\n");
++  printf("\n");
++  printf(
++"  Strange things can happen if you've taken liberties with your PSLG.  Do\n");
++  printf(
++"  you have a point lying in the middle of a segment?  Triangle sometimes\n");
++  printf(
++"  copes poorly with that sort of thing.  Do you want to lay out a collinear\n"
++);
++  printf(
++"  row of evenly spaced, segment-connected points?  Have you simply defined\n"
++);
++  printf(
++"  one long segment connecting the leftmost point to the rightmost point,\n");
++  printf(
++"  and a bunch of points lying along it?  This method occasionally works,\n");
++  printf(
++"  especially with horizontal and vertical lines, but often it doesn't, and\n"
++);
++  printf(
++"  you'll have to connect each adjacent pair of points with a separate\n");
++  printf("  segment.  If you don't like it, tough.\n\n");
++  printf(
++"  Furthermore, if you have segments that intersect other than at their\n");
++  printf(
++"  endpoints, try not to let the intersections fall extremely close to PSLG\n"
++);
++  printf("  points or each other.\n\n");
++  printf(
++"  If you have problems refining a triangulation not produced by Triangle:\n");
++  printf(
++"  Are you sure the triangulation is geometrically valid?  Is it formatted\n");
++  printf(
++"  correctly for Triangle?  Are the triangles all listed so the first three\n"
++);
++  printf("  points are their corners in counterclockwise order?\n\n");
++  printf("Show Me:\n\n");
++  printf(
++"  Triangle comes with a separate program named `Show Me', whose primary\n");
++  printf(
++"  purpose is to draw meshes on your screen or in PostScript.  Its secondary\n"
++);
++  printf(
++"  purpose is to check the validity of your input files, and do so more\n");
++  printf(
++"  thoroughly than Triangle does.  Show Me requires that you have the X\n");
++  printf(
++"  Windows system.  If you didn't receive Show Me with Triangle, complain to\n"
++);
++  printf("  whomever you obtained Triangle from, then send me mail.\n\n");
++  printf("Triangle on the Web:\n\n");
++  printf(
++"  To see an illustrated, updated version of these instructions, check out\n");
++  printf("\n");
++  printf("    http://www.cs.cmu.edu/~quake/triangle.html\n");
++  printf("\n");
++  printf("A Brief Plea:\n");
++  printf("\n");
++  printf(
++"  If you use Triangle, and especially if you use it to accomplish real\n");
++  printf(
++"  work, I would like very much to hear from you.  A short letter or email\n");
++  printf(
++"  (to jrs@cs.cmu.edu) describing how you use Triangle will mean a lot to\n");
++  printf(
++"  me.  The more people I know are using this program, the more easily I can\n"
++);
++  printf(
++"  justify spending time on improvements and on the three-dimensional\n");
++  printf(
++"  successor to Triangle, which in turn will benefit you.  Also, I can put\n");
++  printf(
++"  you on a list to receive email whenever a new version of Triangle is\n");
++  printf("  available.\n\n");
++  printf(
++"  If you use a mesh generated by Triangle in a publication, please include\n"
++);
++  printf("  an acknowledgment as well.\n\n");
++  printf("Research credit:\n\n");
++  printf(
++"  Of course, I can take credit for only a fraction of the ideas that made\n");
++  printf(
++"  this mesh generator possible.  Triangle owes its existence to the efforts\n"
++);
++  printf(
++"  of many fine computational geometers and other researchers, including\n");
++  printf(
++"  Marshall Bern, L. Paul Chew, Boris Delaunay, Rex A. Dwyer, David\n");
++  printf(
++"  Eppstein, Steven Fortune, Leonidas J. Guibas, Donald E. Knuth, C. L.\n");
++  printf(
++"  Lawson, Der-Tsai Lee, Ernst P. Mucke, Douglas M. Priest, Jim Ruppert,\n");
++  printf(
++"  Isaac Saias, Bruce J. Schachter, Micha Sharir, Jorge Stolfi, Christopher\n"
++);
++  printf(
++"  J. Van Wyk, David F. Watson, and Binhai Zhu.  See the comments at the\n");
++  printf("  beginning of the source code for references.\n\n");
++  exit(0);
++}
++
++#endif /* not TRILIBRARY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  internalerror()   Ask the user to send me the defective product.  Exit.  */
++/*                                                                           */
++/*****************************************************************************/
++
++void internalerror()
++{
++  printf("  Please report this bug to jrs@cs.cmu.edu\n");
++  printf("  Include the message above, your input data set, and the exact\n");
++  printf("    command line you used to run Triangle.\n");
++  exit(1);
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  parsecommandline()   Read the command line, identify switches, and set   */
++/*                       up options and file names.                          */
++/*                                                                           */
++/*  The effects of this routine are felt entirely through global variables.  */
++/*                                                                           */
++/*****************************************************************************/
++
++void parsecommandline(argc, argv)
++int argc;
++char **argv;
++{
++#ifdef TRILIBRARY
++#define STARTINDEX 0
++#else /* not TRILIBRARY */
++#define STARTINDEX 1
++  int increment;
++  int meshnumber;
++#endif /* not TRILIBRARY */
++  int i, j, k;
++  char workstring[FILENAMESIZE];
++
++  poly = refine = quality = vararea = fixedarea = regionattrib = convex = 0;
++  firstnumber = 1;
++  edgesout = voronoi = neighbors = geomview = 0;
++  nobound = nopolywritten = nonodewritten = noelewritten = noiterationnum = 0;
++  noholes = noexact = 0;
++  incremental = sweepline = 0;
++  dwyer = 1;
++  splitseg = 0;
++  docheck = 0;
++  nobisect = 0;
++  steiner = -1;
++  order = 1;
++  minangle = 0.0;
++  maxarea = -1.0;
++  quiet = verbose = 0;
++#ifndef TRILIBRARY
++  innodefilename[0] = '\0';
++#endif /* not TRILIBRARY */
++
++  for (i = STARTINDEX; i < argc; i++) {
++#ifndef TRILIBRARY
++    if (argv[i][0] == '-') {
++#endif /* not TRILIBRARY */
++      for (j = STARTINDEX; argv[i][j] != '\0'; j++) {
++        if (argv[i][j] == 'p') {
++          poly = 1;
++      }
++#ifndef CDT_ONLY
++        if (argv[i][j] == 'r') {
++          refine = 1;
++      }
++        if (argv[i][j] == 'q') {
++          quality = 1;
++          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
++              (argv[i][j + 1] == '.')) {
++            k = 0;
++            while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
++                   (argv[i][j + 1] == '.')) {
++              j++;
++              workstring[k] = argv[i][j];
++              k++;
++            }
++            workstring[k] = '\0';
++            minangle = (REAL) strtod(workstring, (char **) NULL);
++        } else {
++            minangle = 20.0;
++        }
++      }
++        if (argv[i][j] == 'a') {
++          quality = 1;
++          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
++              (argv[i][j + 1] == '.')) {
++            fixedarea = 1;
++            k = 0;
++            while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
++                   (argv[i][j + 1] == '.')) {
++              j++;
++              workstring[k] = argv[i][j];
++              k++;
++            }
++            workstring[k] = '\0';
++            maxarea = (REAL) strtod(workstring, (char **) NULL);
++            if (maxarea <= 0.0) {
++              printf("Error:  Maximum area must be greater than zero.\n");
++              exit(1);
++          }
++        } else {
++            vararea = 1;
++        }
++      }
++#endif /* not CDT_ONLY */
++        if (argv[i][j] == 'A') {
++          regionattrib = 1;
++        }
++        if (argv[i][j] == 'c') {
++          convex = 1;
++        }
++        if (argv[i][j] == 'z') {
++          firstnumber = 0;
++        }
++        if (argv[i][j] == 'e') {
++          edgesout = 1;
++      }
++        if (argv[i][j] == 'v') {
++          voronoi = 1;
++      }
++        if (argv[i][j] == 'n') {
++          neighbors = 1;
++      }
++        if (argv[i][j] == 'g') {
++          geomview = 1;
++      }
++        if (argv[i][j] == 'B') {
++          nobound = 1;
++      }
++        if (argv[i][j] == 'P') {
++          nopolywritten = 1;
++      }
++        if (argv[i][j] == 'N') {
++          nonodewritten = 1;
++      }
++        if (argv[i][j] == 'E') {
++          noelewritten = 1;
++      }
++#ifndef TRILIBRARY
++        if (argv[i][j] == 'I') {
++          noiterationnum = 1;
++      }
++#endif /* not TRILIBRARY */
++        if (argv[i][j] == 'O') {
++          noholes = 1;
++      }
++        if (argv[i][j] == 'X') {
++          noexact = 1;
++      }
++        if (argv[i][j] == 'o') {
++          if (argv[i][j + 1] == '2') {
++            j++;
++            order = 2;
++          }
++      }
++#ifndef CDT_ONLY
++        if (argv[i][j] == 'Y') {
++          nobisect++;
++      }
++        if (argv[i][j] == 'S') {
++          steiner = 0;
++          while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
++            j++;
++            steiner = steiner * 10 + (int) (argv[i][j] - '0');
++          }
++        }
++#endif /* not CDT_ONLY */
++#ifndef REDUCED
++        if (argv[i][j] == 'i') {
++          incremental = 1;
++        }
++        if (argv[i][j] == 'F') {
++          sweepline = 1;
++        }
++#endif /* not REDUCED */
++        if (argv[i][j] == 'l') {
++          dwyer = 0;
++        }
++#ifndef REDUCED
++#ifndef CDT_ONLY
++        if (argv[i][j] == 's') {
++          splitseg = 1;
++        }
++#endif /* not CDT_ONLY */
++        if (argv[i][j] == 'C') {
++          docheck = 1;
++        }
++#endif /* not REDUCED */
++        if (argv[i][j] == 'Q') {
++          quiet = 1;
++        }
++        if (argv[i][j] == 'V') {
++          verbose++;
++        }
++#ifndef TRILIBRARY
++        if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
++            (argv[i][j] == '?')) {
++          info();
++      }
++#endif /* not TRILIBRARY */
++      }
++#ifndef TRILIBRARY
++    } else {
++      strncpy(innodefilename, argv[i], FILENAMESIZE - 1);
++      innodefilename[FILENAMESIZE - 1] = '\0';
++    }
++#endif /* not TRILIBRARY */
++  }
++#ifndef TRILIBRARY
++  if (innodefilename[0] == '\0') {
++    syntax();
++  }
++  if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".node")) {
++    innodefilename[strlen(innodefilename) - 5] = '\0';
++  }
++  if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".poly")) {
++    innodefilename[strlen(innodefilename) - 5] = '\0';
++    poly = 1;
++  }
++#ifndef CDT_ONLY
++  if (!strcmp(&innodefilename[strlen(innodefilename) - 4], ".ele")) {
++    innodefilename[strlen(innodefilename) - 4] = '\0';
++    refine = 1;
++  }
++  if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".area")) {
++    innodefilename[strlen(innodefilename) - 5] = '\0';
++    refine = 1;
++    quality = 1;
++    vararea = 1;
++  }
++#endif /* not CDT_ONLY */
++#endif /* not TRILIBRARY */
++  steinerleft = steiner;
++  useshelles = poly || refine || quality || convex;
++  goodangle = cos(minangle * PI / 180.0);
++  goodangle *= goodangle;
++  if (refine && noiterationnum) {
++    printf(
++      "Error:  You cannot use the -I switch when refining a triangulation.\n");
++    exit(1);
++  }
++  /* Be careful not to allocate space for element area constraints that */
++  /*   will never be assigned any value (other than the default -1.0).  */
++  if (!refine && !poly) {
++    vararea = 0;
++  }
++  /* Be careful not to add an extra attribute to each element unless the */
++  /*   input supports it (PSLG in, but not refining a preexisting mesh). */
++  if (refine || !poly) {
++    regionattrib = 0;
++  }
++
++#ifndef TRILIBRARY
++  strcpy(inpolyfilename, innodefilename);
++  strcpy(inelefilename, innodefilename);
++  strcpy(areafilename, innodefilename);
++  increment = 0;
++  strcpy(workstring, innodefilename);
++  j = 1;
++  while (workstring[j] != '\0') {
++    if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
++      increment = j + 1;
++    }
++    j++;
++  }
++  meshnumber = 0;
++  if (increment > 0) {
++    j = increment;
++    do {
++      if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
++        meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
++      } else {
++        increment = 0;
++      }
++      j++;
++    } while (workstring[j] != '\0');
++  }
++  if (noiterationnum) {
++    strcpy(outnodefilename, innodefilename);
++    strcpy(outelefilename, innodefilename);
++    strcpy(edgefilename, innodefilename);
++    strcpy(vnodefilename, innodefilename);
++    strcpy(vedgefilename, innodefilename);
++    strcpy(neighborfilename, innodefilename);
++    strcpy(offfilename, innodefilename);
++    strcat(outnodefilename, ".node");
++    strcat(outelefilename, ".ele");
++    strcat(edgefilename, ".edge");
++    strcat(vnodefilename, ".v.node");
++    strcat(vedgefilename, ".v.edge");
++    strcat(neighborfilename, ".neigh");
++    strcat(offfilename, ".off");
++  } else if (increment == 0) {
++    strcpy(outnodefilename, innodefilename);
++    strcpy(outpolyfilename, innodefilename);
++    strcpy(outelefilename, innodefilename);
++    strcpy(edgefilename, innodefilename);
++    strcpy(vnodefilename, innodefilename);
++    strcpy(vedgefilename, innodefilename);
++    strcpy(neighborfilename, innodefilename);
++    strcpy(offfilename, innodefilename);
++    strcat(outnodefilename, ".1.node");
++    strcat(outpolyfilename, ".1.poly");
++    strcat(outelefilename, ".1.ele");
++    strcat(edgefilename, ".1.edge");
++    strcat(vnodefilename, ".1.v.node");
++    strcat(vedgefilename, ".1.v.edge");
++    strcat(neighborfilename, ".1.neigh");
++    strcat(offfilename, ".1.off");
++  } else {
++    workstring[increment] = '%';
++    workstring[increment + 1] = 'd';
++    workstring[increment + 2] = '\0';
++    sprintf(outnodefilename, workstring, meshnumber + 1);
++    strcpy(outpolyfilename, outnodefilename);
++    strcpy(outelefilename, outnodefilename);
++    strcpy(edgefilename, outnodefilename);
++    strcpy(vnodefilename, outnodefilename);
++    strcpy(vedgefilename, outnodefilename);
++    strcpy(neighborfilename, outnodefilename);
++    strcpy(offfilename, outnodefilename);
++    strcat(outnodefilename, ".node");
++    strcat(outpolyfilename, ".poly");
++    strcat(outelefilename, ".ele");
++    strcat(edgefilename, ".edge");
++    strcat(vnodefilename, ".v.node");
++    strcat(vedgefilename, ".v.edge");
++    strcat(neighborfilename, ".neigh");
++    strcat(offfilename, ".off");
++  }
++  strcat(innodefilename, ".node");
++  strcat(inpolyfilename, ".poly");
++  strcat(inelefilename, ".ele");
++  strcat(areafilename, ".area");
++#endif /* not TRILIBRARY */
++}
++
++/**                                                                         **/
++/**                                                                         **/
++/********* User interaction routines begin here                      *********/
++
++/********* Debugging routines begin here                             *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  printtriangle()   Print out the details of a triangle/edge handle.       */
++/*                                                                           */
++/*  I originally wrote this procedure to simplify debugging; it can be       */
++/*  called directly from the debugger, and presents information about a      */
++/*  triangle/edge handle in digestible form.  It's also used when the        */
++/*  highest level of verbosity (`-VVV') is specified.                        */
++/*                                                                           */
++/*****************************************************************************/
++
++void printtriangle(t)
++struct triedge *t;
++{
++  struct triedge printtri;
++  struct edge printsh;
++  point printpoint;
++
++  printf("triangle x%lx with orientation %d:\n", (unsigned long) t->tri,
++         t->orient);
++  decode(t->tri[0], printtri);
++  if (printtri.tri == dummytri) {
++    printf("    [0] = Outer space\n");
++  } else {
++    printf("    [0] = x%lx  %d\n", (unsigned long) printtri.tri,
++           printtri.orient);
++  }
++  decode(t->tri[1], printtri);
++  if (printtri.tri == dummytri) {
++    printf("    [1] = Outer space\n");
++  } else {
++    printf("    [1] = x%lx  %d\n", (unsigned long) printtri.tri,
++           printtri.orient);
++  }
++  decode(t->tri[2], printtri);
++  if (printtri.tri == dummytri) {
++    printf("    [2] = Outer space\n");
++  } else {
++    printf("    [2] = x%lx  %d\n", (unsigned long) printtri.tri,
++           printtri.orient);
++  }
++  org(*t, printpoint);
++  if (printpoint == (point) NULL)
++    printf("    Origin[%d] = NULL\n", (t->orient + 1) % 3 + 3);
++  else
++    printf("    Origin[%d] = x%lx  (%.12g, %.12g)\n",
++           (t->orient + 1) % 3 + 3, (unsigned long) printpoint,
++           printpoint[0], printpoint[1]);
++  dest(*t, printpoint);
++  if (printpoint == (point) NULL)
++    printf("    Dest  [%d] = NULL\n", (t->orient + 2) % 3 + 3);
++  else
++    printf("    Dest  [%d] = x%lx  (%.12g, %.12g)\n",
++           (t->orient + 2) % 3 + 3, (unsigned long) printpoint,
++           printpoint[0], printpoint[1]);
++  apex(*t, printpoint);
++  if (printpoint == (point) NULL)
++    printf("    Apex  [%d] = NULL\n", t->orient + 3);
++  else
++    printf("    Apex  [%d] = x%lx  (%.12g, %.12g)\n",
++           t->orient + 3, (unsigned long) printpoint,
++           printpoint[0], printpoint[1]);
++  if (useshelles) {
++    sdecode(t->tri[6], printsh);
++    if (printsh.sh != dummysh) {
++      printf("    [6] = x%lx  %d\n", (unsigned long) printsh.sh,
++             printsh.shorient);
++    }
++    sdecode(t->tri[7], printsh);
++    if (printsh.sh != dummysh) {
++      printf("    [7] = x%lx  %d\n", (unsigned long) printsh.sh,
++             printsh.shorient);
++    }
++    sdecode(t->tri[8], printsh);
++    if (printsh.sh != dummysh) {
++      printf("    [8] = x%lx  %d\n", (unsigned long) printsh.sh,
++             printsh.shorient);
++    }
++  }
++  if (vararea) {
++    printf("    Area constraint:  %.4g\n", areabound(*t));
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  printshelle()   Print out the details of a shell edge handle.            */
++/*                                                                           */
++/*  I originally wrote this procedure to simplify debugging; it can be       */
++/*  called directly from the debugger, and presents information about a      */
++/*  shell edge handle in digestible form.  It's also used when the highest   */
++/*  level of verbosity (`-VVV') is specified.                                */
++/*                                                                           */
++/*****************************************************************************/
++
++void printshelle(s)
++struct edge *s;
++{
++  struct edge printsh;
++  struct triedge printtri;
++  point printpoint;
++
++  printf("shell edge x%lx with orientation %d and mark %d:\n",
++         (unsigned long) s->sh, s->shorient, mark(*s));
++  sdecode(s->sh[0], printsh);
++  if (printsh.sh == dummysh) {
++    printf("    [0] = No shell\n");
++  } else {
++    printf("    [0] = x%lx  %d\n", (unsigned long) printsh.sh,
++           printsh.shorient);
++  }
++  sdecode(s->sh[1], printsh);
++  if (printsh.sh == dummysh) {
++    printf("    [1] = No shell\n");
++  } else {
++    printf("    [1] = x%lx  %d\n", (unsigned long) printsh.sh,
++           printsh.shorient);
++  }
++  sorg(*s, printpoint);
++  if (printpoint == (point) NULL)
++    printf("    Origin[%d] = NULL\n", 2 + s->shorient);
++  else
++    printf("    Origin[%d] = x%lx  (%.12g, %.12g)\n",
++           2 + s->shorient, (unsigned long) printpoint,
++           printpoint[0], printpoint[1]);
++  sdest(*s, printpoint);
++  if (printpoint == (point) NULL)
++    printf("    Dest  [%d] = NULL\n", 3 - s->shorient);
++  else
++    printf("    Dest  [%d] = x%lx  (%.12g, %.12g)\n",
++           3 - s->shorient, (unsigned long) printpoint,
++           printpoint[0], printpoint[1]);
++  decode(s->sh[4], printtri);
++  if (printtri.tri == dummytri) {
++    printf("    [4] = Outer space\n");
++  } else {
++    printf("    [4] = x%lx  %d\n", (unsigned long) printtri.tri,
++           printtri.orient);
++  }
++  decode(s->sh[5], printtri);
++  if (printtri.tri == dummytri) {
++    printf("    [5] = Outer space\n");
++  } else {
++    printf("    [5] = x%lx  %d\n", (unsigned long) printtri.tri,
++           printtri.orient);
++  }
++}
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Debugging routines end here                               *********/
++
++/********* Memory management routines begin here                     *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  poolinit()   Initialize a pool of memory for allocation of items.        */
++/*                                                                           */
++/*  This routine initializes the machinery for allocating items.  A `pool'   */
++/*  is created whose records have size at least `bytecount'.  Items will be  */
++/*  allocated in `itemcount'-item blocks.  Each item is assumed to be a      */
++/*  collection of words, and either pointers or floating-point values are    */
++/*  assumed to be the "primary" word type.  (The "primary" word type is used */
++/*  to determine alignment of items.)  If `alignment' isn't zero, all items  */
++/*  will be `alignment'-byte aligned in memory.  `alignment' must be either  */
++/*  a multiple or a factor of the primary word size; powers of two are safe. */
++/*  `alignment' is normally used to create a few unused bits at the bottom   */
++/*  of each item's pointer, in which information may be stored.              */
++/*                                                                           */
++/*  Don't change this routine unless you understand it.                      */
++/*                                                                           */
++/*****************************************************************************/
++
++void poolinit(pool, bytecount, itemcount, wtype, alignment)
++struct memorypool *pool;
++int bytecount;
++int itemcount;
++enum wordtype wtype;
++int alignment;
++{
++  int wordsize;
++
++  /* Initialize values in the pool. */
++  pool->itemwordtype = wtype;
++  wordsize = (pool->itemwordtype == POINTER) ? sizeof(VOID *) : sizeof(REAL);
++  /* Find the proper alignment, which must be at least as large as:   */
++  /*   - The parameter `alignment'.                                   */
++  /*   - The primary word type, to avoid unaligned accesses.          */
++  /*   - sizeof(VOID *), so the stack of dead items can be maintained */
++  /*       without unaligned accesses.                                */
++  if (alignment > wordsize) {
++    pool->alignbytes = alignment;
++  } else {
++    pool->alignbytes = wordsize;
++  }
++  if (sizeof(VOID *) > pool->alignbytes) {
++    pool->alignbytes = sizeof(VOID *);
++  }
++  pool->itemwords = ((bytecount + pool->alignbytes - 1) / pool->alignbytes)
++                  * (pool->alignbytes / wordsize);
++  pool->itembytes = pool->itemwords * wordsize;
++  pool->itemsperblock = itemcount;
++
++  /* Allocate a block of items.  Space for `itemsperblock' items and one    */
++  /*   pointer (to point to the next block) are allocated, as well as space */
++  /*   to ensure alignment of the items.                                    */
++  pool->firstblock = (VOID **) malloc(pool->itemsperblock * pool->itembytes
++                                      + sizeof(VOID *) + pool->alignbytes);
++  if (pool->firstblock == (VOID **) NULL) {
++    printf("Error:  Out of memory.\n");
++    exit(1);
++  }
++  /* Set the next block pointer to NULL. */
++  *(pool->firstblock) = (VOID *) NULL;
++  poolrestart(pool);
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  poolrestart()   Deallocate all items in a pool.                          */
++/*                                                                           */
++/*  The pool is returned to its starting state, except that no memory is     */
++/*  freed to the operating system.  Rather, the previously allocated blocks  */
++/*  are ready to be reused.                                                  */
++/*                                                                           */
++/*****************************************************************************/
++
++void poolrestart(pool)
++struct memorypool *pool;
++{
++  unsigned long alignptr;
++
++  pool->items = 0;
++  pool->maxitems = 0;
++
++  /* Set the currently active block. */
++  pool->nowblock = pool->firstblock;
++  /* Find the first item in the pool.  Increment by the size of (VOID *). */
++  alignptr = (unsigned long) (pool->nowblock + 1);
++  /* Align the item on an `alignbytes'-byte boundary. */
++  pool->nextitem = (VOID *)
++    (alignptr + (unsigned long) pool->alignbytes
++     - (alignptr % (unsigned long) pool->alignbytes));
++  /* There are lots of unallocated items left in this block. */
++  pool->unallocateditems = pool->itemsperblock;
++  /* The stack of deallocated items is empty. */
++  pool->deaditemstack = (VOID *) NULL;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  pooldeinit()   Free to the operating system all memory taken by a pool.  */
++/*                                                                           */
++/*****************************************************************************/
++
++void pooldeinit(pool)
++struct memorypool *pool;
++{
++  while (pool->firstblock != (VOID **) NULL) {
++    pool->nowblock = (VOID **) *(pool->firstblock);
++    free(pool->firstblock);
++    pool->firstblock = pool->nowblock;
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  poolalloc()   Allocate space for an item.                                */
++/*                                                                           */
++/*****************************************************************************/
++
++VOID *poolalloc(pool)
++struct memorypool *pool;
++{
++  VOID *newitem;
++  VOID **newblock;
++  unsigned long alignptr;
++
++  /* First check the linked list of dead items.  If the list is not   */
++  /*   empty, allocate an item from the list rather than a fresh one. */
++  if (pool->deaditemstack != (VOID *) NULL) {
++    newitem = pool->deaditemstack;               /* Take first item in list. */
++    pool->deaditemstack = * (VOID **) pool->deaditemstack;
++  } else {
++    /* Check if there are any free items left in the current block. */
++    if (pool->unallocateditems == 0) {
++      /* Check if another block must be allocated. */
++      if (*(pool->nowblock) == (VOID *) NULL) {
++        /* Allocate a new block of items, pointed to by the previous block. */
++        newblock = (VOID **) malloc(pool->itemsperblock * pool->itembytes
++                                    + sizeof(VOID *) + pool->alignbytes);
++        if (newblock == (VOID **) NULL) {
++          printf("Error:  Out of memory.\n");
++          exit(1);
++        }
++        *(pool->nowblock) = (VOID *) newblock;
++        /* The next block pointer is NULL. */
++        *newblock = (VOID *) NULL;
++      }
++      /* Move to the new block. */
++      pool->nowblock = (VOID **) *(pool->nowblock);
++      /* Find the first item in the block.    */
++      /*   Increment by the size of (VOID *). */
++      alignptr = (unsigned long) (pool->nowblock + 1);
++      /* Align the item on an `alignbytes'-byte boundary. */
++      pool->nextitem = (VOID *)
++        (alignptr + (unsigned long) pool->alignbytes
++         - (alignptr % (unsigned long) pool->alignbytes));
++      /* There are lots of unallocated items left in this block. */
++      pool->unallocateditems = pool->itemsperblock;
++    }
++    /* Allocate a new item. */
++    newitem = pool->nextitem;
++    /* Advance `nextitem' pointer to next free item in block. */
++    if (pool->itemwordtype == POINTER) {
++      pool->nextitem = (VOID *) ((VOID **) pool->nextitem + pool->itemwords);
++    } else {
++      pool->nextitem = (VOID *) ((REAL *) pool->nextitem + pool->itemwords);
++    }
++    pool->unallocateditems--;
++    pool->maxitems++;
++  }
++  pool->items++;
++  return newitem;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  pooldealloc()   Deallocate space for an item.                            */
++/*                                                                           */
++/*  The deallocated space is stored in a queue for later reuse.              */
++/*                                                                           */
++/*****************************************************************************/
++
++void pooldealloc(pool, dyingitem)
++struct memorypool *pool;
++VOID *dyingitem;
++{
++  /* Push freshly killed item onto stack. */
++  *((VOID **) dyingitem) = pool->deaditemstack;
++  pool->deaditemstack = dyingitem;
++  pool->items--;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  traversalinit()   Prepare to traverse the entire list of items.          */
++/*                                                                           */
++/*  This routine is used in conjunction with traverse().                     */
++/*                                                                           */
++/*****************************************************************************/
++
++void traversalinit(pool)
++struct memorypool *pool;
++{
++  unsigned long alignptr;
++
++  /* Begin the traversal in the first block. */
++  pool->pathblock = pool->firstblock;
++  /* Find the first item in the block.  Increment by the size of (VOID *). */
++  alignptr = (unsigned long) (pool->pathblock + 1);
++  /* Align with item on an `alignbytes'-byte boundary. */
++  pool->pathitem = (VOID *)
++    (alignptr + (unsigned long) pool->alignbytes
++     - (alignptr % (unsigned long) pool->alignbytes));
++  /* Set the number of items left in the current block. */
++  pool->pathitemsleft = pool->itemsperblock;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  traverse()   Find the next item in the list.                             */
++/*                                                                           */
++/*  This routine is used in conjunction with traversalinit().  Be forewarned */
++/*  that this routine successively returns all items in the list, including  */
++/*  deallocated ones on the deaditemqueue.  It's up to you to figure out     */
++/*  which ones are actually dead.  Why?  I don't want to allocate extra      */
++/*  space just to demarcate dead items.  It can usually be done more         */
++/*  space-efficiently by a routine that knows something about the structure  */
++/*  of the item.                                                             */
++/*                                                                           */
++/*****************************************************************************/
++
++VOID *traverse(pool)
++struct memorypool *pool;
++{
++  VOID *newitem;
++  unsigned long alignptr;
++
++  /* Stop upon exhausting the list of items. */
++  if (pool->pathitem == pool->nextitem) {
++    return (VOID *) NULL;
++  }
++  /* Check whether any untraversed items remain in the current block. */
++  if (pool->pathitemsleft == 0) {
++    /* Find the next block. */
++    pool->pathblock = (VOID **) *(pool->pathblock);
++    /* Find the first item in the block.  Increment by the size of (VOID *). */
++    alignptr = (unsigned long) (pool->pathblock + 1);
++    /* Align with item on an `alignbytes'-byte boundary. */
++    pool->pathitem = (VOID *)
++      (alignptr + (unsigned long) pool->alignbytes
++       - (alignptr % (unsigned long) pool->alignbytes));
++    /* Set the number of items left in the current block. */
++    pool->pathitemsleft = pool->itemsperblock;
++  }
++  newitem = pool->pathitem;
++  /* Find the next item in the block. */
++  if (pool->itemwordtype == POINTER) {
++    pool->pathitem = (VOID *) ((VOID **) pool->pathitem + pool->itemwords);
++  } else {
++    pool->pathitem = (VOID *) ((REAL *) pool->pathitem + pool->itemwords);
++  }
++  pool->pathitemsleft--;
++  return newitem;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  dummyinit()   Initialize the triangle that fills "outer space" and the   */
++/*                omnipresent shell edge.                                    */
++/*                                                                           */
++/*  The triangle that fills "outer space", called `dummytri', is pointed to  */
++/*  by every triangle and shell edge on a boundary (be it outer or inner) of */
++/*  the triangulation.  Also, `dummytri' points to one of the triangles on   */
++/*  the convex hull (until the holes and concavities are carved), making it  */
++/*  possible to find a starting triangle for point location.                 */
++/*                                                                           */
++/*  The omnipresent shell edge, `dummysh', is pointed to by every triangle   */
++/*  or shell edge that doesn't have a full complement of real shell edges    */
++/*  to point to.                                                             */
++/*                                                                           */
++/*****************************************************************************/
++
++void dummyinit(trianglewords, shellewords)
++int trianglewords;
++int shellewords;
++{
++  unsigned long alignptr;
++
++  /* `triwords' and `shwords' are used by the mesh manipulation primitives */
++  /*   to extract orientations of triangles and shell edges from pointers. */
++  triwords = trianglewords;       /* Initialize `triwords' once and for all. */
++  shwords = shellewords;           /* Initialize `shwords' once and for all. */
++
++  /* Set up `dummytri', the `triangle' that occupies "outer space". */
++  dummytribase = (triangle *) malloc(triwords * sizeof(triangle)
++                                     + triangles.alignbytes);
++  if (dummytribase == (triangle *) NULL) {
++    printf("Error:  Out of memory.\n");
++    exit(1);
++  }
++  /* Align `dummytri' on a `triangles.alignbytes'-byte boundary. */
++  alignptr = (unsigned long) dummytribase;
++  dummytri = (triangle *)
++    (alignptr + (unsigned long) triangles.alignbytes
++     - (alignptr % (unsigned long) triangles.alignbytes));
++  /* Initialize the three adjoining triangles to be "outer space".  These  */
++  /*   will eventually be changed by various bonding operations, but their */
++  /*   values don't really matter, as long as they can legally be          */
++  /*   dereferenced.                                                       */
++  dummytri[0] = (triangle) dummytri;
++  dummytri[1] = (triangle) dummytri;
++  dummytri[2] = (triangle) dummytri;
++  /* Three NULL vertex points. */
++  dummytri[3] = (triangle) NULL;
++  dummytri[4] = (triangle) NULL;
++  dummytri[5] = (triangle) NULL;
++
++  if (useshelles) {
++    /* Set up `dummysh', the omnipresent "shell edge" pointed to by any      */
++    /*   triangle side or shell edge end that isn't attached to a real shell */
++    /*   edge.                                                               */
++    dummyshbase = (shelle *) malloc(shwords * sizeof(shelle)
++                                    + shelles.alignbytes);
++    if (dummyshbase == (shelle *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++    /* Align `dummysh' on a `shelles.alignbytes'-byte boundary. */
++    alignptr = (unsigned long) dummyshbase;
++    dummysh = (shelle *)
++      (alignptr + (unsigned long) shelles.alignbytes
++       - (alignptr % (unsigned long) shelles.alignbytes));
++    /* Initialize the two adjoining shell edges to be the omnipresent shell */
++    /*   edge.  These will eventually be changed by various bonding         */
++    /*   operations, but their values don't really matter, as long as they  */
++    /*   can legally be dereferenced.                                       */
++    dummysh[0] = (shelle) dummysh;
++    dummysh[1] = (shelle) dummysh;
++    /* Two NULL vertex points. */
++    dummysh[2] = (shelle) NULL;
++    dummysh[3] = (shelle) NULL;
++    /* Initialize the two adjoining triangles to be "outer space". */
++    dummysh[4] = (shelle) dummytri;
++    dummysh[5] = (shelle) dummytri;
++    /* Set the boundary marker to zero. */
++    * (int *) (dummysh + 6) = 0;
++
++    /* Initialize the three adjoining shell edges of `dummytri' to be */
++    /*   the omnipresent shell edge.                                  */
++    dummytri[6] = (triangle) dummysh;
++    dummytri[7] = (triangle) dummysh;
++    dummytri[8] = (triangle) dummysh;
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  initializepointpool()   Calculate the size of the point data structure   */
++/*                          and initialize its memory pool.                  */
++/*                                                                           */
++/*  This routine also computes the `pointmarkindex' and `point2triindex'     */
++/*  indices used to find values within each point.                           */
++/*                                                                           */
++/*****************************************************************************/
++
++void initializepointpool()
++{
++  int pointsize;
++
++  /* The index within each point at which the boundary marker is found.  */
++  /*   Ensure the point marker is aligned to a sizeof(int)-byte address. */
++  pointmarkindex = ((mesh_dim + nextras) * sizeof(REAL) + sizeof(int) - 1)
++                 / sizeof(int);
++  pointsize = (pointmarkindex + 1) * sizeof(int);
++  if (poly) {
++    /* The index within each point at which a triangle pointer is found.   */
++    /*   Ensure the pointer is aligned to a sizeof(triangle)-byte address. */
++    point2triindex = (pointsize + sizeof(triangle) - 1) / sizeof(triangle);
++    pointsize = (point2triindex + 1) * sizeof(triangle);
++  }
++  /* Initialize the pool of points. */
++  poolinit(&points, pointsize, POINTPERBLOCK,
++           (sizeof(REAL) >= sizeof(triangle)) ? FLOATINGPOINT : POINTER, 0);
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  initializetrisegpools()   Calculate the sizes of the triangle and shell  */
++/*                            edge data structures and initialize their      */
++/*                            memory pools.                                  */
++/*                                                                           */
++/*  This routine also computes the `highorderindex', `elemattribindex', and  */
++/*  `areaboundindex' indices used to find values within each triangle.       */
++/*                                                                           */
++/*****************************************************************************/
++
++void initializetrisegpools()
++{
++  int trisize;
++
++  /* The index within each triangle at which the extra nodes (above three)  */
++  /*   associated with high order elements are found.  There are three      */
++  /*   pointers to other triangles, three pointers to corners, and possibly */
++  /*   three pointers to shell edges before the extra nodes.                */
++  highorderindex = 6 + (useshelles * 3);
++  /* The number of bytes occupied by a triangle. */
++  trisize = ((order + 1) * (order + 2) / 2 + (highorderindex - 3)) *
++            sizeof(triangle);
++  /* The index within each triangle at which its attributes are found, */
++  /*   where the index is measured in REALs.                           */
++  elemattribindex = (trisize + sizeof(REAL) - 1) / sizeof(REAL);
++  /* The index within each triangle at which the maximum area constraint  */
++  /*   is found, where the index is measured in REALs.  Note that if the  */
++  /*   `regionattrib' flag is set, an additional attribute will be added. */
++  areaboundindex = elemattribindex + eextras + regionattrib;
++  /* If triangle attributes or an area bound are needed, increase the number */
++  /*   of bytes occupied by a triangle.                                      */
++  if (vararea) {
++    trisize = (areaboundindex + 1) * sizeof(REAL);
++  } else if (eextras + regionattrib > 0) {
++    trisize = areaboundindex * sizeof(REAL);
++  }
++  /* If a Voronoi diagram or triangle neighbor graph is requested, make    */
++  /*   sure there's room to store an integer index in each triangle.  This */
++  /*   integer index can occupy the same space as the shell edges or       */
++  /*   attributes or area constraint or extra nodes.                       */
++  if ((voronoi || neighbors) &&
++      (trisize < 6 * sizeof(triangle) + sizeof(int))) {
++    trisize = 6 * sizeof(triangle) + sizeof(int);
++  }
++  /* Having determined the memory size of a triangle, initialize the pool. */
++  poolinit(&triangles, trisize, TRIPERBLOCK, POINTER, 4);
++
++  if (useshelles) {
++    /* Initialize the pool of shell edges. */
++    poolinit(&shelles, 6 * sizeof(triangle) + sizeof(int), SHELLEPERBLOCK,
++             POINTER, 4);
++
++    /* Initialize the "outer space" triangle and omnipresent shell edge. */
++    dummyinit(triangles.itemwords, shelles.itemwords);
++  } else {
++    /* Initialize the "outer space" triangle. */
++    dummyinit(triangles.itemwords, 0);
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  triangledealloc()   Deallocate space for a triangle, marking it dead.    */
++/*                                                                           */
++/*****************************************************************************/
++
++void triangledealloc(dyingtriangle)
++triangle *dyingtriangle;
++{
++  /* Set triangle's vertices to NULL.  This makes it possible to        */
++  /*   detect dead triangles when traversing the list of all triangles. */
++  dyingtriangle[3] = (triangle) NULL;
++  dyingtriangle[4] = (triangle) NULL;
++  dyingtriangle[5] = (triangle) NULL;
++  pooldealloc(&triangles, (VOID *) dyingtriangle);
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  triangletraverse()   Traverse the triangles, skipping dead ones.         */
++/*                                                                           */
++/*****************************************************************************/
++
++triangle *triangletraverse()
++{
++  triangle *newtriangle;
++
++  do {
++    newtriangle = (triangle *) traverse(&triangles);
++    if (newtriangle == (triangle *) NULL) {
++      return (triangle *) NULL;
++    }
++  } while (newtriangle[3] == (triangle) NULL);            /* Skip dead ones. */
++  return newtriangle;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  shelledealloc()   Deallocate space for a shell edge, marking it dead.    */
++/*                                                                           */
++/*****************************************************************************/
++
++void shelledealloc(dyingshelle)
++shelle *dyingshelle;
++{
++  /* Set shell edge's vertices to NULL.  This makes it possible to */
++  /*   detect dead shells when traversing the list of all shells.  */
++  dyingshelle[2] = (shelle) NULL;
++  dyingshelle[3] = (shelle) NULL;
++  pooldealloc(&shelles, (VOID *) dyingshelle);
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  shelletraverse()   Traverse the shell edges, skipping dead ones.         */
++/*                                                                           */
++/*****************************************************************************/
++
++shelle *shelletraverse()
++{
++  shelle *newshelle;
++
++  do {
++    newshelle = (shelle *) traverse(&shelles);
++    if (newshelle == (shelle *) NULL) {
++      return (shelle *) NULL;
++    }
++  } while (newshelle[2] == (shelle) NULL);                /* Skip dead ones. */
++  return newshelle;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  pointdealloc()   Deallocate space for a point, marking it dead.          */
++/*                                                                           */
++/*****************************************************************************/
++
++void pointdealloc(dyingpoint)
++point dyingpoint;
++{
++  /* Mark the point as dead.  This makes it possible to detect dead points */
++  /*   when traversing the list of all points.                             */
++  setpointmark(dyingpoint, DEADPOINT);
++  pooldealloc(&points, (VOID *) dyingpoint);
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  pointtraverse()   Traverse the points, skipping dead ones.               */
++/*                                                                           */
++/*****************************************************************************/
++
++point pointtraverse()
++{
++  point newpoint;
++
++  do {
++    newpoint = (point) traverse(&points);
++    if (newpoint == (point) NULL) {
++      return (point) NULL;
++    }
++  } while (pointmark(newpoint) == DEADPOINT);             /* Skip dead ones. */
++  return newpoint;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  badsegmentdealloc()   Deallocate space for a bad segment, marking it     */
++/*                        dead.                                              */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++void badsegmentdealloc(dyingseg)
++struct edge *dyingseg;
++{
++  /* Set segment's orientation to -1.  This makes it possible to      */
++  /*   detect dead segments when traversing the list of all segments. */
++  dyingseg->shorient = -1;
++  pooldealloc(&badsegments, (VOID *) dyingseg);
++}
++
++#endif /* not CDT_ONLY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  badsegmenttraverse()   Traverse the bad segments, skipping dead ones.    */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++struct edge *badsegmenttraverse()
++{
++  struct edge *newseg;
++
++  do {
++    newseg = (struct edge *) traverse(&badsegments);
++    if (newseg == (struct edge *) NULL) {
++      return (struct edge *) NULL;
++    }
++  } while (newseg->shorient == -1);                       /* Skip dead ones. */
++  return newseg;
++}
++
++#endif /* not CDT_ONLY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  getpoint()   Get a specific point, by number, from the list.             */
++/*                                                                           */
++/*  The first point is number 'firstnumber'.                                 */
++/*                                                                           */
++/*  Note that this takes O(n) time (with a small constant, if POINTPERBLOCK  */
++/*  is large).  I don't care to take the trouble to make it work in constant */
++/*  time.                                                                    */
++/*                                                                           */
++/*****************************************************************************/
++
++point getpoint(number)
++int number;
++{
++  VOID **getblock;
++  point foundpoint;
++  unsigned long alignptr;
++  int current;
++
++  getblock = points.firstblock;
++  current = firstnumber;
++  /* Find the right block. */
++  while (current + points.itemsperblock <= number) {
++    getblock = (VOID **) *getblock;
++    current += points.itemsperblock;
++  }
++  /* Now find the right point. */
++  alignptr = (unsigned long) (getblock + 1);
++  foundpoint = (point) (alignptr + (unsigned long) points.alignbytes
++                        - (alignptr % (unsigned long) points.alignbytes));
++  while (current < number) {
++    foundpoint += points.itemwords;
++    current++;
++  }
++  return foundpoint;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  triangledeinit()   Free all remaining allocated memory.                  */
++/*                                                                           */
++/*****************************************************************************/
++
++void triangledeinit()
++{
++  pooldeinit(&triangles);
++  free(dummytribase);
++  if (useshelles) {
++    pooldeinit(&shelles);
++    free(dummyshbase);
++  }
++  pooldeinit(&points);
++#ifndef CDT_ONLY
++  if (quality) {
++    pooldeinit(&badsegments);
++    if ((minangle > 0.0) || vararea || fixedarea) {
++      pooldeinit(&badtriangles);
++    }
++  }
++#endif /* not CDT_ONLY */
++}
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Memory management routines end here                       *********/
++
++/********* Constructors begin here                                   *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  maketriangle()   Create a new triangle with orientation zero.            */
++/*                                                                           */
++/*****************************************************************************/
++
++void maketriangle(newtriedge)
++struct triedge *newtriedge;
++{
++  int i;
++
++  newtriedge->tri = (triangle *) poolalloc(&triangles);
++  /* Initialize the three adjoining triangles to be "outer space". */
++  newtriedge->tri[0] = (triangle) dummytri;
++  newtriedge->tri[1] = (triangle) dummytri;
++  newtriedge->tri[2] = (triangle) dummytri;
++  /* Three NULL vertex points. */
++  newtriedge->tri[3] = (triangle) NULL;
++  newtriedge->tri[4] = (triangle) NULL;
++  newtriedge->tri[5] = (triangle) NULL;
++  /* Initialize the three adjoining shell edges to be the omnipresent */
++  /*   shell edge.                                                    */
++  if (useshelles) {
++    newtriedge->tri[6] = (triangle) dummysh;
++    newtriedge->tri[7] = (triangle) dummysh;
++    newtriedge->tri[8] = (triangle) dummysh;
++  }
++  for (i = 0; i < eextras; i++) {
++    setelemattribute(*newtriedge, i, 0.0);
++  }
++  if (vararea) {
++    setareabound(*newtriedge, -1.0);
++  }
++
++  newtriedge->orient = 0;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  makeshelle()   Create a new shell edge with orientation zero.            */
++/*                                                                           */
++/*****************************************************************************/
++
++void makeshelle(newedge)
++struct edge *newedge;
++{
++  newedge->sh = (shelle *) poolalloc(&shelles);
++  /* Initialize the two adjoining shell edges to be the omnipresent */
++  /*   shell edge.                                                  */
++  newedge->sh[0] = (shelle) dummysh;
++  newedge->sh[1] = (shelle) dummysh;
++  /* Two NULL vertex points. */
++  newedge->sh[2] = (shelle) NULL;
++  newedge->sh[3] = (shelle) NULL;
++  /* Initialize the two adjoining triangles to be "outer space". */
++  newedge->sh[4] = (shelle) dummytri;
++  newedge->sh[5] = (shelle) dummytri;
++  /* Set the boundary marker to zero. */
++  setmark(*newedge, 0);
++
++  newedge->shorient = 0;
++}
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Constructors end here                                     *********/
++
++/********* Determinant evaluation routines begin here                *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/* The adaptive exact arithmetic geometric predicates implemented herein are */
++/*   described in detail in my Technical Report CMU-CS-96-140.  The complete */
++/*   reference is given in the header.                                       */
++
++/* Which of the following two methods of finding the absolute values is      */
++/*   fastest is compiler-dependent.  A few compilers can inline and optimize */
++/*   the fabs() call; but most will incur the overhead of a function call,   */
++/*   which is disastrously slow.  A faster way on IEEE machines might be to  */
++/*   mask the appropriate bit, but that's difficult to do in C.              */
++
++#define Absolute(a)  ((a) >= 0.0 ? (a) : -(a))
++/* #define Absolute(a)  fabs(a) */
++
++/* Many of the operations are broken up into two pieces, a main part that    */
++/*   performs an approximate operation, and a "tail" that computes the       */
++/*   roundoff error of that operation.                                       */
++/*                                                                           */
++/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(),    */
++/*   Split(), and Two_Product() are all implemented as described in the      */
++/*   reference.  Each of these macros requires certain variables to be       */
++/*   defined in the calling routine.  The variables `bvirt', `c', `abig',    */
++/*   `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because   */
++/*   they store the result of an operation that may incur roundoff error.    */
++/*   The input parameter `x' (or the highest numbered `x_' parameter) must   */
++/*   also be declared `INEXACT'.                                             */
++
++#define Fast_Two_Sum_Tail(a, b, x, y) \
++  bvirt = x - a; \
++  y = b - bvirt
++
++#define Fast_Two_Sum(a, b, x, y) \
++  x = (REAL) (a + b); \
++  Fast_Two_Sum_Tail(a, b, x, y)
++
++#define Two_Sum_Tail(a, b, x, y) \
++  bvirt = (REAL) (x - a); \
++  avirt = x - bvirt; \
++  bround = b - bvirt; \
++  around = a - avirt; \
++  y = around + bround
++
++#define Two_Sum(a, b, x, y) \
++  x = (REAL) (a + b); \
++  Two_Sum_Tail(a, b, x, y)
++
++#define Two_Diff_Tail(a, b, x, y) \
++  bvirt = (REAL) (a - x); \
++  avirt = x + bvirt; \
++  bround = bvirt - b; \
++  around = a - avirt; \
++  y = around + bround
++
++#define Two_Diff(a, b, x, y) \
++  x = (REAL) (a - b); \
++  Two_Diff_Tail(a, b, x, y)
++
++#define Split(a, ahi, alo) \
++  c = (REAL) (splitter * a); \
++  abig = (REAL) (c - a); \
++  ahi = c - abig; \
++  alo = a - ahi
++
++#define Two_Product_Tail(a, b, x, y) \
++  Split(a, ahi, alo); \
++  Split(b, bhi, blo); \
++  err1 = x - (ahi * bhi); \
++  err2 = err1 - (alo * bhi); \
++  err3 = err2 - (ahi * blo); \
++  y = (alo * blo) - err3
++
++#define Two_Product(a, b, x, y) \
++  x = (REAL) (a * b); \
++  Two_Product_Tail(a, b, x, y)
++
++/* Two_Product_Presplit() is Two_Product() where one of the inputs has       */
++/*   already been split.  Avoids redundant splitting.                        */
++
++#define Two_Product_Presplit(a, b, bhi, blo, x, y) \
++  x = (REAL) (a * b); \
++  Split(a, ahi, alo); \
++  err1 = x - (ahi * bhi); \
++  err2 = err1 - (alo * bhi); \
++  err3 = err2 - (ahi * blo); \
++  y = (alo * blo) - err3
++
++/* Square() can be done more quickly than Two_Product().                     */
++
++#define Square_Tail(a, x, y) \
++  Split(a, ahi, alo); \
++  err1 = x - (ahi * ahi); \
++  err3 = err1 - ((ahi + ahi) * alo); \
++  y = (alo * alo) - err3
++
++#define Square(a, x, y) \
++  x = (REAL) (a * a); \
++  Square_Tail(a, x, y)
++
++/* Macros for summing expansions of various fixed lengths.  These are all    */
++/*   unrolled versions of Expansion_Sum().                                   */
++
++#define Two_One_Sum(a1, a0, b, x2, x1, x0) \
++  Two_Sum(a0, b , _i, x0); \
++  Two_Sum(a1, _i, x2, x1)
++
++#define Two_One_Diff(a1, a0, b, x2, x1, x0) \
++  Two_Diff(a0, b , _i, x0); \
++  Two_Sum( a1, _i, x2, x1)
++
++#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \
++  Two_One_Sum(a1, a0, b0, _j, _0, x0); \
++  Two_One_Sum(_j, _0, b1, x3, x2, x1)
++
++#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \
++  Two_One_Diff(a1, a0, b0, _j, _0, x0); \
++  Two_One_Diff(_j, _0, b1, x3, x2, x1)
++
++/*****************************************************************************/
++/*                                                                           */
++/*  exactinit()   Initialize the variables used for exact arithmetic.        */
++/*                                                                           */
++/*  `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in   */
++/*  floating-point arithmetic.  `epsilon' bounds the relative roundoff       */
++/*  error.  It is used for floating-point error analysis.                    */
++/*                                                                           */
++/*  `splitter' is used to split floating-point numbers into two half-        */
++/*  length significands for exact multiplication.                            */
++/*                                                                           */
++/*  I imagine that a highly optimizing compiler might be too smart for its   */
++/*  own good, and somehow cause this routine to fail, if it pretends that    */
++/*  floating-point arithmetic is too much like real arithmetic.              */
++/*                                                                           */
++/*  Don't change this routine unless you fully understand it.                */
++/*                                                                           */
++/*****************************************************************************/
++
++void exactinit()
++{
++  REAL half;
++  REAL check, lastcheck;
++  int every_other;
++
++  every_other = 1;
++  half = 0.5;
++  epsilon = 1.0;
++  splitter = 1.0;
++  check = 1.0;
++  /* Repeatedly divide `epsilon' by two until it is too small to add to      */
++  /*   one without causing roundoff.  (Also check if the sum is equal to     */
++  /*   the previous sum, for machines that round up instead of using exact   */
++  /*   rounding.  Not that these routines will work on such machines anyway. */
++  do {
++    lastcheck = check;
++    epsilon *= half;
++    if (every_other) {
++      splitter *= 2.0;
++    }
++    every_other = !every_other;
++    check = 1.0 + epsilon;
++  } while ((check != 1.0) && (check != lastcheck));
++  splitter += 1.0;
++  if (verbose > 1) {
++    printf("Floating point roundoff is of magnitude %.17g\n", epsilon);
++    printf("Floating point splitter is %.17g\n", splitter);
++  }
++  /* Error bounds for orientation and incircle tests. */
++  resulterrbound = (3.0 + 8.0 * epsilon) * epsilon;
++  ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon;
++  ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon;
++  ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon;
++  iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon;
++  iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon;
++  iccerrboundC = (44.0 + 576.0 * epsilon) * epsilon * epsilon;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  fast_expansion_sum_zeroelim()   Sum two expansions, eliminating zero     */
++/*                                  components from the output expansion.    */
++/*                                                                           */
++/*  Sets h = e + f.  See my Robust Predicates paper for details.             */
++/*                                                                           */
++/*  If round-to-even is used (as with IEEE 754), maintains the strongly      */
++/*  nonoverlapping property.  (That is, if e is strongly nonoverlapping, h   */
++/*  will be also.)  Does NOT maintain the nonoverlapping or nonadjacent      */
++/*  properties.                                                              */
++/*                                                                           */
++/*****************************************************************************/
++
++int fast_expansion_sum_zeroelim(elen, e, flen, f, h)  /* h cannot be e or f. */
++int elen;
++REAL *e;
++int flen;
++REAL *f;
++REAL *h;
++{
++  REAL Q;
++  INEXACT REAL Qnew;
++  INEXACT REAL hh;
++  INEXACT REAL bvirt;
++  REAL avirt, bround, around;
++  int eindex, findex, hindex;
++  REAL enow, fnow;
++
++  enow = e[0];
++  fnow = f[0];
++  eindex = findex = 0;
++  if ((fnow > enow) == (fnow > -enow)) {
++    Q = enow;
++    enow = e[++eindex];
++  } else {
++    Q = fnow;
++    fnow = f[++findex];
++  }
++  hindex = 0;
++  if ((eindex < elen) && (findex < flen)) {
++    if ((fnow > enow) == (fnow > -enow)) {
++      Fast_Two_Sum(enow, Q, Qnew, hh);
++      enow = e[++eindex];
++    } else {
++      Fast_Two_Sum(fnow, Q, Qnew, hh);
++      fnow = f[++findex];
++    }
++    Q = Qnew;
++    if (hh != 0.0) {
++      h[hindex++] = hh;
++    }
++    while ((eindex < elen) && (findex < flen)) {
++      if ((fnow > enow) == (fnow > -enow)) {
++        Two_Sum(Q, enow, Qnew, hh);
++        enow = e[++eindex];
++      } else {
++        Two_Sum(Q, fnow, Qnew, hh);
++        fnow = f[++findex];
++      }
++      Q = Qnew;
++      if (hh != 0.0) {
++        h[hindex++] = hh;
++      }
++    }
++  }
++  while (eindex < elen) {
++    Two_Sum(Q, enow, Qnew, hh);
++    enow = e[++eindex];
++    Q = Qnew;
++    if (hh != 0.0) {
++      h[hindex++] = hh;
++    }
++  }
++  while (findex < flen) {
++    Two_Sum(Q, fnow, Qnew, hh);
++    fnow = f[++findex];
++    Q = Qnew;
++    if (hh != 0.0) {
++      h[hindex++] = hh;
++    }
++  }
++  if ((Q != 0.0) || (hindex == 0)) {
++    h[hindex++] = Q;
++  }
++  return hindex;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  scale_expansion_zeroelim()   Multiply an expansion by a scalar,          */
++/*                               eliminating zero components from the        */
++/*                               output expansion.                           */
++/*                                                                           */
++/*  Sets h = be.  See my Robust Predicates paper for details.                */
++/*                                                                           */
++/*  Maintains the nonoverlapping property.  If round-to-even is used (as     */
++/*  with IEEE 754), maintains the strongly nonoverlapping and nonadjacent    */
++/*  properties as well.  (That is, if e has one of these properties, so      */
++/*  will h.)                                                                 */
++/*                                                                           */
++/*****************************************************************************/
++
++int scale_expansion_zeroelim(elen, e, b, h)   /* e and h cannot be the same. */
++int elen;
++REAL *e;
++REAL b;
++REAL *h;
++{
++  INEXACT REAL Q, sum;
++  REAL hh;
++  INEXACT REAL product1;
++  REAL product0;
++  int eindex, hindex;
++  REAL enow;
++  INEXACT REAL bvirt;
++  REAL avirt, bround, around;
++  INEXACT REAL c;
++  INEXACT REAL abig;
++  REAL ahi, alo, bhi, blo;
++  REAL err1, err2, err3;
++
++  Split(b, bhi, blo);
++  Two_Product_Presplit(e[0], b, bhi, blo, Q, hh);
++  hindex = 0;
++  if (hh != 0) {
++    h[hindex++] = hh;
++  }
++  for (eindex = 1; eindex < elen; eindex++) {
++    enow = e[eindex];
++    Two_Product_Presplit(enow, b, bhi, blo, product1, product0);
++    Two_Sum(Q, product0, sum, hh);
++    if (hh != 0) {
++      h[hindex++] = hh;
++    }
++    Fast_Two_Sum(product1, sum, Q, hh);
++    if (hh != 0) {
++      h[hindex++] = hh;
++    }
++  }
++  if ((Q != 0.0) || (hindex == 0)) {
++    h[hindex++] = Q;
++  }
++  return hindex;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  estimate()   Produce a one-word estimate of an expansion's value.        */
++/*                                                                           */
++/*  See my Robust Predicates paper for details.                              */
++/*                                                                           */
++/*****************************************************************************/
++
++REAL estimate(elen, e)
++int elen;
++REAL *e;
++{
++  REAL Q;
++  int eindex;
++
++  Q = e[0];
++  for (eindex = 1; eindex < elen; eindex++) {
++    Q += e[eindex];
++  }
++  return Q;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  counterclockwise()   Return a positive value if the points pa, pb, and   */
++/*                       pc occur in counterclockwise order; a negative      */
++/*                       value if they occur in clockwise order; and zero    */
++/*                       if they are collinear.  The result is also a rough  */
++/*                       approximation of twice the signed area of the       */
++/*                       triangle defined by the three points.               */
++/*                                                                           */
++/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
++/*  result returned is the determinant of a matrix.  This determinant is     */
++/*  computed adaptively, in the sense that exact arithmetic is used only to  */
++/*  the degree it is needed to ensure that the returned value has the        */
++/*  correct sign.  Hence, this function is usually quite fast, but will run  */
++/*  more slowly when the input points are collinear or nearly so.            */
++/*                                                                           */
++/*  See my Robust Predicates paper for details.                              */
++/*                                                                           */
++/*****************************************************************************/
++
++REAL counterclockwiseadapt(pa, pb, pc, detsum)
++point pa;
++point pb;
++point pc;
++REAL detsum;
++{
++  INEXACT REAL acx, acy, bcx, bcy;
++  REAL acxtail, acytail, bcxtail, bcytail;
++  INEXACT REAL detleft, detright;
++  REAL detlefttail, detrighttail;
++  REAL det, errbound;
++  REAL B[4], C1[8], C2[12], D[16];
++  INEXACT REAL B3;
++  int C1length, C2length, Dlength;
++  REAL u[4];
++  INEXACT REAL u3;
++  INEXACT REAL s1, t1;
++  REAL s0, t0;
++
++  INEXACT REAL bvirt;
++  REAL avirt, bround, around;
++  INEXACT REAL c;
++  INEXACT REAL abig;
++  REAL ahi, alo, bhi, blo;
++  REAL err1, err2, err3;
++  INEXACT REAL _i, _j;
++  REAL _0;
++
++  acx = (REAL) (pa[0] - pc[0]);
++  bcx = (REAL) (pb[0] - pc[0]);
++  acy = (REAL) (pa[1] - pc[1]);
++  bcy = (REAL) (pb[1] - pc[1]);
++
++  Two_Product(acx, bcy, detleft, detlefttail);
++  Two_Product(acy, bcx, detright, detrighttail);
++
++  Two_Two_Diff(detleft, detlefttail, detright, detrighttail,
++               B3, B[2], B[1], B[0]);
++  B[3] = B3;
++
++  det = estimate(4, B);
++  errbound = ccwerrboundB * detsum;
++  if ((det >= errbound) || (-det >= errbound)) {
++    return det;
++  }
++
++  Two_Diff_Tail(pa[0], pc[0], acx, acxtail);
++  Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail);
++  Two_Diff_Tail(pa[1], pc[1], acy, acytail);
++  Two_Diff_Tail(pb[1], pc[1], bcy, bcytail);
++
++  if ((acxtail == 0.0) && (acytail == 0.0)
++      && (bcxtail == 0.0) && (bcytail == 0.0)) {
++    return det;
++  }
++
++  errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det);
++  det += (acx * bcytail + bcy * acxtail)
++       - (acy * bcxtail + bcx * acytail);
++  if ((det >= errbound) || (-det >= errbound)) {
++    return det;
++  }
++
++  Two_Product(acxtail, bcy, s1, s0);
++  Two_Product(acytail, bcx, t1, t0);
++  Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
++  u[3] = u3;
++  C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1);
++
++  Two_Product(acx, bcytail, s1, s0);
++  Two_Product(acy, bcxtail, t1, t0);
++  Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
++  u[3] = u3;
++  C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2);
++
++  Two_Product(acxtail, bcytail, s1, s0);
++  Two_Product(acytail, bcxtail, t1, t0);
++  Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
++  u[3] = u3;
++  Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D);
++
++  return(D[Dlength - 1]);
++}
++
++REAL counterclockwise(pa, pb, pc)
++point pa;
++point pb;
++point pc;
++{
++  REAL detleft, detright, det;
++  REAL detsum, errbound;
++
++  counterclockcount++;
++
++  detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]);
++  detright = (pa[1] - pc[1]) * (pb[0] - pc[0]);
++  det = detleft - detright;
++
++  if (noexact) {
++    return det;
++  }
++
++  if (detleft > 0.0) {
++    if (detright <= 0.0) {
++      return det;
++    } else {
++      detsum = detleft + detright;
++    }
++  } else if (detleft < 0.0) {
++    if (detright >= 0.0) {
++      return det;
++    } else {
++      detsum = -detleft - detright;
++    }
++  } else {
++    return det;
++  }
++
++  errbound = ccwerrboundA * detsum;
++  if ((det >= errbound) || (-det >= errbound)) {
++    return det;
++  }
++
++  return counterclockwiseadapt(pa, pb, pc, detsum);
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  incircle()   Return a positive value if the point pd lies inside the     */
++/*               circle passing through pa, pb, and pc; a negative value if  */
++/*               it lies outside; and zero if the four points are cocircular.*/
++/*               The points pa, pb, and pc must be in counterclockwise       */
++/*               order, or the sign of the result will be reversed.          */
++/*                                                                           */
++/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
++/*  result returned is the determinant of a matrix.  This determinant is     */
++/*  computed adaptively, in the sense that exact arithmetic is used only to  */
++/*  the degree it is needed to ensure that the returned value has the        */
++/*  correct sign.  Hence, this function is usually quite fast, but will run  */
++/*  more slowly when the input points are cocircular or nearly so.           */
++/*                                                                           */
++/*  See my Robust Predicates paper for details.                              */
++/*                                                                           */
++/*****************************************************************************/
++
++REAL incircleadapt(pa, pb, pc, pd, permanent)
++point pa;
++point pb;
++point pc;
++point pd;
++REAL permanent;
++{
++  INEXACT REAL adx, bdx, cdx, ady, bdy, cdy;
++  REAL det, errbound;
++
++  INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
++  REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
++  REAL bc[4], ca[4], ab[4];
++  INEXACT REAL bc3, ca3, ab3;
++  REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32];
++  int axbclen, axxbclen, aybclen, ayybclen, alen;
++  REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32];
++  int bxcalen, bxxcalen, bycalen, byycalen, blen;
++  REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32];
++  int cxablen, cxxablen, cyablen, cyyablen, clen;
++  REAL abdet[64];
++  int ablen;
++  REAL fin1[1152], fin2[1152];
++  REAL *finnow, *finother, *finswap;
++  int finlength;
++
++  REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail;
++  INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1;
++  REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0;
++  REAL aa[4], bb[4], cc[4];
++  INEXACT REAL aa3, bb3, cc3;
++  INEXACT REAL ti1, tj1;
++  REAL ti0, tj0;
++  REAL u[4], v[4];
++  INEXACT REAL u3, v3;
++  REAL temp8[8], temp16a[16], temp16b[16], temp16c[16];
++  REAL temp32a[32], temp32b[32], temp48[48], temp64[64];
++  int temp8len, temp16alen, temp16blen, temp16clen;
++  int temp32alen, temp32blen, temp48len, temp64len;
++  REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8];
++  int axtbblen, axtcclen, aytbblen, aytcclen;
++  REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8];
++  int bxtaalen, bxtcclen, bytaalen, bytcclen;
++  REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8];
++  int cxtaalen, cxtbblen, cytaalen, cytbblen;
++  REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8];
++  int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen;
++  REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16];
++  int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen;
++  REAL axtbctt[8], aytbctt[8], bxtcatt[8];
++  REAL bytcatt[8], cxtabtt[8], cytabtt[8];
++  int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen;
++  REAL abt[8], bct[8], cat[8];
++  int abtlen, bctlen, catlen;
++  REAL abtt[4], bctt[4], catt[4];
++  int abttlen, bcttlen, cattlen;
++  INEXACT REAL abtt3, bctt3, catt3;
++  REAL negate;
++
++  INEXACT REAL bvirt;
++  REAL avirt, bround, around;
++  INEXACT REAL c;
++  INEXACT REAL abig;
++  REAL ahi, alo, bhi, blo;
++  REAL err1, err2, err3;
++  INEXACT REAL _i, _j;
++  REAL _0;
++
++  adx = (REAL) (pa[0] - pd[0]);
++  bdx = (REAL) (pb[0] - pd[0]);
++  cdx = (REAL) (pc[0] - pd[0]);
++  ady = (REAL) (pa[1] - pd[1]);
++  bdy = (REAL) (pb[1] - pd[1]);
++  cdy = (REAL) (pc[1] - pd[1]);
++
++  Two_Product(bdx, cdy, bdxcdy1, bdxcdy0);
++  Two_Product(cdx, bdy, cdxbdy1, cdxbdy0);
++  Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
++  bc[3] = bc3;
++  axbclen = scale_expansion_zeroelim(4, bc, adx, axbc);
++  axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc);
++  aybclen = scale_expansion_zeroelim(4, bc, ady, aybc);
++  ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc);
++  alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet);
++
++  Two_Product(cdx, ady, cdxady1, cdxady0);
++  Two_Product(adx, cdy, adxcdy1, adxcdy0);
++  Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
++  ca[3] = ca3;
++  bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca);
++  bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca);
++  bycalen = scale_expansion_zeroelim(4, ca, bdy, byca);
++  byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca);
++  blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet);
++
++  Two_Product(adx, bdy, adxbdy1, adxbdy0);
++  Two_Product(bdx, ady, bdxady1, bdxady0);
++  Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
++  ab[3] = ab3;
++  cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab);
++  cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab);
++  cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab);
++  cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab);
++  clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet);
++
++  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
++  finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1);
++
++  det = estimate(finlength, fin1);
++  errbound = iccerrboundB * permanent;
++  if ((det >= errbound) || (-det >= errbound)) {
++    return det;
++  }
++
++  Two_Diff_Tail(pa[0], pd[0], adx, adxtail);
++  Two_Diff_Tail(pa[1], pd[1], ady, adytail);
++  Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail);
++  Two_Diff_Tail(pb[1], pd[1], bdy, bdytail);
++  Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail);
++  Two_Diff_Tail(pc[1], pd[1], cdy, cdytail);
++  if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0)
++      && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) {
++    return det;
++  }
++
++  errbound = iccerrboundC * permanent + resulterrbound * Absolute(det);
++  det += ((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail)
++                                     - (bdy * cdxtail + cdx * bdytail))
++          + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx))
++       + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail)
++                                     - (cdy * adxtail + adx * cdytail))
++          + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx))
++       + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail)
++                                     - (ady * bdxtail + bdx * adytail))
++          + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx));
++  if ((det >= errbound) || (-det >= errbound)) {
++    return det;
++  }
++
++  finnow = fin1;
++  finother = fin2;
++
++  if ((bdxtail != 0.0) || (bdytail != 0.0)
++      || (cdxtail != 0.0) || (cdytail != 0.0)) {
++    Square(adx, adxadx1, adxadx0);
++    Square(ady, adyady1, adyady0);
++    Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]);
++    aa[3] = aa3;
++  }
++  if ((cdxtail != 0.0) || (cdytail != 0.0)
++      || (adxtail != 0.0) || (adytail != 0.0)) {
++    Square(bdx, bdxbdx1, bdxbdx0);
++    Square(bdy, bdybdy1, bdybdy0);
++    Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]);
++    bb[3] = bb3;
++  }
++  if ((adxtail != 0.0) || (adytail != 0.0)
++      || (bdxtail != 0.0) || (bdytail != 0.0)) {
++    Square(cdx, cdxcdx1, cdxcdx0);
++    Square(cdy, cdycdy1, cdycdy0);
++    Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]);
++    cc[3] = cc3;
++  }
++
++  if (adxtail != 0.0) {
++    axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc);
++    temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx,
++                                          temp16a);
++
++    axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc);
++    temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b);
++
++    axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb);
++    temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c);
++
++    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                            temp16blen, temp16b, temp32a);
++    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
++                                            temp32alen, temp32a, temp48);
++    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
++                                            temp48, finother);
++    finswap = finnow; finnow = finother; finother = finswap;
++  }
++  if (adytail != 0.0) {
++    aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc);
++    temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady,
++                                          temp16a);
++
++    aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb);
++    temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b);
++
++    aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc);
++    temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c);
++
++    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                            temp16blen, temp16b, temp32a);
++    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
++                                            temp32alen, temp32a, temp48);
++    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
++                                            temp48, finother);
++    finswap = finnow; finnow = finother; finother = finswap;
++  }
++  if (bdxtail != 0.0) {
++    bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca);
++    temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx,
++                                          temp16a);
++
++    bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa);
++    temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b);
++
++    bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc);
++    temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c);
++
++    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                            temp16blen, temp16b, temp32a);
++    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
++                                            temp32alen, temp32a, temp48);
++    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
++                                            temp48, finother);
++    finswap = finnow; finnow = finother; finother = finswap;
++  }
++  if (bdytail != 0.0) {
++    bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca);
++    temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy,
++                                          temp16a);
++
++    bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc);
++    temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b);
++
++    bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa);
++    temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c);
++
++    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                            temp16blen, temp16b, temp32a);
++    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
++                                            temp32alen, temp32a, temp48);
++    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
++                                            temp48, finother);
++    finswap = finnow; finnow = finother; finother = finswap;
++  }
++  if (cdxtail != 0.0) {
++    cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab);
++    temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx,
++                                          temp16a);
++
++    cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb);
++    temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b);
++
++    cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa);
++    temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c);
++
++    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                            temp16blen, temp16b, temp32a);
++    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
++                                            temp32alen, temp32a, temp48);
++    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
++                                            temp48, finother);
++    finswap = finnow; finnow = finother; finother = finswap;
++  }
++  if (cdytail != 0.0) {
++    cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab);
++    temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy,
++                                          temp16a);
++
++    cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa);
++    temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b);
++
++    cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb);
++    temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c);
++
++    temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                            temp16blen, temp16b, temp32a);
++    temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c,
++                                            temp32alen, temp32a, temp48);
++    finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
++                                            temp48, finother);
++    finswap = finnow; finnow = finother; finother = finswap;
++  }
++
++  if ((adxtail != 0.0) || (adytail != 0.0)) {
++    if ((bdxtail != 0.0) || (bdytail != 0.0)
++        || (cdxtail != 0.0) || (cdytail != 0.0)) {
++      Two_Product(bdxtail, cdy, ti1, ti0);
++      Two_Product(bdx, cdytail, tj1, tj0);
++      Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
++      u[3] = u3;
++      negate = -bdy;
++      Two_Product(cdxtail, negate, ti1, ti0);
++      negate = -bdytail;
++      Two_Product(cdx, negate, tj1, tj0);
++      Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
++      v[3] = v3;
++      bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct);
++
++      Two_Product(bdxtail, cdytail, ti1, ti0);
++      Two_Product(cdxtail, bdytail, tj1, tj0);
++      Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]);
++      bctt[3] = bctt3;
++      bcttlen = 4;
++    } else {
++      bct[0] = 0.0;
++      bctlen = 1;
++      bctt[0] = 0.0;
++      bcttlen = 1;
++    }
++
++    if (adxtail != 0.0) {
++      temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a);
++      axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct);
++      temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx,
++                                            temp32a);
++      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                              temp32alen, temp32a, temp48);
++      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
++                                              temp48, finother);
++      finswap = finnow; finnow = finother; finother = finswap;
++      if (bdytail != 0.0) {
++        temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8);
++        temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail,
++                                              temp16a);
++        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
++                                                temp16a, finother);
++        finswap = finnow; finnow = finother; finother = finswap;
++      }
++      if (cdytail != 0.0) {
++        temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8);
++        temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail,
++                                              temp16a);
++        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
++                                                temp16a, finother);
++        finswap = finnow; finnow = finother; finother = finswap;
++      }
++
++      temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail,
++                                            temp32a);
++      axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt);
++      temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx,
++                                            temp16a);
++      temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail,
++                                            temp16b);
++      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                              temp16blen, temp16b, temp32b);
++      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
++                                              temp32blen, temp32b, temp64);
++      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
++                                              temp64, finother);
++      finswap = finnow; finnow = finother; finother = finswap;
++    }
++    if (adytail != 0.0) {
++      temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a);
++      aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct);
++      temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady,
++                                            temp32a);
++      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                              temp32alen, temp32a, temp48);
++      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
++                                              temp48, finother);
++      finswap = finnow; finnow = finother; finother = finswap;
++
++
++      temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail,
++                                            temp32a);
++      aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt);
++      temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady,
++                                            temp16a);
++      temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail,
++                                            temp16b);
++      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                              temp16blen, temp16b, temp32b);
++      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
++                                              temp32blen, temp32b, temp64);
++      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
++                                              temp64, finother);
++      finswap = finnow; finnow = finother; finother = finswap;
++    }
++  }
++  if ((bdxtail != 0.0) || (bdytail != 0.0)) {
++    if ((cdxtail != 0.0) || (cdytail != 0.0)
++        || (adxtail != 0.0) || (adytail != 0.0)) {
++      Two_Product(cdxtail, ady, ti1, ti0);
++      Two_Product(cdx, adytail, tj1, tj0);
++      Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
++      u[3] = u3;
++      negate = -cdy;
++      Two_Product(adxtail, negate, ti1, ti0);
++      negate = -cdytail;
++      Two_Product(adx, negate, tj1, tj0);
++      Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
++      v[3] = v3;
++      catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat);
++
++      Two_Product(cdxtail, adytail, ti1, ti0);
++      Two_Product(adxtail, cdytail, tj1, tj0);
++      Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]);
++      catt[3] = catt3;
++      cattlen = 4;
++    } else {
++      cat[0] = 0.0;
++      catlen = 1;
++      catt[0] = 0.0;
++      cattlen = 1;
++    }
++
++    if (bdxtail != 0.0) {
++      temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a);
++      bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat);
++      temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx,
++                                            temp32a);
++      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                              temp32alen, temp32a, temp48);
++      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
++                                              temp48, finother);
++      finswap = finnow; finnow = finother; finother = finswap;
++      if (cdytail != 0.0) {
++        temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8);
++        temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail,
++                                              temp16a);
++        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
++                                                temp16a, finother);
++        finswap = finnow; finnow = finother; finother = finswap;
++      }
++      if (adytail != 0.0) {
++        temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8);
++        temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail,
++                                              temp16a);
++        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
++                                                temp16a, finother);
++        finswap = finnow; finnow = finother; finother = finswap;
++      }
++
++      temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail,
++                                            temp32a);
++      bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt);
++      temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx,
++                                            temp16a);
++      temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail,
++                                            temp16b);
++      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                              temp16blen, temp16b, temp32b);
++      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
++                                              temp32blen, temp32b, temp64);
++      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
++                                              temp64, finother);
++      finswap = finnow; finnow = finother; finother = finswap;
++    }
++    if (bdytail != 0.0) {
++      temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a);
++      bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat);
++      temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy,
++                                            temp32a);
++      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                              temp32alen, temp32a, temp48);
++      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
++                                              temp48, finother);
++      finswap = finnow; finnow = finother; finother = finswap;
++
++
++      temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail,
++                                            temp32a);
++      bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt);
++      temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy,
++                                            temp16a);
++      temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail,
++                                            temp16b);
++      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                              temp16blen, temp16b, temp32b);
++      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
++                                              temp32blen, temp32b, temp64);
++      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
++                                              temp64, finother);
++      finswap = finnow; finnow = finother; finother = finswap;
++    }
++  }
++  if ((cdxtail != 0.0) || (cdytail != 0.0)) {
++    if ((adxtail != 0.0) || (adytail != 0.0)
++        || (bdxtail != 0.0) || (bdytail != 0.0)) {
++      Two_Product(adxtail, bdy, ti1, ti0);
++      Two_Product(adx, bdytail, tj1, tj0);
++      Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
++      u[3] = u3;
++      negate = -ady;
++      Two_Product(bdxtail, negate, ti1, ti0);
++      negate = -adytail;
++      Two_Product(bdx, negate, tj1, tj0);
++      Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
++      v[3] = v3;
++      abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt);
++
++      Two_Product(adxtail, bdytail, ti1, ti0);
++      Two_Product(bdxtail, adytail, tj1, tj0);
++      Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]);
++      abtt[3] = abtt3;
++      abttlen = 4;
++    } else {
++      abt[0] = 0.0;
++      abtlen = 1;
++      abtt[0] = 0.0;
++      abttlen = 1;
++    }
++
++    if (cdxtail != 0.0) {
++      temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a);
++      cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt);
++      temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx,
++                                            temp32a);
++      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                              temp32alen, temp32a, temp48);
++      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
++                                              temp48, finother);
++      finswap = finnow; finnow = finother; finother = finswap;
++      if (adytail != 0.0) {
++        temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8);
++        temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail,
++                                              temp16a);
++        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
++                                                temp16a, finother);
++        finswap = finnow; finnow = finother; finother = finswap;
++      }
++      if (bdytail != 0.0) {
++        temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8);
++        temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail,
++                                              temp16a);
++        finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen,
++                                                temp16a, finother);
++        finswap = finnow; finnow = finother; finother = finswap;
++      }
++
++      temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail,
++                                            temp32a);
++      cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt);
++      temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx,
++                                            temp16a);
++      temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail,
++                                            temp16b);
++      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                              temp16blen, temp16b, temp32b);
++      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
++                                              temp32blen, temp32b, temp64);
++      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
++                                              temp64, finother);
++      finswap = finnow; finnow = finother; finother = finswap;
++    }
++    if (cdytail != 0.0) {
++      temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a);
++      cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt);
++      temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy,
++                                            temp32a);
++      temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                              temp32alen, temp32a, temp48);
++      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len,
++                                              temp48, finother);
++      finswap = finnow; finnow = finother; finother = finswap;
++
++
++      temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail,
++                                            temp32a);
++      cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt);
++      temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy,
++                                            temp16a);
++      temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail,
++                                            temp16b);
++      temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a,
++                                              temp16blen, temp16b, temp32b);
++      temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a,
++                                              temp32blen, temp32b, temp64);
++      finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len,
++                                              temp64, finother);
++      finswap = finnow; finnow = finother; finother = finswap;
++    }
++  }
++
++  return finnow[finlength - 1];
++}
++
++REAL incircle(pa, pb, pc, pd)
++point pa;
++point pb;
++point pc;
++point pd;
++{
++  REAL adx, bdx, cdx, ady, bdy, cdy;
++  REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
++  REAL alift, blift, clift;
++  REAL det;
++  REAL permanent, errbound;
++
++  incirclecount++;
++
++  adx = pa[0] - pd[0];
++  bdx = pb[0] - pd[0];
++  cdx = pc[0] - pd[0];
++  ady = pa[1] - pd[1];
++  bdy = pb[1] - pd[1];
++  cdy = pc[1] - pd[1];
++
++  bdxcdy = bdx * cdy;
++  cdxbdy = cdx * bdy;
++  alift = adx * adx + ady * ady;
++
++  cdxady = cdx * ady;
++  adxcdy = adx * cdy;
++  blift = bdx * bdx + bdy * bdy;
++
++  adxbdy = adx * bdy;
++  bdxady = bdx * ady;
++  clift = cdx * cdx + cdy * cdy;
++
++  det = alift * (bdxcdy - cdxbdy)
++      + blift * (cdxady - adxcdy)
++      + clift * (adxbdy - bdxady);
++
++  if (noexact) {
++    return det;
++  }
++
++  permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift
++            + (Absolute(cdxady) + Absolute(adxcdy)) * blift
++            + (Absolute(adxbdy) + Absolute(bdxady)) * clift;
++  errbound = iccerrboundA * permanent;
++  if ((det > errbound) || (-det > errbound)) {
++    return det;
++  }
++
++  return incircleadapt(pa, pb, pc, pd, permanent);
++}
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Determinant evaluation routines end here                  *********/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  triangleinit()   Initialize some variables.                              */
++/*                                                                           */
++/*****************************************************************************/
++
++void triangleinit()
++{
++  points.maxitems = triangles.maxitems = shelles.maxitems = viri.maxitems =
++    badsegments.maxitems = badtriangles.maxitems = splaynodes.maxitems = 0l;
++  points.itembytes = triangles.itembytes = shelles.itembytes = viri.itembytes =
++    badsegments.itembytes = badtriangles.itembytes = splaynodes.itembytes = 0;
++  recenttri.tri = (triangle *) NULL;    /* No triangle has been visited yet. */
++  samples = 1;            /* Point location should take at least one sample. */
++  checksegments = 0;      /* There are no segments in the triangulation yet. */
++  incirclecount = counterclockcount = hyperbolacount = 0;
++  circumcentercount = circletopcount = 0;
++  randomseed = 1;
++
++  exactinit();                     /* Initialize exact arithmetic constants. */
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  randomnation()   Generate a random number between 0 and `choices' - 1.   */
++/*                                                                           */
++/*  This is a simple linear congruential random number generator.  Hence, it */
++/*  is a bad random number generator, but good enough for most randomized    */
++/*  geometric algorithms.                                                    */
++/*                                                                           */
++/*****************************************************************************/
++
++unsigned long randomnation(choices)
++unsigned int choices;
++{
++  randomseed = (randomseed * 1366l + 150889l) % 714025l;
++  return randomseed / (714025l / choices + 1);
++}
++
++/********* Mesh quality testing routines begin here                  *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  checkmesh()   Test the mesh for topological consistency.                 */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef REDUCED
++
++void checkmesh()
++{
++  struct triedge triangleloop;
++  struct triedge oppotri, oppooppotri;
++  point triorg, tridest, triapex;
++  point oppoorg, oppodest;
++  int horrors;
++  int saveexact;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++
++  /* Temporarily turn on exact arithmetic if it's off. */
++  saveexact = noexact;
++  noexact = 0;
++  if (!quiet) {
++    printf("  Checking consistency of mesh...\n");
++  }
++  horrors = 0;
++  /* Run through the list of triangles, checking each one. */
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  while (triangleloop.tri != (triangle *) NULL) {
++    /* Check all three edges of the triangle. */
++    for (triangleloop.orient = 0; triangleloop.orient < 3;
++         triangleloop.orient++) {
++      org(triangleloop, triorg);
++      dest(triangleloop, tridest);
++      if (triangleloop.orient == 0) {       /* Only test for inversion once. */
++        /* Test if the triangle is flat or inverted. */
++        apex(triangleloop, triapex);
++        if (counterclockwise(triorg, tridest, triapex) <= 0.0) {
++          printf("  !! !! Inverted ");
++          printtriangle(&triangleloop);
++          horrors++;
++        }
++      }
++      /* Find the neighboring triangle on this edge. */
++      sym(triangleloop, oppotri);
++      if (oppotri.tri != dummytri) {
++        /* Check that the triangle's neighbor knows it's a neighbor. */
++        sym(oppotri, oppooppotri);
++        if ((triangleloop.tri != oppooppotri.tri)
++            || (triangleloop.orient != oppooppotri.orient)) {
++          printf("  !! !! Asymmetric triangle-triangle bond:\n");
++          if (triangleloop.tri == oppooppotri.tri) {
++            printf("   (Right triangle, wrong orientation)\n");
++          }
++          printf("    First ");
++          printtriangle(&triangleloop);
++          printf("    Second (nonreciprocating) ");
++          printtriangle(&oppotri);
++          horrors++;
++        }
++        /* Check that both triangles agree on the identities */
++        /*   of their shared vertices.                       */
++        org(oppotri, oppoorg);
++        dest(oppotri, oppodest);
++        if ((triorg != oppodest) || (tridest != oppoorg)) {
++          printf("  !! !! Mismatched edge coordinates between two triangles:\n"
++                 );
++          printf("    First mismatched ");
++          printtriangle(&triangleloop);
++          printf("    Second mismatched ");
++          printtriangle(&oppotri);
++          horrors++;
++        }
++      }
++    }
++    triangleloop.tri = triangletraverse();
++  }
++  if (horrors == 0) {
++    if (!quiet) {
++      printf("  In my studied opinion, the mesh appears to be consistent.\n");
++    }
++  } else if (horrors == 1) {
++    printf("  !! !! !! !! Precisely one festering wound discovered.\n");
++  } else {
++    printf("  !! !! !! !! %d abominations witnessed.\n", horrors);
++  }
++  /* Restore the status of exact arithmetic. */
++  noexact = saveexact;
++}
++
++#endif /* not REDUCED */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  checkdelaunay()   Ensure that the mesh is (constrained) Delaunay.        */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef REDUCED
++
++void checkdelaunay()
++{
++  struct triedge triangleloop;
++  struct triedge oppotri;
++  struct edge opposhelle;
++  point triorg, tridest, triapex;
++  point oppoapex;
++  int shouldbedelaunay;
++  int horrors;
++  int saveexact;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  /* Temporarily turn on exact arithmetic if it's off. */
++  saveexact = noexact;
++  noexact = 0;
++  if (!quiet) {
++    printf("  Checking Delaunay property of mesh...\n");
++  }
++  horrors = 0;
++  /* Run through the list of triangles, checking each one. */
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  while (triangleloop.tri != (triangle *) NULL) {
++    /* Check all three edges of the triangle. */
++    for (triangleloop.orient = 0; triangleloop.orient < 3;
++         triangleloop.orient++) {
++      org(triangleloop, triorg);
++      dest(triangleloop, tridest);
++      apex(triangleloop, triapex);
++      sym(triangleloop, oppotri);
++      apex(oppotri, oppoapex);
++      /* Only test that the edge is locally Delaunay if there is an   */
++      /*   adjoining triangle whose pointer is larger (to ensure that */
++      /*   each pair isn't tested twice).                             */
++      shouldbedelaunay = (oppotri.tri != dummytri)
++            && (triapex != (point) NULL) && (oppoapex != (point) NULL)
++            && (triangleloop.tri < oppotri.tri);
++      if (checksegments && shouldbedelaunay) {
++        /* If a shell edge separates the triangles, then the edge is */
++        /*   constrained, so no local Delaunay test should be done.  */
++        tspivot(triangleloop, opposhelle);
++        if (opposhelle.sh != dummysh){
++          shouldbedelaunay = 0;
++        }
++      }
++      if (shouldbedelaunay) {
++        if (incircle(triorg, tridest, triapex, oppoapex) > 0.0) {
++          printf("  !! !! Non-Delaunay pair of triangles:\n");
++          printf("    First non-Delaunay ");
++          printtriangle(&triangleloop);
++          printf("    Second non-Delaunay ");
++          printtriangle(&oppotri);
++          horrors++;
++        }
++      }
++    }
++    triangleloop.tri = triangletraverse();
++  }
++  if (horrors == 0) {
++    if (!quiet) {
++      printf(
++  "  By virtue of my perceptive intelligence, I declare the mesh Delaunay.\n");
++    }
++  } else if (horrors == 1) {
++    printf(
++         "  !! !! !! !! Precisely one terrifying transgression identified.\n");
++  } else {
++    printf("  !! !! !! !! %d obscenities viewed with horror.\n", horrors);
++  }
++  /* Restore the status of exact arithmetic. */
++  noexact = saveexact;
++}
++
++#endif /* not REDUCED */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  enqueuebadtri()   Add a bad triangle to the end of a queue.              */
++/*                                                                           */
++/*  The queue is actually a set of 64 queues.  I use multiple queues to give */
++/*  priority to smaller angles.  I originally implemented a heap, but the    */
++/*  queues are (to my surprise) much faster.                                 */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++void enqueuebadtri(instri, angle, insapex, insorg, insdest)
++struct triedge *instri;
++REAL angle;
++point insapex;
++point insorg;
++point insdest;
++{
++  struct badface *newface;
++  int queuenumber;
++
++  if (verbose > 2) {
++    printf("  Queueing bad triangle:\n");
++    printf("    (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", insorg[0],
++           insorg[1], insdest[0], insdest[1], insapex[0], insapex[1]);
++  }
++  /* Allocate space for the bad triangle. */
++  newface = (struct badface *) poolalloc(&badtriangles);
++  triedgecopy(*instri, newface->badfacetri);
++  newface->key = angle;
++  newface->faceapex = insapex;
++  newface->faceorg = insorg;
++  newface->facedest = insdest;
++  newface->nextface = (struct badface *) NULL;
++  /* Determine the appropriate queue to put the bad triangle into. */
++  if (angle > 0.6) {
++    queuenumber = (int) (160.0 * (angle - 0.6));
++    if (queuenumber > 63) {
++      queuenumber = 63;
++    }
++  } else {
++    /* It's not a bad angle; put the triangle in the lowest-priority queue. */
++    queuenumber = 0;
++  }
++  /* Add the triangle to the end of a queue. */
++  *queuetail[queuenumber] = newface;
++  /* Maintain a pointer to the NULL pointer at the end of the queue. */
++  queuetail[queuenumber] = &newface->nextface;
++}
++
++#endif /* not CDT_ONLY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  dequeuebadtri()   Remove a triangle from the front of the queue.         */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++struct badface *dequeuebadtri()
++{
++  struct badface *result;
++  int queuenumber;
++
++  /* Look for a nonempty queue. */
++  for (queuenumber = 63; queuenumber >= 0; queuenumber--) {
++    result = queuefront[queuenumber];
++    if (result != (struct badface *) NULL) {
++      /* Remove the triangle from the queue. */
++      queuefront[queuenumber] = result->nextface;
++      /* Maintain a pointer to the NULL pointer at the end of the queue. */
++      if (queuefront[queuenumber] == (struct badface *) NULL) {
++        queuetail[queuenumber] = &queuefront[queuenumber];
++      }
++      return result;
++    }
++  }
++  return (struct badface *) NULL;
++}
++
++#endif /* not CDT_ONLY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  checkedge4encroach()   Check a segment to see if it is encroached; add   */
++/*                         it to the list if it is.                          */
++/*                                                                           */
++/*  An encroached segment is an unflippable edge that has a point in its     */
++/*  diametral circle (that is, it faces an angle greater than 90 degrees).   */
++/*  This definition is due to Ruppert.                                       */
++/*                                                                           */
++/*  Returns a nonzero value if the edge is encroached.                       */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++int checkedge4encroach(testedge)
++struct edge *testedge;
++{
++  struct triedge neighbortri;
++  struct edge testsym;
++  struct edge *badedge;
++  int addtolist;
++  int sides;
++  point eorg, edest, eapex;
++  triangle ptr;                     /* Temporary variable used by stpivot(). */
++
++  addtolist = 0;
++  sides = 0;
++
++  sorg(*testedge, eorg);
++  sdest(*testedge, edest);
++  /* Check one neighbor of the shell edge. */
++  stpivot(*testedge, neighbortri);
++  /* Does the neighbor exist, or is this a boundary edge? */
++  if (neighbortri.tri != dummytri) {
++    sides++;
++    /* Find a vertex opposite this edge. */
++    apex(neighbortri, eapex);
++    /* Check whether the vertex is inside the diametral circle of the  */
++    /*   shell edge.  Pythagoras' Theorem is used to check whether the */
++    /*   angle at the vertex is greater than 90 degrees.               */
++    if (eapex[0] * (eorg[0] + edest[0]) + eapex[1] * (eorg[1] + edest[1]) >
++        eapex[0] * eapex[0] + eorg[0] * edest[0] +
++        eapex[1] * eapex[1] + eorg[1] * edest[1]) {
++      addtolist = 1;
++    }
++  }
++  /* Check the other neighbor of the shell edge. */
++  ssym(*testedge, testsym);
++  stpivot(testsym, neighbortri);
++  /* Does the neighbor exist, or is this a boundary edge? */
++  if (neighbortri.tri != dummytri) {
++    sides++;
++    /* Find the other vertex opposite this edge. */
++    apex(neighbortri, eapex);
++    /* Check whether the vertex is inside the diametral circle of the  */
++    /*   shell edge.  Pythagoras' Theorem is used to check whether the */
++    /*   angle at the vertex is greater than 90 degrees.               */
++    if (eapex[0] * (eorg[0] + edest[0]) +
++        eapex[1] * (eorg[1] + edest[1]) >
++        eapex[0] * eapex[0] + eorg[0] * edest[0] +
++        eapex[1] * eapex[1] + eorg[1] * edest[1]) {
++      addtolist += 2;
++    }
++  }
++
++  if (addtolist && (!nobisect || ((nobisect == 1) && (sides == 2)))) {
++    if (verbose > 2) {
++      printf("  Queueing encroached segment (%.12g, %.12g) (%.12g, %.12g).\n",
++             eorg[0], eorg[1], edest[0], edest[1]);
++    }
++    /* Add the shell edge to the list of encroached segments. */
++    /*   Be sure to get the orientation right.                */
++    badedge = (struct edge *) poolalloc(&badsegments);
++    if (addtolist == 1) {
++      shellecopy(*testedge, *badedge);
++    } else {
++      shellecopy(testsym, *badedge);
++    }
++  }
++  return addtolist;
++}
++
++#endif /* not CDT_ONLY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  testtriangle()   Test a face for quality measures.                       */
++/*                                                                           */
++/*  Tests a triangle to see if it satisfies the minimum angle condition and  */
++/*  the maximum area condition.  Triangles that aren't up to spec are added  */
++/*  to the bad triangle queue.                                               */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++void testtriangle(testtri)
++struct triedge *testtri;
++{
++  struct triedge sametesttri;
++  struct edge edge1, edge2;
++  point torg, tdest, tapex;
++  point anglevertex;
++  REAL dxod, dyod, dxda, dyda, dxao, dyao;
++  REAL dxod2, dyod2, dxda2, dyda2, dxao2, dyao2;
++  REAL apexlen, orglen, destlen;
++  REAL angle;
++  REAL area;
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  org(*testtri, torg);
++  dest(*testtri, tdest);
++  apex(*testtri, tapex);
++  dxod = torg[0] - tdest[0];
++  dyod = torg[1] - tdest[1];
++  dxda = tdest[0] - tapex[0];
++  dyda = tdest[1] - tapex[1];
++  dxao = tapex[0] - torg[0];
++  dyao = tapex[1] - torg[1];
++  dxod2 = dxod * dxod;
++  dyod2 = dyod * dyod;
++  dxda2 = dxda * dxda;
++  dyda2 = dyda * dyda;
++  dxao2 = dxao * dxao;
++  dyao2 = dyao * dyao;
++  /* Find the lengths of the triangle's three edges. */
++  apexlen = dxod2 + dyod2;
++  orglen = dxda2 + dyda2;
++  destlen = dxao2 + dyao2;
++  if ((apexlen < orglen) && (apexlen < destlen)) {
++    /* The edge opposite the apex is shortest. */
++    /* Find the square of the cosine of the angle at the apex. */
++    angle = dxda * dxao + dyda * dyao;
++    angle = angle * angle / (orglen * destlen);
++    anglevertex = tapex;
++    lnext(*testtri, sametesttri);
++    tspivot(sametesttri, edge1);
++    lnextself(sametesttri);
++    tspivot(sametesttri, edge2);
++  } else if (orglen < destlen) {
++    /* The edge opposite the origin is shortest. */
++    /* Find the square of the cosine of the angle at the origin. */
++    angle = dxod * dxao + dyod * dyao;
++    angle = angle * angle / (apexlen * destlen);
++    anglevertex = torg;
++    tspivot(*testtri, edge1);
++    lprev(*testtri, sametesttri);
++    tspivot(sametesttri, edge2);
++  } else {
++    /* The edge opposite the destination is shortest. */
++    /* Find the square of the cosine of the angle at the destination. */
++    angle = dxod * dxda + dyod * dyda;
++    angle = angle * angle / (apexlen * orglen);
++    anglevertex = tdest;
++    tspivot(*testtri, edge1);
++    lnext(*testtri, sametesttri);
++    tspivot(sametesttri, edge2);
++  }
++  /* Check if both edges that form the angle are segments. */
++  if ((edge1.sh != dummysh) && (edge2.sh != dummysh)) {
++    /* The angle is a segment intersection. */
++    if ((angle > 0.9924) && !quiet) {                  /* Roughly 5 degrees. */
++      if (angle > 1.0) {
++        /* Beware of a floating exception in acos(). */
++        angle = 1.0;
++      }
++      /* Find the actual angle in degrees, for printing. */
++      angle = acos(sqrt(angle)) * (180.0 / PI);
++      printf(
++      "Warning:  Small angle (%.4g degrees) between segments at point\n",
++             angle);
++      printf("  (%.12g, %.12g)\n", anglevertex[0], anglevertex[1]);
++    }
++    /* Don't add this bad triangle to the list; there's nothing that */
++    /*   can be done about a small angle between two segments.       */
++    angle = 0.0;
++  }
++  /* Check whether the angle is smaller than permitted. */
++  if (angle > goodangle) {
++    /* Add this triangle to the list of bad triangles. */
++    enqueuebadtri(testtri, angle, tapex, torg, tdest);
++    return;
++  }
++  if (vararea || fixedarea) {
++    /* Check whether the area is larger than permitted. */
++    area = 0.5 * (dxod * dyda - dyod * dxda);
++
++#if 0
++    if ( area < 1.0 / (2.0 * 3600.0 * 3600.0) ) {
++      /* FGFS ADDITION!!! */
++      /* small enough, don't add to list of bad triangles */
++      printf("REJECTING TRIANGLE OF AREA %.6g\n", area);
++    }
++#endif
++
++    if (fixedarea && (area > maxarea)) {
++      /* Add this triangle to the list of bad triangles. */
++      enqueuebadtri(testtri, angle, tapex, torg, tdest);
++    } else if (vararea) {
++      /* Nonpositive area constraints are treated as unconstrained. */
++      if ((area > areabound(*testtri)) && (areabound(*testtri) > 0.0)) {
++        /* Add this triangle to the list of bad triangles. */
++        enqueuebadtri(testtri, angle, tapex, torg, tdest);
++      }
++    }
++  }
++}
++
++#endif /* not CDT_ONLY */
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Mesh quality testing routines end here                    *********/
++
++/********* Point location routines begin here                        *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  makepointmap()   Construct a mapping from points to triangles to improve  */
++/*                  the speed of point location for segment insertion.       */
++/*                                                                           */
++/*  Traverses all the triangles, and provides each corner of each triangle   */
++/*  with a pointer to that triangle.  Of course, pointers will be            */
++/*  overwritten by other pointers because (almost) each point is a corner    */
++/*  of several triangles, but in the end every point will point to some      */
++/*  triangle that contains it.                                               */
++/*                                                                           */
++/*****************************************************************************/
++
++void makepointmap()
++{
++  struct triedge triangleloop;
++  point triorg;
++
++  if (verbose) {
++    printf("    Constructing mapping from points to triangles.\n");
++  }
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  while (triangleloop.tri != (triangle *) NULL) {
++    /* Check all three points of the triangle. */
++    for (triangleloop.orient = 0; triangleloop.orient < 3;
++         triangleloop.orient++) {
++      org(triangleloop, triorg);
++      setpoint2tri(triorg, encode(triangleloop));
++    }
++    triangleloop.tri = triangletraverse();
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  preciselocate()   Find a triangle or edge containing a given point.      */
++/*                                                                           */
++/*  Begins its search from `searchtri'.  It is important that `searchtri'    */
++/*  be a handle with the property that `searchpoint' is strictly to the left */
++/*  of the edge denoted by `searchtri', or is collinear with that edge and   */
++/*  does not intersect that edge.  (In particular, `searchpoint' should not  */
++/*  be the origin or destination of that edge.)                              */
++/*                                                                           */
++/*  These conditions are imposed because preciselocate() is normally used in */
++/*  one of two situations:                                                   */
++/*                                                                           */
++/*  (1)  To try to find the location to insert a new point.  Normally, we    */
++/*       know an edge that the point is strictly to the left of.  In the     */
++/*       incremental Delaunay algorithm, that edge is a bounding box edge.   */
++/*       In Ruppert's Delaunay refinement algorithm for quality meshing,     */
++/*       that edge is the shortest edge of the triangle whose circumcenter   */
++/*       is being inserted.                                                  */
++/*                                                                           */
++/*  (2)  To try to find an existing point.  In this case, any edge on the    */
++/*       convex hull is a good starting edge.  The possibility that the      */
++/*       vertex one seeks is an endpoint of the starting edge must be        */
++/*       screened out before preciselocate() is called.                      */
++/*                                                                           */
++/*  On completion, `searchtri' is a triangle that contains `searchpoint'.    */
++/*                                                                           */
++/*  This implementation differs from that given by Guibas and Stolfi.  It    */
++/*  walks from triangle to triangle, crossing an edge only if `searchpoint'  */
++/*  is on the other side of the line containing that edge.  After entering   */
++/*  a triangle, there are two edges by which one can leave that triangle.    */
++/*  If both edges are valid (`searchpoint' is on the other side of both      */
++/*  edges), one of the two is chosen by drawing a line perpendicular to      */
++/*  the entry edge (whose endpoints are `forg' and `fdest') passing through  */
++/*  `fapex'.  Depending on which side of this perpendicular `searchpoint'    */
++/*  falls on, an exit edge is chosen.                                        */
++/*                                                                           */
++/*  This implementation is empirically faster than the Guibas and Stolfi     */
++/*  point location routine (which I originally used), which tends to spiral  */
++/*  in toward its target.                                                    */
++/*                                                                           */
++/*  Returns ONVERTEX if the point lies on an existing vertex.  `searchtri'   */
++/*  is a handle whose origin is the existing vertex.                         */
++/*                                                                           */
++/*  Returns ONEDGE if the point lies on a mesh edge.  `searchtri' is a       */
++/*  handle whose primary edge is the edge on which the point lies.           */
++/*                                                                           */
++/*  Returns INTRIANGLE if the point lies strictly within a triangle.         */
++/*  `searchtri' is a handle on the triangle that contains the point.         */
++/*                                                                           */
++/*  Returns OUTSIDE if the point lies outside the mesh.  `searchtri' is a    */
++/*  handle whose primary edge the point is to the right of.  This might      */
++/*  occur when the circumcenter of a triangle falls just slightly outside    */
++/*  the mesh due to floating-point roundoff error.  It also occurs when      */
++/*  seeking a hole or region point that a foolish user has placed outside    */
++/*  the mesh.                                                                */
++/*                                                                           */
++/*  WARNING:  This routine is designed for convex triangulations, and will   */
++/*  not generally work after the holes and concavities have been carved.     */
++/*  However, it can still be used to find the circumcenter of a triangle, as */
++/*  long as the search is begun from the triangle in question.               */
++/*                                                                           */
++/*****************************************************************************/
++
++enum locateresult preciselocate(searchpoint, searchtri)
++point searchpoint;
++struct triedge *searchtri;
++{
++  struct triedge backtracktri;
++  point forg, fdest, fapex;
++  point swappoint;
++  REAL orgorient, destorient;
++  int moveleft;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++
++  if (verbose > 2) {
++    printf("  Searching for point (%.12g, %.12g).\n",
++           searchpoint[0], searchpoint[1]);
++  }
++  /* Where are we? */
++  org(*searchtri, forg);
++  dest(*searchtri, fdest);
++  apex(*searchtri, fapex);
++  while (1) {
++    if (verbose > 2) {
++      printf("    At (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
++             forg[0], forg[1], fdest[0], fdest[1], fapex[0], fapex[1]);
++    }
++    /* Check whether the apex is the point we seek. */
++    if ((fapex[0] == searchpoint[0]) && (fapex[1] == searchpoint[1])) {
++      lprevself(*searchtri);
++      return ONVERTEX;
++    }
++    /* Does the point lie on the other side of the line defined by the */
++    /*   triangle edge opposite the triangle's destination?            */
++    destorient = counterclockwise(forg, fapex, searchpoint);
++    /* Does the point lie on the other side of the line defined by the */
++    /*   triangle edge opposite the triangle's origin?                 */
++    orgorient = counterclockwise(fapex, fdest, searchpoint);
++    if (destorient > 0.0) {
++      if (orgorient > 0.0) {
++        /* Move left if the inner product of (fapex - searchpoint) and  */
++        /*   (fdest - forg) is positive.  This is equivalent to drawing */
++        /*   a line perpendicular to the line (forg, fdest) passing     */
++        /*   through `fapex', and determining which side of this line   */
++        /*   `searchpoint' falls on.                                    */
++        moveleft = (fapex[0] - searchpoint[0]) * (fdest[0] - forg[0]) +
++                   (fapex[1] - searchpoint[1]) * (fdest[1] - forg[1]) > 0.0;
++      } else {
++        moveleft = 1;
++      }
++    } else {
++      if (orgorient > 0.0) {
++        moveleft = 0;
++      } else {
++        /* The point we seek must be on the boundary of or inside this */
++        /*   triangle.                                                 */
++        if (destorient == 0.0) {
++          lprevself(*searchtri);
++          return ONEDGE;
++        }
++        if (orgorient == 0.0) {
++          lnextself(*searchtri);
++          return ONEDGE;
++        }
++        return INTRIANGLE;
++      }
++    }
++
++    /* Move to another triangle.  Leave a trace `backtracktri' in case */
++    /*   floating-point roundoff or some such bogey causes us to walk  */
++    /*   off a boundary of the triangulation.  We can just bounce off  */
++    /*   the boundary as if it were an elastic band.                   */
++    if (moveleft) {
++      lprev(*searchtri, backtracktri);
++      fdest = fapex;
++    } else {
++      lnext(*searchtri, backtracktri);
++      forg = fapex;
++    }
++    sym(backtracktri, *searchtri);
++
++    /* Check for walking off the edge. */
++    if (searchtri->tri == dummytri) {
++      /* Turn around. */
++      triedgecopy(backtracktri, *searchtri);
++      swappoint = forg;
++      forg = fdest;
++      fdest = swappoint;
++      apex(*searchtri, fapex);
++      /* Check if the point really is beyond the triangulation boundary. */
++      destorient = counterclockwise(forg, fapex, searchpoint);
++      orgorient = counterclockwise(fapex, fdest, searchpoint);
++      if ((orgorient < 0.0) && (destorient < 0.0)) {
++        return OUTSIDE;
++      }
++    } else {
++      apex(*searchtri, fapex);
++    }
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  locate()   Find a triangle or edge containing a given point.             */
++/*                                                                           */
++/*  Searching begins from one of:  the input `searchtri', a recently         */
++/*  encountered triangle `recenttri', or from a triangle chosen from a       */
++/*  random sample.  The choice is made by determining which triangle's       */
++/*  origin is closest to the point we are searcing for.  Normally,           */
++/*  `searchtri' should be a handle on the convex hull of the triangulation.  */
++/*                                                                           */
++/*  Details on the random sampling method can be found in the Mucke, Saias,  */
++/*  and Zhu paper cited in the header of this code.                          */
++/*                                                                           */
++/*  On completion, `searchtri' is a triangle that contains `searchpoint'.    */
++/*                                                                           */
++/*  Returns ONVERTEX if the point lies on an existing vertex.  `searchtri'   */
++/*  is a handle whose origin is the existing vertex.                         */
++/*                                                                           */
++/*  Returns ONEDGE if the point lies on a mesh edge.  `searchtri' is a       */
++/*  handle whose primary edge is the edge on which the point lies.           */
++/*                                                                           */
++/*  Returns INTRIANGLE if the point lies strictly within a triangle.         */
++/*  `searchtri' is a handle on the triangle that contains the point.         */
++/*                                                                           */
++/*  Returns OUTSIDE if the point lies outside the mesh.  `searchtri' is a    */
++/*  handle whose primary edge the point is to the right of.  This might      */
++/*  occur when the circumcenter of a triangle falls just slightly outside    */
++/*  the mesh due to floating-point roundoff error.  It also occurs when      */
++/*  seeking a hole or region point that a foolish user has placed outside    */
++/*  the mesh.                                                                */
++/*                                                                           */
++/*  WARNING:  This routine is designed for convex triangulations, and will   */
++/*  not generally work after the holes and concavities have been carved.     */
++/*                                                                           */
++/*****************************************************************************/
++
++enum locateresult locate(searchpoint, searchtri)
++point searchpoint;
++struct triedge *searchtri;
++{
++  VOID **sampleblock;
++  triangle *firsttri;
++  struct triedge sampletri;
++  point torg, tdest;
++  unsigned long alignptr;
++  REAL searchdist, dist;
++  REAL ahead;
++  long sampleblocks, samplesperblock, samplenum;
++  long triblocks;
++  long i, j;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++
++  if (verbose > 2) {
++    printf("  Randomly sampling for a triangle near point (%.12g, %.12g).\n",
++           searchpoint[0], searchpoint[1]);
++  }
++  /* Record the distance from the suggested starting triangle to the */
++  /*   point we seek.                                                */
++  org(*searchtri, torg);
++  searchdist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0])
++             + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
++  if (verbose > 2) {
++    printf("    Boundary triangle has origin (%.12g, %.12g).\n",
++           torg[0], torg[1]);
++  }
++
++  /* If a recently encountered triangle has been recorded and has not been */
++  /*   deallocated, test it as a good starting point.                      */
++  if (recenttri.tri != (triangle *) NULL) {
++    if (recenttri.tri[3] != (triangle) NULL) {
++      org(recenttri, torg);
++      if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) {
++        triedgecopy(recenttri, *searchtri);
++        return ONVERTEX;
++      }
++      dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0])
++           + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
++      if (dist < searchdist) {
++        triedgecopy(recenttri, *searchtri);
++        searchdist = dist;
++        if (verbose > 2) {
++          printf("    Choosing recent triangle with origin (%.12g, %.12g).\n",
++                 torg[0], torg[1]);
++        }
++      }
++    }
++  }
++
++  /* The number of random samples taken is proportional to the cube root of */
++  /*   the number of triangles in the mesh.  The next bit of code assumes   */
++  /*   that the number of triangles increases monotonically.                */
++  while (SAMPLEFACTOR * samples * samples * samples < triangles.items) {
++    samples++;
++  }
++  triblocks = (triangles.maxitems + TRIPERBLOCK - 1) / TRIPERBLOCK;
++  samplesperblock = 1 + (samples / triblocks);
++  sampleblocks = samples / samplesperblock;
++  sampleblock = triangles.firstblock;
++  sampletri.orient = 0;
++  for (i = 0; i < sampleblocks; i++) {
++    alignptr = (unsigned long) (sampleblock + 1);
++    firsttri = (triangle *) (alignptr + (unsigned long) triangles.alignbytes
++                          - (alignptr % (unsigned long) triangles.alignbytes));
++    for (j = 0; j < samplesperblock; j++) {
++      if (i == triblocks - 1) {
++        samplenum = randomnation((int)
++                                 (triangles.maxitems - (i * TRIPERBLOCK)));
++      } else {
++        samplenum = randomnation(TRIPERBLOCK);
++      }
++      sampletri.tri = (triangle *)
++                      (firsttri + (samplenum * triangles.itemwords));
++      if (sampletri.tri[3] != (triangle) NULL) {
++        org(sampletri, torg);
++        dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0])
++             + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
++        if (dist < searchdist) {
++          triedgecopy(sampletri, *searchtri);
++          searchdist = dist;
++          if (verbose > 2) {
++            printf("    Choosing triangle with origin (%.12g, %.12g).\n",
++                   torg[0], torg[1]);
++          }
++        }
++      }
++    }
++    sampleblock = (VOID **) *sampleblock;
++  }
++  /* Where are we? */
++  org(*searchtri, torg);
++  dest(*searchtri, tdest);
++  /* Check the starting triangle's vertices. */
++  if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) {
++    return ONVERTEX;
++  }
++  if ((tdest[0] == searchpoint[0]) && (tdest[1] == searchpoint[1])) {
++    lnextself(*searchtri);
++    return ONVERTEX;
++  }
++  /* Orient `searchtri' to fit the preconditions of calling preciselocate(). */
++  ahead = counterclockwise(torg, tdest, searchpoint);
++  if (ahead < 0.0) {
++    /* Turn around so that `searchpoint' is to the left of the */
++    /*   edge specified by `searchtri'.                        */
++    symself(*searchtri);
++  } else if (ahead == 0.0) {
++    /* Check if `searchpoint' is between `torg' and `tdest'. */
++    if (((torg[0] < searchpoint[0]) == (searchpoint[0] < tdest[0]))
++        && ((torg[1] < searchpoint[1]) == (searchpoint[1] < tdest[1]))) {
++      return ONEDGE;
++    }
++  }
++  return preciselocate(searchpoint, searchtri);
++}
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Point location routines end here                          *********/
++
++/********* Mesh transformation routines begin here                   *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  insertshelle()   Create a new shell edge and insert it between two       */
++/*                   triangles.                                              */
++/*                                                                           */
++/*  The new shell edge is inserted at the edge described by the handle       */
++/*  `tri'.  Its vertices are properly initialized.  The marker `shellemark'  */
++/*  is applied to the shell edge and, if appropriate, its vertices.          */
++/*                                                                           */
++/*****************************************************************************/
++
++void insertshelle(tri, shellemark)
++struct triedge *tri;          /* Edge at which to insert the new shell edge. */
++int shellemark;                            /* Marker for the new shell edge. */
++{
++  struct triedge oppotri;
++  struct edge newshelle;
++  point triorg, tridest;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  /* Mark points if possible. */
++  org(*tri, triorg);
++  dest(*tri, tridest);
++  if (pointmark(triorg) == 0) {
++    setpointmark(triorg, shellemark);
++  }
++  if (pointmark(tridest) == 0) {
++    setpointmark(tridest, shellemark);
++  }
++  /* Check if there's already a shell edge here. */
++  tspivot(*tri, newshelle);
++  if (newshelle.sh == dummysh) {
++    /* Make new shell edge and initialize its vertices. */
++    makeshelle(&newshelle);
++    setsorg(newshelle, tridest);
++    setsdest(newshelle, triorg);
++    /* Bond new shell edge to the two triangles it is sandwiched between. */
++    /*   Note that the facing triangle `oppotri' might be equal to        */
++    /*   `dummytri' (outer space), but the new shell edge is bonded to it */
++    /*   all the same.                                                    */
++    tsbond(*tri, newshelle);
++    sym(*tri, oppotri);
++    ssymself(newshelle);
++    tsbond(oppotri, newshelle);
++    setmark(newshelle, shellemark);
++    if (verbose > 2) {
++      printf("  Inserting new ");
++      printshelle(&newshelle);
++    }
++  } else {
++    if (mark(newshelle) == 0) {
++      setmark(newshelle, shellemark);
++    }
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  Terminology                                                              */
++/*                                                                           */
++/*  A "local transformation" replaces a small set of triangles with another  */
++/*  set of triangles.  This may or may not involve inserting or deleting a   */
++/*  point.                                                                   */
++/*                                                                           */
++/*  The term "casing" is used to describe the set of triangles that are      */
++/*  attached to the triangles being transformed, but are not transformed     */
++/*  themselves.  Think of the casing as a fixed hollow structure inside      */
++/*  which all the action happens.  A "casing" is only defined relative to    */
++/*  a single transformation; each occurrence of a transformation will        */
++/*  involve a different casing.                                              */
++/*                                                                           */
++/*  A "shell" is similar to a "casing".  The term "shell" describes the set  */
++/*  of shell edges (if any) that are attached to the triangles being         */
++/*  transformed.  However, I sometimes use "shell" to refer to a single      */
++/*  shell edge, so don't get confused.                                       */
++/*                                                                           */
++/*****************************************************************************/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  flip()   Transform two triangles to two different triangles by flipping  */
++/*           an edge within a quadrilateral.                                 */
++/*                                                                           */
++/*  Imagine the original triangles, abc and bad, oriented so that the        */
++/*  shared edge ab lies in a horizontal plane, with the point b on the left  */
++/*  and the point a on the right.  The point c lies below the edge, and the  */
++/*  point d lies above the edge.  The `flipedge' handle holds the edge ab    */
++/*  of triangle abc, and is directed left, from vertex a to vertex b.        */
++/*                                                                           */
++/*  The triangles abc and bad are deleted and replaced by the triangles cdb  */
++/*  and dca.  The triangles that represent abc and bad are NOT deallocated;  */
++/*  they are reused for dca and cdb, respectively.  Hence, any handles that  */
++/*  may have held the original triangles are still valid, although not       */
++/*  directed as they were before.                                            */
++/*                                                                           */
++/*  Upon completion of this routine, the `flipedge' handle holds the edge    */
++/*  dc of triangle dca, and is directed down, from vertex d to vertex c.     */
++/*  (Hence, the two triangles have rotated counterclockwise.)                */
++/*                                                                           */
++/*  WARNING:  This transformation is geometrically valid only if the         */
++/*  quadrilateral adbc is convex.  Furthermore, this transformation is       */
++/*  valid only if there is not a shell edge between the triangles abc and    */
++/*  bad.  This routine does not check either of these preconditions, and     */
++/*  it is the responsibility of the calling routine to ensure that they are  */
++/*  met.  If they are not, the streets shall be filled with wailing and      */
++/*  gnashing of teeth.                                                       */
++/*                                                                           */
++/*****************************************************************************/
++
++void flip(flipedge)
++struct triedge *flipedge;                    /* Handle for the triangle abc. */
++{
++  struct triedge botleft, botright;
++  struct triedge topleft, topright;
++  struct triedge top;
++  struct triedge botlcasing, botrcasing;
++  struct triedge toplcasing, toprcasing;
++  struct edge botlshelle, botrshelle;
++  struct edge toplshelle, toprshelle;
++  point leftpoint, rightpoint, botpoint;
++  point farpoint;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  /* Identify the vertices of the quadrilateral. */
++  org(*flipedge, rightpoint);
++  dest(*flipedge, leftpoint);
++  apex(*flipedge, botpoint);
++  sym(*flipedge, top);
++#ifdef SELF_CHECK
++  if (top.tri == dummytri) {
++    printf("Internal error in flip():  Attempt to flip on boundary.\n");
++    lnextself(*flipedge);
++    return;
++  }
++  if (checksegments) {
++    tspivot(*flipedge, toplshelle);
++    if (toplshelle.sh != dummysh) {
++      printf("Internal error in flip():  Attempt to flip a segment.\n");
++      lnextself(*flipedge);
++      return;
++    }
++  }
++#endif /* SELF_CHECK */
++  apex(top, farpoint);
++
++  /* Identify the casing of the quadrilateral. */
++  lprev(top, topleft);
++  sym(topleft, toplcasing);
++  lnext(top, topright);
++  sym(topright, toprcasing);
++  lnext(*flipedge, botleft);
++  sym(botleft, botlcasing);
++  lprev(*flipedge, botright);
++  sym(botright, botrcasing);
++  /* Rotate the quadrilateral one-quarter turn counterclockwise. */
++  bond(topleft, botlcasing);
++  bond(botleft, botrcasing);
++  bond(botright, toprcasing);
++  bond(topright, toplcasing);
++
++  if (checksegments) {
++    /* Check for shell edges and rebond them to the quadrilateral. */
++    tspivot(topleft, toplshelle);
++    tspivot(botleft, botlshelle);
++    tspivot(botright, botrshelle);
++    tspivot(topright, toprshelle);
++    if (toplshelle.sh == dummysh) {
++      tsdissolve(topright);
++    } else {
++      tsbond(topright, toplshelle);
++    }
++    if (botlshelle.sh == dummysh) {
++      tsdissolve(topleft);
++    } else {
++      tsbond(topleft, botlshelle);
++    }
++    if (botrshelle.sh == dummysh) {
++      tsdissolve(botleft);
++    } else {
++      tsbond(botleft, botrshelle);
++    }
++    if (toprshelle.sh == dummysh) {
++      tsdissolve(botright);
++    } else {
++      tsbond(botright, toprshelle);
++    }
++  }
++
++  /* New point assignments for the rotated quadrilateral. */
++  setorg(*flipedge, farpoint);
++  setdest(*flipedge, botpoint);
++  setapex(*flipedge, rightpoint);
++  setorg(top, botpoint);
++  setdest(top, farpoint);
++  setapex(top, leftpoint);
++  if (verbose > 2) {
++    printf("  Edge flip results in left ");
++    lnextself(topleft);
++    printtriangle(&topleft);
++    printf("  and right ");
++    printtriangle(flipedge);
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  insertsite()   Insert a vertex into a Delaunay triangulation,            */
++/*                 performing flips as necessary to maintain the Delaunay    */
++/*                 property.                                                 */
++/*                                                                           */
++/*  The point `insertpoint' is located.  If `searchtri.tri' is not NULL,     */
++/*  the search for the containing triangle begins from `searchtri'.  If      */
++/*  `searchtri.tri' is NULL, a full point location procedure is called.      */
++/*  If `insertpoint' is found inside a triangle, the triangle is split into  */
++/*  three; if `insertpoint' lies on an edge, the edge is split in two,       */
++/*  thereby splitting the two adjacent triangles into four.  Edge flips are  */
++/*  used to restore the Delaunay property.  If `insertpoint' lies on an      */
++/*  existing vertex, no action is taken, and the value DUPLICATEPOINT is     */
++/*  returned.  On return, `searchtri' is set to a handle whose origin is the */
++/*  existing vertex.                                                         */
++/*                                                                           */
++/*  Normally, the parameter `splitedge' is set to NULL, implying that no     */
++/*  segment should be split.  In this case, if `insertpoint' is found to     */
++/*  lie on a segment, no action is taken, and the value VIOLATINGPOINT is    */
++/*  returned.  On return, `searchtri' is set to a handle whose primary edge  */
++/*  is the violated segment.                                                 */
++/*                                                                           */
++/*  If the calling routine wishes to split a segment by inserting a point in */
++/*  it, the parameter `splitedge' should be that segment.  In this case,     */
++/*  `searchtri' MUST be the triangle handle reached by pivoting from that    */
++/*  segment; no point location is done.                                      */
++/*                                                                           */
++/*  `segmentflaws' and `triflaws' are flags that indicate whether or not     */
++/*  there should be checks for the creation of encroached segments or bad    */
++/*  quality faces.  If a newly inserted point encroaches upon segments,      */
++/*  these segments are added to the list of segments to be split if          */
++/*  `segmentflaws' is set.  If bad triangles are created, these are added    */
++/*  to the queue if `triflaws' is set.                                       */
++/*                                                                           */
++/*  If a duplicate point or violated segment does not prevent the point      */
++/*  from being inserted, the return value will be ENCROACHINGPOINT if the    */
++/*  point encroaches upon a segment (and checking is enabled), or            */
++/*  SUCCESSFULPOINT otherwise.  In either case, `searchtri' is set to a      */
++/*  handle whose origin is the newly inserted vertex.                        */
++/*                                                                           */
++/*  insertsite() does not use flip() for reasons of speed; some              */
++/*  information can be reused from edge flip to edge flip, like the          */
++/*  locations of shell edges.                                                */
++/*                                                                           */
++/*****************************************************************************/
++
++enum insertsiteresult insertsite(insertpoint, searchtri, splitedge,
++                                 segmentflaws, triflaws)
++point insertpoint;
++struct triedge *searchtri;
++struct edge *splitedge;
++int segmentflaws;
++int triflaws;
++{
++  struct triedge horiz;
++  struct triedge top;
++  struct triedge botleft, botright;
++  struct triedge topleft, topright;
++  struct triedge newbotleft, newbotright;
++  struct triedge newtopright;
++  struct triedge botlcasing, botrcasing;
++  struct triedge toplcasing, toprcasing;
++  struct triedge testtri;
++  struct edge botlshelle, botrshelle;
++  struct edge toplshelle, toprshelle;
++  struct edge brokenshelle;
++  struct edge checkshelle;
++  struct edge rightedge;
++  struct edge newedge;
++  struct edge *encroached;
++  point first;
++  point leftpoint, rightpoint, botpoint, toppoint, farpoint;
++  REAL attrib;
++  REAL area;
++  enum insertsiteresult success;
++  enum locateresult intersect;
++  int doflip;
++  int mirrorflag;
++  int i;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++  shelle sptr;         /* Temporary variable used by spivot() and tspivot(). */
++
++  if (verbose > 1) {
++    printf("  Inserting (%.12g, %.12g).\n", insertpoint[0], insertpoint[1]);
++  }
++  if (splitedge == (struct edge *) NULL) {
++    /* Find the location of the point to be inserted.  Check if a good */
++    /*   starting triangle has already been provided by the caller.    */
++    if (searchtri->tri == (triangle *) NULL) {
++      /* Find a boundary triangle. */
++      horiz.tri = dummytri;
++      horiz.orient = 0;
++      symself(horiz);
++      /* Search for a triangle containing `insertpoint'. */
++      intersect = locate(insertpoint, &horiz);
++    } else {
++      /* Start searching from the triangle provided by the caller. */
++      triedgecopy(*searchtri, horiz);
++      intersect = preciselocate(insertpoint, &horiz);
++    }
++  } else {
++    /* The calling routine provides the edge in which the point is inserted. */
++    triedgecopy(*searchtri, horiz);
++    intersect = ONEDGE;
++  }
++  if (intersect == ONVERTEX) {
++    /* There's already a vertex there.  Return in `searchtri' a triangle */
++    /*   whose origin is the existing vertex.                            */
++    triedgecopy(horiz, *searchtri);
++    triedgecopy(horiz, recenttri);
++    return DUPLICATEPOINT;
++  }
++  if ((intersect == ONEDGE) || (intersect == OUTSIDE)) {
++    /* The vertex falls on an edge or boundary. */
++    if (checksegments && (splitedge == (struct edge *) NULL)) {
++      /* Check whether the vertex falls on a shell edge. */
++      tspivot(horiz, brokenshelle);
++      if (brokenshelle.sh != dummysh) {
++        /* The vertex falls on a shell edge. */
++        if (segmentflaws) {
++          if (nobisect == 0) {
++            /* Add the shell edge to the list of encroached segments. */
++            encroached = (struct edge *) poolalloc(&badsegments);
++            shellecopy(brokenshelle, *encroached);
++          } else if ((nobisect == 1) && (intersect == ONEDGE)) {
++            /* This segment may be split only if it is an internal boundary. */
++            sym(horiz, testtri);
++            if (testtri.tri != dummytri) {
++              /* Add the shell edge to the list of encroached segments. */
++              encroached = (struct edge *) poolalloc(&badsegments);
++              shellecopy(brokenshelle, *encroached);
++            }
++          }
++        }
++        /* Return a handle whose primary edge contains the point, */
++        /*   which has not been inserted.                         */
++        triedgecopy(horiz, *searchtri);
++        triedgecopy(horiz, recenttri);
++        return VIOLATINGPOINT;
++      }
++    }
++    /* Insert the point on an edge, dividing one triangle into two (if */
++    /*   the edge lies on a boundary) or two triangles into four.      */
++    lprev(horiz, botright);
++    sym(botright, botrcasing);
++    sym(horiz, topright);
++    /* Is there a second triangle?  (Or does this edge lie on a boundary?) */
++    mirrorflag = topright.tri != dummytri;
++    if (mirrorflag) {
++      lnextself(topright);
++      sym(topright, toprcasing);
++      maketriangle(&newtopright);
++    } else {
++      /* Splitting the boundary edge increases the number of boundary edges. */
++      hullsize++;
++    }
++    maketriangle(&newbotright);
++
++    /* Set the vertices of changed and new triangles. */
++    org(horiz, rightpoint);
++    dest(horiz, leftpoint);
++    apex(horiz, botpoint);
++    setorg(newbotright, botpoint);
++    setdest(newbotright, rightpoint);
++    setapex(newbotright, insertpoint);
++    setorg(horiz, insertpoint);
++    for (i = 0; i < eextras; i++) {
++      /* Set the element attributes of a new triangle. */
++      setelemattribute(newbotright, i, elemattribute(botright, i));
++    }
++    if (vararea) {
++      /* Set the area constraint of a new triangle. */
++      setareabound(newbotright, areabound(botright));
++    }
++    if (mirrorflag) {
++      dest(topright, toppoint);
++      setorg(newtopright, rightpoint);
++      setdest(newtopright, toppoint);
++      setapex(newtopright, insertpoint);
++      setorg(topright, insertpoint);
++      for (i = 0; i < eextras; i++) {
++        /* Set the element attributes of another new triangle. */
++        setelemattribute(newtopright, i, elemattribute(topright, i));
++      }
++      if (vararea) {
++        /* Set the area constraint of another new triangle. */
++        setareabound(newtopright, areabound(topright));
++      }
++    }
++
++    /* There may be shell edges that need to be bonded */
++    /*   to the new triangle(s).                       */
++    if (checksegments) {
++      tspivot(botright, botrshelle);
++      if (botrshelle.sh != dummysh) {
++        tsdissolve(botright);
++        tsbond(newbotright, botrshelle);
++      }
++      if (mirrorflag) {
++        tspivot(topright, toprshelle);
++        if (toprshelle.sh != dummysh) {
++          tsdissolve(topright);
++          tsbond(newtopright, toprshelle);
++        }
++      }
++    }
++
++    /* Bond the new triangle(s) to the surrounding triangles. */
++    bond(newbotright, botrcasing);
++    lprevself(newbotright);
++    bond(newbotright, botright);
++    lprevself(newbotright);
++    if (mirrorflag) {
++      bond(newtopright, toprcasing);
++      lnextself(newtopright);
++      bond(newtopright, topright);
++      lnextself(newtopright);
++      bond(newtopright, newbotright);
++    }
++
++    if (splitedge != (struct edge *) NULL) {
++      /* Split the shell edge into two. */
++      setsdest(*splitedge, insertpoint);
++      ssymself(*splitedge);
++      spivot(*splitedge, rightedge);
++      insertshelle(&newbotright, mark(*splitedge));
++      tspivot(newbotright, newedge);
++      sbond(*splitedge, newedge);
++      ssymself(newedge);
++      sbond(newedge, rightedge);
++      ssymself(*splitedge);
++    }
++
++#ifdef SELF_CHECK
++    if (counterclockwise(rightpoint, leftpoint, botpoint) < 0.0) {
++      printf("Internal error in insertsite():\n");
++      printf("  Clockwise triangle prior to edge point insertion (bottom).\n");
++    }
++    if (mirrorflag) {
++      if (counterclockwise(leftpoint, rightpoint, toppoint) < 0.0) {
++        printf("Internal error in insertsite():\n");
++        printf("  Clockwise triangle prior to edge point insertion (top).\n");
++      }
++      if (counterclockwise(rightpoint, toppoint, insertpoint) < 0.0) {
++        printf("Internal error in insertsite():\n");
++        printf("  Clockwise triangle after edge point insertion (top right).\n"
++               );
++      }
++      if (counterclockwise(toppoint, leftpoint, insertpoint) < 0.0) {
++        printf("Internal error in insertsite():\n");
++        printf("  Clockwise triangle after edge point insertion (top left).\n"
++               );
++      }
++    }
++    if (counterclockwise(leftpoint, botpoint, insertpoint) < 0.0) {
++      printf("Internal error in insertsite():\n");
++      printf("  Clockwise triangle after edge point insertion (bottom left).\n"
++             );
++    }
++    if (counterclockwise(botpoint, rightpoint, insertpoint) < 0.0) {
++      printf("Internal error in insertsite():\n");
++      printf(
++        "  Clockwise triangle after edge point insertion (bottom right).\n");
++    }
++#endif /* SELF_CHECK */
++    if (verbose > 2) {
++      printf("  Updating bottom left ");
++      printtriangle(&botright);
++      if (mirrorflag) {
++        printf("  Updating top left ");
++        printtriangle(&topright);
++        printf("  Creating top right ");
++        printtriangle(&newtopright);
++      }
++      printf("  Creating bottom right ");
++      printtriangle(&newbotright);
++    }
++
++    /* Position `horiz' on the first edge to check for */
++    /*   the Delaunay property.                        */
++    lnextself(horiz);
++  } else {
++    /* Insert the point in a triangle, splitting it into three. */
++    lnext(horiz, botleft);
++    lprev(horiz, botright);
++    sym(botleft, botlcasing);
++    sym(botright, botrcasing);
++    maketriangle(&newbotleft);
++    maketriangle(&newbotright);
++
++    /* Set the vertices of changed and new triangles. */
++    org(horiz, rightpoint);
++    dest(horiz, leftpoint);
++    apex(horiz, botpoint);
++    setorg(newbotleft, leftpoint);
++    setdest(newbotleft, botpoint);
++    setapex(newbotleft, insertpoint);
++    setorg(newbotright, botpoint);
++    setdest(newbotright, rightpoint);
++    setapex(newbotright, insertpoint);
++    setapex(horiz, insertpoint);
++    for (i = 0; i < eextras; i++) {
++      /* Set the element attributes of the new triangles. */
++      attrib = elemattribute(horiz, i);
++      setelemattribute(newbotleft, i, attrib);
++      setelemattribute(newbotright, i, attrib);
++    }
++    if (vararea) {
++      /* Set the area constraint of the new triangles. */
++      area = areabound(horiz);
++      setareabound(newbotleft, area);
++      setareabound(newbotright, area);
++    }
++
++    /* There may be shell edges that need to be bonded */
++    /*   to the new triangles.                         */
++    if (checksegments) {
++      tspivot(botleft, botlshelle);
++      if (botlshelle.sh != dummysh) {
++        tsdissolve(botleft);
++        tsbond(newbotleft, botlshelle);
++      }
++      tspivot(botright, botrshelle);
++      if (botrshelle.sh != dummysh) {
++        tsdissolve(botright);
++        tsbond(newbotright, botrshelle);
++      }
++    }
++
++    /* Bond the new triangles to the surrounding triangles. */
++    bond(newbotleft, botlcasing);
++    bond(newbotright, botrcasing);
++    lnextself(newbotleft);
++    lprevself(newbotright);
++    bond(newbotleft, newbotright);
++    lnextself(newbotleft);
++    bond(botleft, newbotleft);
++    lprevself(newbotright);
++    bond(botright, newbotright);
++
++#ifdef SELF_CHECK
++    if (counterclockwise(rightpoint, leftpoint, botpoint) < 0.0) {
++      printf("Internal error in insertsite():\n");
++      printf("  Clockwise triangle prior to point insertion.\n");
++    }
++    if (counterclockwise(rightpoint, leftpoint, insertpoint) < 0.0) {
++      printf("Internal error in insertsite():\n");
++      printf("  Clockwise triangle after point insertion (top).\n");
++    }
++    if (counterclockwise(leftpoint, botpoint, insertpoint) < 0.0) {
++      printf("Internal error in insertsite():\n");
++      printf("  Clockwise triangle after point insertion (left).\n");
++    }
++    if (counterclockwise(botpoint, rightpoint, insertpoint) < 0.0) {
++      printf("Internal error in insertsite():\n");
++      printf("  Clockwise triangle after point insertion (right).\n");
++    }
++#endif /* SELF_CHECK */
++    if (verbose > 2) {
++      printf("  Updating top ");
++      printtriangle(&horiz);
++      printf("  Creating left ");
++      printtriangle(&newbotleft);
++      printf("  Creating right ");
++      printtriangle(&newbotright);
++    }
++  }
++
++  /* The insertion is successful by default, unless an encroached */
++  /*   edge is found.                                             */
++  success = SUCCESSFULPOINT;
++  /* Circle around the newly inserted vertex, checking each edge opposite */
++  /*   it for the Delaunay property.  Non-Delaunay edges are flipped.     */
++  /*   `horiz' is always the edge being checked.  `first' marks where to  */
++  /*   stop circling.                                                     */
++  org(horiz, first);
++  rightpoint = first;
++  dest(horiz, leftpoint);
++  /* Circle until finished. */
++  while (1) {
++    /* By default, the edge will be flipped. */
++    doflip = 1;
++    if (checksegments) {
++      /* Check for a segment, which cannot be flipped. */
++      tspivot(horiz, checkshelle);
++      if (checkshelle.sh != dummysh) {
++        /* The edge is a segment and cannot be flipped. */
++        doflip = 0;
++#ifndef CDT_ONLY
++        if (segmentflaws) {
++          /* Does the new point encroach upon this segment? */
++          if (checkedge4encroach(&checkshelle)) {
++            success = ENCROACHINGPOINT;
++          }
++        }
++#endif /* not CDT_ONLY */
++      }
++    }
++    if (doflip) {
++      /* Check if the edge is a boundary edge. */
++      sym(horiz, top);
++      if (top.tri == dummytri) {
++        /* The edge is a boundary edge and cannot be flipped. */
++        doflip = 0;
++      } else {
++        /* Find the point on the other side of the edge. */
++        apex(top, farpoint);
++        /* In the incremental Delaunay triangulation algorithm, any of    */
++        /*   `leftpoint', `rightpoint', and `farpoint' could be vertices  */
++        /*   of the triangular bounding box.  These vertices must be      */
++        /*   treated as if they are infinitely distant, even though their */
++        /*   "coordinates" are not.                                       */
++        if ((leftpoint == infpoint1) || (leftpoint == infpoint2)
++                   || (leftpoint == infpoint3)) {
++          /* `leftpoint' is infinitely distant.  Check the convexity of */
++          /*   the boundary of the triangulation.  'farpoint' might be  */
++          /*   infinite as well, but trust me, this same condition      */
++          /*   should be applied.                                       */
++          doflip = counterclockwise(insertpoint, rightpoint, farpoint) > 0.0;
++        } else if ((rightpoint == infpoint1) || (rightpoint == infpoint2)
++                   || (rightpoint == infpoint3)) {
++          /* `rightpoint' is infinitely distant.  Check the convexity of */
++          /*   the boundary of the triangulation.  'farpoint' might be  */
++          /*   infinite as well, but trust me, this same condition      */
++          /*   should be applied.                                       */
++          doflip = counterclockwise(farpoint, leftpoint, insertpoint) > 0.0;
++        } else if ((farpoint == infpoint1) || (farpoint == infpoint2)
++            || (farpoint == infpoint3)) {
++          /* `farpoint' is infinitely distant and cannot be inside */
++          /*   the circumcircle of the triangle `horiz'.           */
++          doflip = 0;
++        } else {
++          /* Test whether the edge is locally Delaunay. */
++          doflip = incircle(leftpoint, insertpoint, rightpoint, farpoint)
++                   > 0.0;
++        }
++        if (doflip) {
++          /* We made it!  Flip the edge `horiz' by rotating its containing */
++          /*   quadrilateral (the two triangles adjacent to `horiz').      */
++          /* Identify the casing of the quadrilateral. */
++          lprev(top, topleft);
++          sym(topleft, toplcasing);
++          lnext(top, topright);
++          sym(topright, toprcasing);
++          lnext(horiz, botleft);
++          sym(botleft, botlcasing);
++          lprev(horiz, botright);
++          sym(botright, botrcasing);
++          /* Rotate the quadrilateral one-quarter turn counterclockwise. */
++          bond(topleft, botlcasing);
++          bond(botleft, botrcasing);
++          bond(botright, toprcasing);
++          bond(topright, toplcasing);
++          if (checksegments) {
++            /* Check for shell edges and rebond them to the quadrilateral. */
++            tspivot(topleft, toplshelle);
++            tspivot(botleft, botlshelle);
++            tspivot(botright, botrshelle);
++            tspivot(topright, toprshelle);
++            if (toplshelle.sh == dummysh) {
++              tsdissolve(topright);
++            } else {
++              tsbond(topright, toplshelle);
++            }
++            if (botlshelle.sh == dummysh) {
++              tsdissolve(topleft);
++            } else {
++              tsbond(topleft, botlshelle);
++            }
++            if (botrshelle.sh == dummysh) {
++              tsdissolve(botleft);
++            } else {
++              tsbond(botleft, botrshelle);
++            }
++            if (toprshelle.sh == dummysh) {
++              tsdissolve(botright);
++            } else {
++              tsbond(botright, toprshelle);
++            }
++          }
++          /* New point assignments for the rotated quadrilateral. */
++          setorg(horiz, farpoint);
++          setdest(horiz, insertpoint);
++          setapex(horiz, rightpoint);
++          setorg(top, insertpoint);
++          setdest(top, farpoint);
++          setapex(top, leftpoint);
++          for (i = 0; i < eextras; i++) {
++            /* Take the average of the two triangles' attributes. */
++            attrib = 0.5 * (elemattribute(top, i) + elemattribute(horiz, i));
++            setelemattribute(top, i, attrib);
++            setelemattribute(horiz, i, attrib);
++          }
++          if (vararea) {
++            if ((areabound(top) <= 0.0) || (areabound(horiz) <= 0.0)) {
++              area = -1.0;
++            } else {
++              /* Take the average of the two triangles' area constraints.    */
++              /*   This prevents small area constraints from migrating a     */
++              /*   long, long way from their original location due to flips. */
++              area = 0.5 * (areabound(top) + areabound(horiz));
++            }
++            setareabound(top, area);
++            setareabound(horiz, area);
++          }
++#ifdef SELF_CHECK
++          if (insertpoint != (point) NULL) {
++            if (counterclockwise(leftpoint, insertpoint, rightpoint) < 0.0) {
++              printf("Internal error in insertsite():\n");
++              printf("  Clockwise triangle prior to edge flip (bottom).\n");
++            }
++            /* The following test has been removed because constrainededge() */
++            /*   sometimes generates inverted triangles that insertsite()    */
++            /*   removes.                                                    */
++/*
++            if (counterclockwise(rightpoint, farpoint, leftpoint) < 0.0) {
++              printf("Internal error in insertsite():\n");
++              printf("  Clockwise triangle prior to edge flip (top).\n");
++            }
++*/
++            if (counterclockwise(farpoint, leftpoint, insertpoint) < 0.0) {
++              printf("Internal error in insertsite():\n");
++              printf("  Clockwise triangle after edge flip (left).\n");
++            }
++            if (counterclockwise(insertpoint, rightpoint, farpoint) < 0.0) {
++              printf("Internal error in insertsite():\n");
++              printf("  Clockwise triangle after edge flip (right).\n");
++            }
++          }
++#endif /* SELF_CHECK */
++          if (verbose > 2) {
++            printf("  Edge flip results in left ");
++            lnextself(topleft);
++            printtriangle(&topleft);
++            printf("  and right ");
++            printtriangle(&horiz);
++          }
++          /* On the next iterations, consider the two edges that were  */
++          /*   exposed (this is, are now visible to the newly inserted */
++          /*   point) by the edge flip.                                */
++          lprevself(horiz);
++          leftpoint = farpoint;
++        }
++      }
++    }
++    if (!doflip) {
++      /* The handle `horiz' is accepted as locally Delaunay. */
++#ifndef CDT_ONLY
++      if (triflaws) {
++        /* Check the triangle `horiz' for quality. */
++        testtriangle(&horiz);
++      }
++#endif /* not CDT_ONLY */
++      /* Look for the next edge around the newly inserted point. */
++      lnextself(horiz);
++      sym(horiz, testtri);
++      /* Check for finishing a complete revolution about the new point, or */
++      /*   falling off the edge of the triangulation.  The latter will     */
++      /*   happen when a point is inserted at a boundary.                  */
++      if ((leftpoint == first) || (testtri.tri == dummytri)) {
++        /* We're done.  Return a triangle whose origin is the new point. */
++        lnext(horiz, *searchtri);
++        lnext(horiz, recenttri);
++        return success;
++      }
++      /* Finish finding the next edge around the newly inserted point. */
++      lnext(testtri, horiz);
++      rightpoint = leftpoint;
++      dest(horiz, leftpoint);
++    }
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  triangulatepolygon()   Find the Delaunay triangulation of a polygon that */
++/*                         has a certain "nice" shape.  This includes the    */
++/*                         polygons that result from deletion of a point or  */
++/*                         insertion of a segment.                           */
++/*                                                                           */
++/*  This is a conceptually difficult routine.  The starting assumption is    */
++/*  that we have a polygon with n sides.  n - 1 of these sides are currently */
++/*  represented as edges in the mesh.  One side, called the "base", need not */
++/*  be.                                                                      */
++/*                                                                           */
++/*  Inside the polygon is a structure I call a "fan", consisting of n - 1    */
++/*  triangles that share a common origin.  For each of these triangles, the  */
++/*  edge opposite the origin is one of the sides of the polygon.  The        */
++/*  primary edge of each triangle is the edge directed from the origin to    */
++/*  the destination; note that this is not the same edge that is a side of   */
++/*  the polygon.  `firstedge' is the primary edge of the first triangle.     */
++/*  From there, the triangles follow in counterclockwise order about the     */
++/*  polygon, until `lastedge', the primary edge of the last triangle.        */
++/*  `firstedge' and `lastedge' are probably connected to other triangles     */
++/*  beyond the extremes of the fan, but their identity is not important, as  */
++/*  long as the fan remains connected to them.                               */
++/*                                                                           */
++/*  Imagine the polygon oriented so that its base is at the bottom.  This    */
++/*  puts `firstedge' on the far right, and `lastedge' on the far left.       */
++/*  The right vertex of the base is the destination of `firstedge', and the  */
++/*  left vertex of the base is the apex of `lastedge'.                       */
++/*                                                                           */
++/*  The challenge now is to find the right sequence of edge flips to         */
++/*  transform the fan into a Delaunay triangulation of the polygon.  Each    */
++/*  edge flip effectively removes one triangle from the fan, committing it   */
++/*  to the polygon.  The resulting polygon has one fewer edge.  If `doflip'  */
++/*  is set, the final flip will be performed, resulting in a fan of one      */
++/*  (useless?) triangle.  If `doflip' is not set, the final flip is not      */
++/*  performed, resulting in a fan of two triangles, and an unfinished        */
++/*  triangular polygon that is not yet filled out with a single triangle.    */
++/*  On completion of the routine, `lastedge' is the last remaining triangle, */
++/*  or the leftmost of the last two.                                         */
++/*                                                                           */
++/*  Although the flips are performed in the order described above, the       */
++/*  decisions about what flips to perform are made in precisely the reverse  */
++/*  order.  The recursive triangulatepolygon() procedure makes a decision,   */
++/*  uses up to two recursive calls to triangulate the "subproblems"          */
++/*  (polygons with fewer edges), and then performs an edge flip.             */
++/*                                                                           */
++/*  The "decision" it makes is which vertex of the polygon should be         */
++/*  connected to the base.  This decision is made by testing every possible  */
++/*  vertex.  Once the best vertex is found, the two edges that connect this  */
++/*  vertex to the base become the bases for two smaller polygons.  These     */
++/*  are triangulated recursively.  Unfortunately, this approach can take     */
++/*  O(n^2) time not only in the worst case, but in many common cases.  It's  */
++/*  rarely a big deal for point deletion, where n is rarely larger than ten, */
++/*  but it could be a big deal for segment insertion, especially if there's  */
++/*  a lot of long segments that each cut many triangles.  I ought to code    */
++/*  a faster algorithm some time.                                            */
++/*                                                                           */
++/*  The `edgecount' parameter is the number of sides of the polygon,         */
++/*  including its base.  `triflaws' is a flag that determines whether the    */
++/*  new triangles should be tested for quality, and enqueued if they are     */
++/*  bad.                                                                     */
++/*                                                                           */
++/*****************************************************************************/
++
++void triangulatepolygon(firstedge, lastedge, edgecount, doflip, triflaws)
++struct triedge *firstedge;
++struct triedge *lastedge;
++int edgecount;
++int doflip;
++int triflaws;
++{
++  struct triedge testtri;
++  struct triedge besttri;
++  struct triedge tempedge;
++  point leftbasepoint, rightbasepoint;
++  point testpoint;
++  point bestpoint;
++  int bestnumber;
++  int i;
++  triangle ptr;   /* Temporary variable used by sym(), onext(), and oprev(). */
++
++  /* Identify the base vertices. */
++  apex(*lastedge, leftbasepoint);
++  dest(*firstedge, rightbasepoint);
++  if (verbose > 2) {
++    printf("  Triangulating interior polygon at edge\n");
++    printf("    (%.12g, %.12g) (%.12g, %.12g)\n", leftbasepoint[0],
++           leftbasepoint[1], rightbasepoint[0], rightbasepoint[1]);
++  }
++  /* Find the best vertex to connect the base to. */
++  onext(*firstedge, besttri);
++  dest(besttri, bestpoint);
++  triedgecopy(besttri, testtri);
++  bestnumber = 1;
++  for (i = 2; i <= edgecount - 2; i++) {
++    onextself(testtri);
++    dest(testtri, testpoint);
++    /* Is this a better vertex? */
++    if (incircle(leftbasepoint, rightbasepoint, bestpoint, testpoint) > 0.0) {
++      triedgecopy(testtri, besttri);
++      bestpoint = testpoint;
++      bestnumber = i;
++    }
++  }
++  if (verbose > 2) {
++    printf("    Connecting edge to (%.12g, %.12g)\n", bestpoint[0],
++           bestpoint[1]);
++  }
++  if (bestnumber > 1) {
++    /* Recursively triangulate the smaller polygon on the right. */
++    oprev(besttri, tempedge);
++    triangulatepolygon(firstedge, &tempedge, bestnumber + 1, 1, triflaws);
++  }
++  if (bestnumber < edgecount - 2) {
++    /* Recursively triangulate the smaller polygon on the left. */
++    sym(besttri, tempedge);
++    triangulatepolygon(&besttri, lastedge, edgecount - bestnumber, 1,
++                       triflaws);
++    /* Find `besttri' again; it may have been lost to edge flips. */
++    sym(tempedge, besttri);
++  }
++  if (doflip) {
++    /* Do one final edge flip. */
++    flip(&besttri);
++#ifndef CDT_ONLY
++    if (triflaws) {
++      /* Check the quality of the newly committed triangle. */
++      sym(besttri, testtri);
++      testtriangle(&testtri);
++    }
++#endif /* not CDT_ONLY */
++  }
++  /* Return the base triangle. */
++  triedgecopy(besttri, *lastedge);
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  deletesite()   Delete a vertex from a Delaunay triangulation, ensuring   */
++/*                 that the triangulation remains Delaunay.                  */
++/*                                                                           */
++/*  The origin of `deltri' is deleted.  The union of the triangles adjacent  */
++/*  to this point is a polygon, for which the Delaunay triangulation is      */
++/*  found.  Two triangles are removed from the mesh.                         */
++/*                                                                           */
++/*  Only interior points that do not lie on segments (shell edges) or        */
++/*  boundaries may be deleted.                                               */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++void deletesite(deltri)
++struct triedge *deltri;
++{
++  struct triedge countingtri;
++  struct triedge firstedge, lastedge;
++  struct triedge deltriright;
++  struct triedge lefttri, righttri;
++  struct triedge leftcasing, rightcasing;
++  struct edge leftshelle, rightshelle;
++  point delpoint;
++  point neworg;
++  int edgecount;
++  triangle ptr;   /* Temporary variable used by sym(), onext(), and oprev(). */
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  org(*deltri, delpoint);
++  if (verbose > 1) {
++    printf("  Deleting (%.12g, %.12g).\n", delpoint[0], delpoint[1]);
++  }
++  pointdealloc(delpoint);
++
++  /* Count the degree of the point being deleted. */
++  onext(*deltri, countingtri);
++  edgecount = 1;
++  while (!triedgeequal(*deltri, countingtri)) {
++#ifdef SELF_CHECK
++    if (countingtri.tri == dummytri) {
++      printf("Internal error in deletesite():\n");
++      printf("  Attempt to delete boundary point.\n");
++      internalerror();
++    }
++#endif /* SELF_CHECK */
++    edgecount++;
++    onextself(countingtri);
++  }
++
++#ifdef SELF_CHECK
++  if (edgecount < 3) {
++    printf("Internal error in deletesite():\n  Point has degree %d.\n",
++           edgecount);
++    internalerror();
++  }
++#endif /* SELF_CHECK */
++  if (edgecount > 3) {
++    /* Triangulate the polygon defined by the union of all triangles */
++    /*   adjacent to the point being deleted.  Check the quality of  */
++    /*   the resulting triangles.                                    */
++    onext(*deltri, firstedge);
++    oprev(*deltri, lastedge);
++    triangulatepolygon(&firstedge, &lastedge, edgecount, 0, !nobisect);
++  }
++  /* Splice out two triangles. */
++  lprev(*deltri, deltriright);
++  dnext(*deltri, lefttri);
++  sym(lefttri, leftcasing);
++  oprev(deltriright, righttri);
++  sym(righttri, rightcasing);
++  bond(*deltri, leftcasing);
++  bond(deltriright, rightcasing);
++  tspivot(lefttri, leftshelle);
++  if (leftshelle.sh != dummysh) {
++    tsbond(*deltri, leftshelle);
++  }
++  tspivot(righttri, rightshelle);
++  if (rightshelle.sh != dummysh) {
++    tsbond(deltriright, rightshelle);
++  }
++
++  /* Set the new origin of `deltri' and check its quality. */
++  org(lefttri, neworg);
++  setorg(*deltri, neworg);
++  if (!nobisect) {
++    testtriangle(deltri);
++  }
++
++  /* Delete the two spliced-out triangles. */
++  triangledealloc(lefttri.tri);
++  triangledealloc(righttri.tri);
++}
++
++#endif /* not CDT_ONLY */
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Mesh transformation routines end here                     *********/
++
++/********* Divide-and-conquer Delaunay triangulation begins here     *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  The divide-and-conquer bounding box                                      */
++/*                                                                           */
++/*  I originally implemented the divide-and-conquer and incremental Delaunay */
++/*  triangulations using the edge-based data structure presented by Guibas   */
++/*  and Stolfi.  Switching to a triangle-based data structure doubled the    */
++/*  speed.  However, I had to think of a few extra tricks to maintain the    */
++/*  elegance of the original algorithms.                                     */
++/*                                                                           */
++/*  The "bounding box" used by my variant of the divide-and-conquer          */
++/*  algorithm uses one triangle for each edge of the convex hull of the      */
++/*  triangulation.  These bounding triangles all share a common apical       */
++/*  vertex, which is represented by NULL and which represents nothing.       */
++/*  The bounding triangles are linked in a circular fan about this NULL      */
++/*  vertex, and the edges on the convex hull of the triangulation appear     */
++/*  opposite the NULL vertex.  You might find it easiest to imagine that     */
++/*  the NULL vertex is a point in 3D space behind the center of the          */
++/*  triangulation, and that the bounding triangles form a sort of cone.      */
++/*                                                                           */
++/*  This bounding box makes it easy to represent degenerate cases.  For      */
++/*  instance, the triangulation of two vertices is a single edge.  This edge */
++/*  is represented by two bounding box triangles, one on each "side" of the  */
++/*  edge.  These triangles are also linked together in a fan about the NULL  */
++/*  vertex.                                                                  */
++/*                                                                           */
++/*  The bounding box also makes it easy to traverse the convex hull, as the  */
++/*  divide-and-conquer algorithm needs to do.                                */
++/*                                                                           */
++/*****************************************************************************/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  pointsort()   Sort an array of points by x-coordinate, using the         */
++/*                y-coordinate as a secondary key.                           */
++/*                                                                           */
++/*  Uses quicksort.  Randomized O(n log n) time.  No, I did not make any of  */
++/*  the usual quicksort mistakes.                                            */
++/*                                                                           */
++/*****************************************************************************/
++
++void pointsort(sortarray, arraysize)
++point *sortarray;
++int arraysize;
++{
++  int left, right;
++  int pivot;
++  REAL pivotx, pivoty;
++  point temp;
++
++  if (arraysize == 2) {
++    /* Recursive base case. */
++    if ((sortarray[0][0] > sortarray[1][0]) ||
++        ((sortarray[0][0] == sortarray[1][0]) &&
++         (sortarray[0][1] > sortarray[1][1]))) {
++      temp = sortarray[1];
++      sortarray[1] = sortarray[0];
++      sortarray[0] = temp;
++    }
++    return;
++  }
++  /* Choose a random pivot to split the array. */
++  pivot = (int) randomnation(arraysize);
++  pivotx = sortarray[pivot][0];
++  pivoty = sortarray[pivot][1];
++  /* Split the array. */
++  left = -1;
++  right = arraysize;
++  while (left < right) {
++    /* Search for a point whose x-coordinate is too large for the left. */
++    do {
++      left++;
++    } while ((left <= right) && ((sortarray[left][0] < pivotx) ||
++                                 ((sortarray[left][0] == pivotx) &&
++                                  (sortarray[left][1] < pivoty))));
++    /* Search for a point whose x-coordinate is too small for the right. */
++    do {
++      right--;
++    } while ((left <= right) && ((sortarray[right][0] > pivotx) ||
++                                 ((sortarray[right][0] == pivotx) &&
++                                  (sortarray[right][1] > pivoty))));
++    if (left < right) {
++      /* Swap the left and right points. */
++      temp = sortarray[left];
++      sortarray[left] = sortarray[right];
++      sortarray[right] = temp;
++    }
++  }
++  if (left > 1) {
++    /* Recursively sort the left subset. */
++    pointsort(sortarray, left);
++  }
++  if (right < arraysize - 2) {
++    /* Recursively sort the right subset. */
++    pointsort(&sortarray[right + 1], arraysize - right - 1);
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  pointmedian()   An order statistic algorithm, almost.  Shuffles an array */
++/*                  of points so that the first `median' points occur        */
++/*                  lexicographically before the remaining points.           */
++/*                                                                           */
++/*  Uses the x-coordinate as the primary key if axis == 0; the y-coordinate  */
++/*  if axis == 1.  Very similar to the pointsort() procedure, but runs in    */
++/*  randomized linear time.                                                  */
++/*                                                                           */
++/*****************************************************************************/
++
++void pointmedian(sortarray, arraysize, median, axis)
++point *sortarray;
++int arraysize;
++int median;
++int axis;
++{
++  int left, right;
++  int pivot;
++  REAL pivot1, pivot2;
++  point temp;
++
++  if (arraysize == 2) {
++    /* Recursive base case. */
++    if ((sortarray[0][axis] > sortarray[1][axis]) ||
++        ((sortarray[0][axis] == sortarray[1][axis]) &&
++         (sortarray[0][1 - axis] > sortarray[1][1 - axis]))) {
++      temp = sortarray[1];
++      sortarray[1] = sortarray[0];
++      sortarray[0] = temp;
++    }
++    return;
++  }
++  /* Choose a random pivot to split the array. */
++  pivot = (int) randomnation(arraysize);
++  pivot1 = sortarray[pivot][axis];
++  pivot2 = sortarray[pivot][1 - axis];
++  /* Split the array. */
++  left = -1;
++  right = arraysize;
++  while (left < right) {
++    /* Search for a point whose x-coordinate is too large for the left. */
++    do {
++      left++;
++    } while ((left <= right) && ((sortarray[left][axis] < pivot1) ||
++                                 ((sortarray[left][axis] == pivot1) &&
++                                  (sortarray[left][1 - axis] < pivot2))));
++    /* Search for a point whose x-coordinate is too small for the right. */
++    do {
++      right--;
++    } while ((left <= right) && ((sortarray[right][axis] > pivot1) ||
++                                 ((sortarray[right][axis] == pivot1) &&
++                                  (sortarray[right][1 - axis] > pivot2))));
++    if (left < right) {
++      /* Swap the left and right points. */
++      temp = sortarray[left];
++      sortarray[left] = sortarray[right];
++      sortarray[right] = temp;
++    }
++  }
++  /* Unlike in pointsort(), at most one of the following */
++  /*   conditionals is true.                             */
++  if (left > median) {
++    /* Recursively shuffle the left subset. */
++    pointmedian(sortarray, left, median, axis);
++  }
++  if (right < median - 1) {
++    /* Recursively shuffle the right subset. */
++    pointmedian(&sortarray[right + 1], arraysize - right - 1,
++                median - right - 1, axis);
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  alternateaxes()   Sorts the points as appropriate for the divide-and-    */
++/*                    conquer algorithm with alternating cuts.               */
++/*                                                                           */
++/*  Partitions by x-coordinate if axis == 0; by y-coordinate if axis == 1.   */
++/*  For the base case, subsets containing only two or three points are       */
++/*  always sorted by x-coordinate.                                           */
++/*                                                                           */
++/*****************************************************************************/
++
++void alternateaxes(sortarray, arraysize, axis)
++point *sortarray;
++int arraysize;
++int axis;
++{
++  int divider;
++
++  divider = arraysize >> 1;
++  if (arraysize <= 3) {
++    /* Recursive base case:  subsets of two or three points will be      */
++    /*   handled specially, and should always be sorted by x-coordinate. */
++    axis = 0;
++  }
++  /* Partition with a horizontal or vertical cut. */
++  pointmedian(sortarray, arraysize, divider, axis);
++  /* Recursively partition the subsets with a cross cut. */
++  if (arraysize - divider >= 2) {
++    if (divider >= 2) {
++      alternateaxes(sortarray, divider, 1 - axis);
++    }
++    alternateaxes(&sortarray[divider], arraysize - divider, 1 - axis);
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  mergehulls()   Merge two adjacent Delaunay triangulations into a         */
++/*                 single Delaunay triangulation.                            */
++/*                                                                           */
++/*  This is similar to the algorithm given by Guibas and Stolfi, but uses    */
++/*  a triangle-based, rather than edge-based, data structure.                */
++/*                                                                           */
++/*  The algorithm walks up the gap between the two triangulations, knitting  */
++/*  them together.  As they are merged, some of their bounding triangles     */
++/*  are converted into real triangles of the triangulation.  The procedure   */
++/*  pulls each hull's bounding triangles apart, then knits them together     */
++/*  like the teeth of two gears.  The Delaunay property determines, at each  */
++/*  step, whether the next "tooth" is a bounding triangle of the left hull   */
++/*  or the right.  When a bounding triangle becomes real, its apex is        */
++/*  changed from NULL to a real point.                                       */
++/*                                                                           */
++/*  Only two new triangles need to be allocated.  These become new bounding  */
++/*  triangles at the top and bottom of the seam.  They are used to connect   */
++/*  the remaining bounding triangles (those that have not been converted     */
++/*  into real triangles) into a single fan.                                  */
++/*                                                                           */
++/*  On entry, `farleft' and `innerleft' are bounding triangles of the left   */
++/*  triangulation.  The origin of `farleft' is the leftmost vertex, and      */
++/*  the destination of `innerleft' is the rightmost vertex of the            */
++/*  triangulation.  Similarly, `innerright' and `farright' are bounding      */
++/*  triangles of the right triangulation.  The origin of `innerright' and    */
++/*  destination of `farright' are the leftmost and rightmost vertices.       */
++/*                                                                           */
++/*  On completion, the origin of `farleft' is the leftmost vertex of the     */
++/*  merged triangulation, and the destination of `farright' is the rightmost */
++/*  vertex.                                                                  */
++/*                                                                           */
++/*****************************************************************************/
++
++void mergehulls(farleft, innerleft, innerright, farright, axis)
++struct triedge *farleft;
++struct triedge *innerleft;
++struct triedge *innerright;
++struct triedge *farright;
++int axis;
++{
++  struct triedge leftcand, rightcand;
++  struct triedge baseedge;
++  struct triedge nextedge;
++  struct triedge sidecasing, topcasing, outercasing;
++  struct triedge checkedge;
++  point innerleftdest;
++  point innerrightorg;
++  point innerleftapex, innerrightapex;
++  point farleftpt, farrightpt;
++  point farleftapex, farrightapex;
++  point lowerleft, lowerright;
++  point upperleft, upperright;
++  point nextapex;
++  point checkvertex;
++  int changemade;
++  int badedge;
++  int leftfinished, rightfinished;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++
++  dest(*innerleft, innerleftdest);
++  apex(*innerleft, innerleftapex);
++  org(*innerright, innerrightorg);
++  apex(*innerright, innerrightapex);
++  /* Special treatment for horizontal cuts. */
++  if (dwyer && (axis == 1)) {
++    org(*farleft, farleftpt);
++    apex(*farleft, farleftapex);
++    dest(*farright, farrightpt);
++    apex(*farright, farrightapex);
++    /* The pointers to the extremal points are shifted to point to the */
++    /*   topmost and bottommost point of each hull, rather than the    */
++    /*   leftmost and rightmost points.                                */
++    while (farleftapex[1] < farleftpt[1]) {
++      lnextself(*farleft);
++      symself(*farleft);
++      farleftpt = farleftapex;
++      apex(*farleft, farleftapex);
++    }
++    sym(*innerleft, checkedge);
++    apex(checkedge, checkvertex);
++    while (checkvertex[1] > innerleftdest[1]) {
++      lnext(checkedge, *innerleft);
++      innerleftapex = innerleftdest;
++      innerleftdest = checkvertex;
++      sym(*innerleft, checkedge);
++      apex(checkedge, checkvertex);
++    }
++    while (innerrightapex[1] < innerrightorg[1]) {
++      lnextself(*innerright);
++      symself(*innerright);
++      innerrightorg = innerrightapex;
++      apex(*innerright, innerrightapex);
++    }
++    sym(*farright, checkedge);
++    apex(checkedge, checkvertex);
++    while (checkvertex[1] > farrightpt[1]) {
++      lnext(checkedge, *farright);
++      farrightapex = farrightpt;
++      farrightpt = checkvertex;
++      sym(*farright, checkedge);
++      apex(checkedge, checkvertex);
++    }
++  }
++  /* Find a line tangent to and below both hulls. */
++  do {
++    changemade = 0;
++    /* Make innerleftdest the "bottommost" point of the left hull. */
++    if (counterclockwise(innerleftdest, innerleftapex, innerrightorg) > 0.0) {
++      lprevself(*innerleft);
++      symself(*innerleft);
++      innerleftdest = innerleftapex;
++      apex(*innerleft, innerleftapex);
++      changemade = 1;
++    }
++    /* Make innerrightorg the "bottommost" point of the right hull. */
++    if (counterclockwise(innerrightapex, innerrightorg, innerleftdest) > 0.0) {
++      lnextself(*innerright);
++      symself(*innerright);
++      innerrightorg = innerrightapex;
++      apex(*innerright, innerrightapex);
++      changemade = 1;
++    }
++  } while (changemade);
++  /* Find the two candidates to be the next "gear tooth". */
++  sym(*innerleft, leftcand);
++  sym(*innerright, rightcand);
++  /* Create the bottom new bounding triangle. */
++  maketriangle(&baseedge);
++  /* Connect it to the bounding boxes of the left and right triangulations. */
++  bond(baseedge, *innerleft);
++  lnextself(baseedge);
++  bond(baseedge, *innerright);
++  lnextself(baseedge);
++  setorg(baseedge, innerrightorg);
++  setdest(baseedge, innerleftdest);
++  /* Apex is intentionally left NULL. */
++  if (verbose > 2) {
++    printf("  Creating base bounding ");
++    printtriangle(&baseedge);
++  }
++  /* Fix the extreme triangles if necessary. */
++  org(*farleft, farleftpt);
++  if (innerleftdest == farleftpt) {
++    lnext(baseedge, *farleft);
++  }
++  dest(*farright, farrightpt);
++  if (innerrightorg == farrightpt) {
++    lprev(baseedge, *farright);
++  }
++  /* The vertices of the current knitting edge. */
++  lowerleft = innerleftdest;
++  lowerright = innerrightorg;
++  /* The candidate vertices for knitting. */
++  apex(leftcand, upperleft);
++  apex(rightcand, upperright);
++  /* Walk up the gap between the two triangulations, knitting them together. */
++  while (1) {
++    /* Have we reached the top?  (This isn't quite the right question,       */
++    /*   because even though the left triangulation might seem finished now, */
++    /*   moving up on the right triangulation might reveal a new point of    */
++    /*   the left triangulation.  And vice-versa.)                           */
++    leftfinished = counterclockwise(upperleft, lowerleft, lowerright) <= 0.0;
++    rightfinished = counterclockwise(upperright, lowerleft, lowerright) <= 0.0;
++    if (leftfinished && rightfinished) {
++      /* Create the top new bounding triangle. */
++      maketriangle(&nextedge);
++      setorg(nextedge, lowerleft);
++      setdest(nextedge, lowerright);
++      /* Apex is intentionally left NULL. */
++      /* Connect it to the bounding boxes of the two triangulations. */
++      bond(nextedge, baseedge);
++      lnextself(nextedge);
++      bond(nextedge, rightcand);
++      lnextself(nextedge);
++      bond(nextedge, leftcand);
++      if (verbose > 2) {
++        printf("  Creating top bounding ");
++        printtriangle(&baseedge);
++      }
++      /* Special treatment for horizontal cuts. */
++      if (dwyer && (axis == 1)) {
++        org(*farleft, farleftpt);
++        apex(*farleft, farleftapex);
++        dest(*farright, farrightpt);
++        apex(*farright, farrightapex);
++        sym(*farleft, checkedge);
++        apex(checkedge, checkvertex);
++        /* The pointers to the extremal points are restored to the leftmost */
++        /*   and rightmost points (rather than topmost and bottommost).     */
++        while (checkvertex[0] < farleftpt[0]) {
++          lprev(checkedge, *farleft);
++          farleftapex = farleftpt;
++          farleftpt = checkvertex;
++          sym(*farleft, checkedge);
++          apex(checkedge, checkvertex);
++        }
++        while (farrightapex[0] > farrightpt[0]) {
++          lprevself(*farright);
++          symself(*farright);
++          farrightpt = farrightapex;
++          apex(*farright, farrightapex);
++        }
++      }
++      return;
++    }
++    /* Consider eliminating edges from the left triangulation. */
++    if (!leftfinished) {
++      /* What vertex would be exposed if an edge were deleted? */
++      lprev(leftcand, nextedge);
++      symself(nextedge);
++      apex(nextedge, nextapex);
++      /* If nextapex is NULL, then no vertex would be exposed; the */
++      /*   triangulation would have been eaten right through.      */
++      if (nextapex != (point) NULL) {
++        /* Check whether the edge is Delaunay. */
++        badedge = incircle(lowerleft, lowerright, upperleft, nextapex) > 0.0;
++        while (badedge) {
++          /* Eliminate the edge with an edge flip.  As a result, the    */
++          /*   left triangulation will have one more boundary triangle. */
++          lnextself(nextedge);
++          sym(nextedge, topcasing);
++          lnextself(nextedge);
++          sym(nextedge, sidecasing);
++          bond(nextedge, topcasing);
++          bond(leftcand, sidecasing);
++          lnextself(leftcand);
++          sym(leftcand, outercasing);
++          lprevself(nextedge);
++          bond(nextedge, outercasing);
++          /* Correct the vertices to reflect the edge flip. */
++          setorg(leftcand, lowerleft);
++          setdest(leftcand, NULL);
++          setapex(leftcand, nextapex);
++          setorg(nextedge, NULL);
++          setdest(nextedge, upperleft);
++          setapex(nextedge, nextapex);
++          /* Consider the newly exposed vertex. */
++          upperleft = nextapex;
++          /* What vertex would be exposed if another edge were deleted? */
++          triedgecopy(sidecasing, nextedge);
++          apex(nextedge, nextapex);
++          if (nextapex != (point) NULL) {
++            /* Check whether the edge is Delaunay. */
++            badedge = incircle(lowerleft, lowerright, upperleft, nextapex)
++                      > 0.0;
++          } else {
++            /* Avoid eating right through the triangulation. */
++            badedge = 0;
++          }
++        }
++      }
++    }
++    /* Consider eliminating edges from the right triangulation. */
++    if (!rightfinished) {
++      /* What vertex would be exposed if an edge were deleted? */
++      lnext(rightcand, nextedge);
++      symself(nextedge);
++      apex(nextedge, nextapex);
++      /* If nextapex is NULL, then no vertex would be exposed; the */
++      /*   triangulation would have been eaten right through.      */
++      if (nextapex != (point) NULL) {
++        /* Check whether the edge is Delaunay. */
++        badedge = incircle(lowerleft, lowerright, upperright, nextapex) > 0.0;
++        while (badedge) {
++          /* Eliminate the edge with an edge flip.  As a result, the     */
++          /*   right triangulation will have one more boundary triangle. */
++          lprevself(nextedge);
++          sym(nextedge, topcasing);
++          lprevself(nextedge);
++          sym(nextedge, sidecasing);
++          bond(nextedge, topcasing);
++          bond(rightcand, sidecasing);
++          lprevself(rightcand);
++          sym(rightcand, outercasing);
++          lnextself(nextedge);
++          bond(nextedge, outercasing);
++          /* Correct the vertices to reflect the edge flip. */
++          setorg(rightcand, NULL);
++          setdest(rightcand, lowerright);
++          setapex(rightcand, nextapex);
++          setorg(nextedge, upperright);
++          setdest(nextedge, NULL);
++          setapex(nextedge, nextapex);
++          /* Consider the newly exposed vertex. */
++          upperright = nextapex;
++          /* What vertex would be exposed if another edge were deleted? */
++          triedgecopy(sidecasing, nextedge);
++          apex(nextedge, nextapex);
++          if (nextapex != (point) NULL) {
++            /* Check whether the edge is Delaunay. */
++            badedge = incircle(lowerleft, lowerright, upperright, nextapex)
++                      > 0.0;
++          } else {
++            /* Avoid eating right through the triangulation. */
++            badedge = 0;
++          }
++        }
++      }
++    }
++    if (leftfinished || (!rightfinished &&
++           (incircle(upperleft, lowerleft, lowerright, upperright) > 0.0))) {
++      /* Knit the triangulations, adding an edge from `lowerleft' */
++      /*   to `upperright'.                                       */
++      bond(baseedge, rightcand);
++      lprev(rightcand, baseedge);
++      setdest(baseedge, lowerleft);
++      lowerright = upperright;
++      sym(baseedge, rightcand);
++      apex(rightcand, upperright);
++    } else {
++      /* Knit the triangulations, adding an edge from `upperleft' */
++      /*   to `lowerright'.                                       */
++      bond(baseedge, leftcand);
++      lnext(leftcand, baseedge);
++      setorg(baseedge, lowerright);
++      lowerleft = upperleft;
++      sym(baseedge, leftcand);
++      apex(leftcand, upperleft);
++    }
++    if (verbose > 2) {
++      printf("  Connecting ");
++      printtriangle(&baseedge);
++    }
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  divconqrecurse()   Recursively form a Delaunay triangulation by the      */
++/*                     divide-and-conquer method.                            */
++/*                                                                           */
++/*  Recursively breaks down the problem into smaller pieces, which are       */
++/*  knitted together by mergehulls().  The base cases (problems of two or    */
++/*  three points) are handled specially here.                                */
++/*                                                                           */
++/*  On completion, `farleft' and `farright' are bounding triangles such that */
++/*  the origin of `farleft' is the leftmost vertex (breaking ties by         */
++/*  choosing the highest leftmost vertex), and the destination of            */
++/*  `farright' is the rightmost vertex (breaking ties by choosing the        */
++/*  lowest rightmost vertex).                                                */
++/*                                                                           */
++/*****************************************************************************/
++
++void divconqrecurse(sortarray, vertices, axis, farleft, farright)
++point *sortarray;
++int vertices;
++int axis;
++struct triedge *farleft;
++struct triedge *farright;
++{
++  struct triedge midtri, tri1, tri2, tri3;
++  struct triedge innerleft, innerright;
++  REAL area;
++  int divider;
++
++  if (verbose > 2) {
++    printf("  Triangulating %d points.\n", vertices);
++  }
++  if (vertices == 2) {
++    /* The triangulation of two vertices is an edge.  An edge is */
++    /*   represented by two bounding triangles.                  */
++    maketriangle(farleft);
++    setorg(*farleft, sortarray[0]);
++    setdest(*farleft, sortarray[1]);
++    /* The apex is intentionally left NULL. */
++    maketriangle(farright);
++    setorg(*farright, sortarray[1]);
++    setdest(*farright, sortarray[0]);
++    /* The apex is intentionally left NULL. */
++    bond(*farleft, *farright);
++    lprevself(*farleft);
++    lnextself(*farright);
++    bond(*farleft, *farright);
++    lprevself(*farleft);
++    lnextself(*farright);
++    bond(*farleft, *farright);
++    if (verbose > 2) {
++      printf("  Creating ");
++      printtriangle(farleft);
++      printf("  Creating ");
++      printtriangle(farright);
++    }
++    /* Ensure that the origin of `farleft' is sortarray[0]. */
++    lprev(*farright, *farleft);
++    return;
++  } else if (vertices == 3) {
++    /* The triangulation of three vertices is either a triangle (with */
++    /*   three bounding triangles) or two edges (with four bounding   */
++    /*   triangles).  In either case, four triangles are created.     */
++    maketriangle(&midtri);
++    maketriangle(&tri1);
++    maketriangle(&tri2);
++    maketriangle(&tri3);
++    area = counterclockwise(sortarray[0], sortarray[1], sortarray[2]);
++    if (area == 0.0) {
++      /* Three collinear points; the triangulation is two edges. */
++      setorg(midtri, sortarray[0]);
++      setdest(midtri, sortarray[1]);
++      setorg(tri1, sortarray[1]);
++      setdest(tri1, sortarray[0]);
++      setorg(tri2, sortarray[2]);
++      setdest(tri2, sortarray[1]);
++      setorg(tri3, sortarray[1]);
++      setdest(tri3, sortarray[2]);
++      /* All apices are intentionally left NULL. */
++      bond(midtri, tri1);
++      bond(tri2, tri3);
++      lnextself(midtri);
++      lprevself(tri1);
++      lnextself(tri2);
++      lprevself(tri3);
++      bond(midtri, tri3);
++      bond(tri1, tri2);
++      lnextself(midtri);
++      lprevself(tri1);
++      lnextself(tri2);
++      lprevself(tri3);
++      bond(midtri, tri1);
++      bond(tri2, tri3);
++      /* Ensure that the origin of `farleft' is sortarray[0]. */
++      triedgecopy(tri1, *farleft);
++      /* Ensure that the destination of `farright' is sortarray[2]. */
++      triedgecopy(tri2, *farright);
++    } else {
++      /* The three points are not collinear; the triangulation is one */
++      /*   triangle, namely `midtri'.                                 */
++      setorg(midtri, sortarray[0]);
++      setdest(tri1, sortarray[0]);
++      setorg(tri3, sortarray[0]);
++      /* Apices of tri1, tri2, and tri3 are left NULL. */
++      if (area > 0.0) {
++        /* The vertices are in counterclockwise order. */
++        setdest(midtri, sortarray[1]);
++        setorg(tri1, sortarray[1]);
++        setdest(tri2, sortarray[1]);
++        setapex(midtri, sortarray[2]);
++        setorg(tri2, sortarray[2]);
++        setdest(tri3, sortarray[2]);
++      } else {
++        /* The vertices are in clockwise order. */
++        setdest(midtri, sortarray[2]);
++        setorg(tri1, sortarray[2]);
++        setdest(tri2, sortarray[2]);
++        setapex(midtri, sortarray[1]);
++        setorg(tri2, sortarray[1]);
++        setdest(tri3, sortarray[1]);
++      }
++      /* The topology does not depend on how the vertices are ordered. */
++      bond(midtri, tri1);
++      lnextself(midtri);
++      bond(midtri, tri2);
++      lnextself(midtri);
++      bond(midtri, tri3);
++      lprevself(tri1);
++      lnextself(tri2);
++      bond(tri1, tri2);
++      lprevself(tri1);
++      lprevself(tri3);
++      bond(tri1, tri3);
++      lnextself(tri2);
++      lprevself(tri3);
++      bond(tri2, tri3);
++      /* Ensure that the origin of `farleft' is sortarray[0]. */
++      triedgecopy(tri1, *farleft);
++      /* Ensure that the destination of `farright' is sortarray[2]. */
++      if (area > 0.0) {
++        triedgecopy(tri2, *farright);
++      } else {
++        lnext(*farleft, *farright);
++      }
++    }
++    if (verbose > 2) {
++      printf("  Creating ");
++      printtriangle(&midtri);
++      printf("  Creating ");
++      printtriangle(&tri1);
++      printf("  Creating ");
++      printtriangle(&tri2);
++      printf("  Creating ");
++      printtriangle(&tri3);
++    }
++    return;
++  } else {
++    /* Split the vertices in half. */
++    divider = vertices >> 1;
++    /* Recursively triangulate each half. */
++    divconqrecurse(sortarray, divider, 1 - axis, farleft, &innerleft);
++    divconqrecurse(&sortarray[divider], vertices - divider, 1 - axis,
++                   &innerright, farright);
++    if (verbose > 1) {
++      printf("  Joining triangulations with %d and %d vertices.\n", divider,
++             vertices - divider);
++    }
++    /* Merge the two triangulations into one. */
++    mergehulls(farleft, &innerleft, &innerright, farright, axis);
++  }
++}
++
++long removeghosts(startghost)
++struct triedge *startghost;
++{
++  struct triedge searchedge;
++  struct triedge dissolveedge;
++  struct triedge deadtri;
++  point markorg;
++  long hullsize;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++
++  if (verbose) {
++    printf("  Removing ghost triangles.\n");
++  }
++  /* Find an edge on the convex hull to start point location from. */
++  lprev(*startghost, searchedge);
++  symself(searchedge);
++  dummytri[0] = encode(searchedge);
++  /* Remove the bounding box and count the convex hull edges. */
++  triedgecopy(*startghost, dissolveedge);
++  hullsize = 0;
++  do {
++    hullsize++;
++    lnext(dissolveedge, deadtri);
++    lprevself(dissolveedge);
++    symself(dissolveedge);
++    /* If no PSLG is involved, set the boundary markers of all the points */
++    /*   on the convex hull.  If a PSLG is used, this step is done later. */
++    if (!poly) {
++      /* Watch out for the case where all the input points are collinear. */
++      if (dissolveedge.tri != dummytri) {
++        org(dissolveedge, markorg);
++        if (pointmark(markorg) == 0) {
++          setpointmark(markorg, 1);
++        }
++      }
++    }
++    /* Remove a bounding triangle from a convex hull triangle. */
++    dissolve(dissolveedge);
++    /* Find the next bounding triangle. */
++    sym(deadtri, dissolveedge);
++    /* Delete the bounding triangle. */
++    triangledealloc(deadtri.tri);
++  } while (!triedgeequal(dissolveedge, *startghost));
++  return hullsize;
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  divconqdelaunay()   Form a Delaunay triangulation by the divide-and-     */
++/*                      conquer method.                                      */
++/*                                                                           */
++/*  Sorts the points, calls a recursive procedure to triangulate them, and   */
++/*  removes the bounding box, setting boundary markers as appropriate.       */
++/*                                                                           */
++/*****************************************************************************/
++
++long divconqdelaunay()
++{
++  point *sortarray;
++  struct triedge hullleft, hullright;
++  int divider;
++  int i, j;
++
++  /* Allocate an array of pointers to points for sorting. */
++  sortarray = (point *) malloc(inpoints * sizeof(point));
++  if (sortarray == (point *) NULL) {
++    printf("Error:  Out of memory.\n");
++    exit(1);
++  }
++  traversalinit(&points);
++  for (i = 0; i < inpoints; i++) {
++    sortarray[i] = pointtraverse();
++  }
++  if (verbose) {
++    printf("  Sorting points.\n");
++  }
++  /* Sort the points. */
++  pointsort(sortarray, inpoints);
++  /* Discard duplicate points, which can really mess up the algorithm. */
++  i = 0;
++  for (j = 1; j < inpoints; j++) {
++    if ((sortarray[i][0] == sortarray[j][0])
++        && (sortarray[i][1] == sortarray[j][1])) {
++      if (!quiet) {
++        printf(
++"Warning:  A duplicate point at (%.12g, %.12g) appeared and was ignored.\n",
++               sortarray[j][0], sortarray[j][1]);
++      }
++/*  Commented out - would eliminate point from output .node file, but causes
++    a failure if some segment has this point as an endpoint.
++      setpointmark(sortarray[j], DEADPOINT);
++*/
++    } else {
++      i++;
++      sortarray[i] = sortarray[j];
++    }
++  }
++  i++;
++  if (dwyer) {
++    /* Re-sort the array of points to accommodate alternating cuts. */
++    divider = i >> 1;
++    if (i - divider >= 2) {
++      if (divider >= 2) {
++        alternateaxes(sortarray, divider, 1);
++      }
++      alternateaxes(&sortarray[divider], i - divider, 1);
++    }
++  }
++  if (verbose) {
++    printf("  Forming triangulation.\n");
++  }
++  /* Form the Delaunay triangulation. */
++  divconqrecurse(sortarray, i, 0, &hullleft, &hullright);
++  free(sortarray);
++
++  return removeghosts(&hullleft);
++}
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Divide-and-conquer Delaunay triangulation ends here       *********/
++
++/********* Incremental Delaunay triangulation begins here            *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  boundingbox()   Form an "infinite" bounding triangle to insert points    */
++/*                  into.                                                    */
++/*                                                                           */
++/*  The points at "infinity" are assigned finite coordinates, which are used */
++/*  by the point location routines, but (mostly) ignored by the Delaunay     */
++/*  edge flip routines.                                                      */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef REDUCED
++
++void boundingbox()
++{
++  struct triedge inftri;          /* Handle for the triangular bounding box. */
++  REAL width;
++
++  if (verbose) {
++    printf("  Creating triangular bounding box.\n");
++  }
++  /* Find the width (or height, whichever is larger) of the triangulation. */
++  width = xmax - xmin;
++  if (ymax - ymin > width) {
++    width = ymax - ymin;
++  }
++  if (width == 0.0) {
++    width = 1.0;
++  }
++  /* Create the vertices of the bounding box. */
++  infpoint1 = (point) malloc(points.itembytes);
++  infpoint2 = (point) malloc(points.itembytes);
++  infpoint3 = (point) malloc(points.itembytes);
++  if ((infpoint1 == (point) NULL) || (infpoint2 == (point) NULL)
++      || (infpoint3 == (point) NULL)) {
++    printf("Error:  Out of memory.\n");
++    exit(1);
++  }
++  infpoint1[0] = xmin - 50.0 * width;
++  infpoint1[1] = ymin - 40.0 * width;
++  infpoint2[0] = xmax + 50.0 * width;
++  infpoint2[1] = ymin - 40.0 * width;
++  infpoint3[0] = 0.5 * (xmin + xmax);
++  infpoint3[1] = ymax + 60.0 * width;
++
++  /* Create the bounding box. */
++  maketriangle(&inftri);
++  setorg(inftri, infpoint1);
++  setdest(inftri, infpoint2);
++  setapex(inftri, infpoint3);
++  /* Link dummytri to the bounding box so we can always find an */
++  /*   edge to begin searching (point location) from.           */
++  dummytri[0] = (triangle) inftri.tri;
++  if (verbose > 2) {
++    printf("  Creating ");
++    printtriangle(&inftri);
++  }
++}
++
++#endif /* not REDUCED */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  removebox()   Remove the "infinite" bounding triangle, setting boundary  */
++/*                markers as appropriate.                                    */
++/*                                                                           */
++/*  The triangular bounding box has three boundary triangles (one for each   */
++/*  side of the bounding box), and a bunch of triangles fanning out from     */
++/*  the three bounding box vertices (one triangle for each edge of the       */
++/*  convex hull of the inner mesh).  This routine removes these triangles.   */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef REDUCED
++
++long removebox()
++{
++  struct triedge deadtri;
++  struct triedge searchedge;
++  struct triedge checkedge;
++  struct triedge nextedge, finaledge, dissolveedge;
++  point markorg;
++  long hullsize;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++
++  if (verbose) {
++    printf("  Removing triangular bounding box.\n");
++  }
++  /* Find a boundary triangle. */
++  nextedge.tri = dummytri;
++  nextedge.orient = 0;
++  symself(nextedge);
++  /* Mark a place to stop. */
++  lprev(nextedge, finaledge);
++  lnextself(nextedge);
++  symself(nextedge);
++  /* Find a triangle (on the boundary of the point set) that isn't */
++  /*   a bounding box triangle.                                    */
++  lprev(nextedge, searchedge);
++  symself(searchedge);
++  /* Check whether nextedge is another boundary triangle */
++  /*   adjacent to the first one.                        */
++  lnext(nextedge, checkedge);
++  symself(checkedge);
++  if (checkedge.tri == dummytri) {
++    /* Go on to the next triangle.  There are only three boundary   */
++    /*   triangles, and this next triangle cannot be the third one, */
++    /*   so it's safe to stop here.                                 */
++    lprevself(searchedge);
++    symself(searchedge);
++  }
++  /* Find a new boundary edge to search from, as the current search */
++  /*   edge lies on a bounding box triangle and will be deleted.    */
++  dummytri[0] = encode(searchedge);
++  hullsize = -2l;
++  while (!triedgeequal(nextedge, finaledge)) {
++    hullsize++;
++    lprev(nextedge, dissolveedge);
++    symself(dissolveedge);
++    /* If not using a PSLG, the vertices should be marked now. */
++    /*   (If using a PSLG, markhull() will do the job.)        */
++    if (!poly) {
++      /* Be careful!  One must check for the case where all the input   */
++      /*   points are collinear, and thus all the triangles are part of */
++      /*   the bounding box.  Otherwise, the setpointmark() call below  */
++      /*   will cause a bad pointer reference.                          */
++      if (dissolveedge.tri != dummytri) {
++        org(dissolveedge, markorg);
++        if (pointmark(markorg) == 0) {
++          setpointmark(markorg, 1);
++        }
++      }
++    }
++    /* Disconnect the bounding box triangle from the mesh triangle. */
++    dissolve(dissolveedge);
++    lnext(nextedge, deadtri);
++    sym(deadtri, nextedge);
++    /* Get rid of the bounding box triangle. */
++    triangledealloc(deadtri.tri);
++    /* Do we need to turn the corner? */
++    if (nextedge.tri == dummytri) {
++      /* Turn the corner. */
++      triedgecopy(dissolveedge, nextedge);
++    }
++  }
++  triangledealloc(finaledge.tri);
++
++  free(infpoint1);                  /* Deallocate the bounding box vertices. */
++  free(infpoint2);
++  free(infpoint3);
++
++  return hullsize;
++}
++
++#endif /* not REDUCED */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  incrementaldelaunay()   Form a Delaunay triangulation by incrementally   */
++/*                          adding vertices.                                 */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef REDUCED
++
++long incrementaldelaunay()
++{
++  struct triedge starttri;
++  point pointloop;
++  int i;
++
++  /* Create a triangular bounding box. */
++  boundingbox();
++  if (verbose) {
++    printf("  Incrementally inserting points.\n");
++  }
++  traversalinit(&points);
++  pointloop = pointtraverse();
++  i = 1;
++  while (pointloop != (point) NULL) {
++    /* Find a boundary triangle to search from. */
++    starttri.tri = (triangle *) NULL;
++    if (insertsite(pointloop, &starttri, (struct edge *) NULL, 0, 0) ==
++        DUPLICATEPOINT) {
++      if (!quiet) {
++        printf(
++"Warning:  A duplicate point at (%.12g, %.12g) appeared and was ignored.\n",
++               pointloop[0], pointloop[1]);
++      }
++/*  Commented out - would eliminate point from output .node file.
++      setpointmark(pointloop, DEADPOINT);
++*/
++    }
++    pointloop = pointtraverse();
++    i++;
++  }
++  /* Remove the bounding box. */
++  return removebox();
++}
++
++#endif /* not REDUCED */
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Incremental Delaunay triangulation ends here              *********/
++
++/********* Sweepline Delaunay triangulation begins here              *********/
++/**                                                                         **/
++/**                                                                         **/
++
++#ifndef REDUCED
++
++void eventheapinsert(heap, heapsize, newevent)
++struct event **heap;
++int heapsize;
++struct event *newevent;
++{
++  REAL eventx, eventy;
++  int eventnum;
++  int parent;
++  int notdone;
++
++  eventx = newevent->xkey;
++  eventy = newevent->ykey;
++  eventnum = heapsize;
++  notdone = eventnum > 0;
++  while (notdone) {
++    parent = (eventnum - 1) >> 1;
++    if ((heap[parent]->ykey < eventy) ||
++        ((heap[parent]->ykey == eventy)
++         && (heap[parent]->xkey <= eventx))) {
++      notdone = 0;
++    } else {
++      heap[eventnum] = heap[parent];
++      heap[eventnum]->heapposition = eventnum;
++
++      eventnum = parent;
++      notdone = eventnum > 0;
++    }
++  }
++  heap[eventnum] = newevent;
++  newevent->heapposition = eventnum;
++}
++
++#endif /* not REDUCED */
++
++#ifndef REDUCED
++
++void eventheapify(heap, heapsize, eventnum)
++struct event **heap;
++int heapsize;
++int eventnum;
++{
++  struct event *thisevent;
++  REAL eventx, eventy;
++  int leftchild, rightchild;
++  int smallest;
++  int notdone;
++
++  thisevent = heap[eventnum];
++  eventx = thisevent->xkey;
++  eventy = thisevent->ykey;
++  leftchild = 2 * eventnum + 1;
++  notdone = leftchild < heapsize;
++  while (notdone) {
++    if ((heap[leftchild]->ykey < eventy) ||
++        ((heap[leftchild]->ykey == eventy)
++         && (heap[leftchild]->xkey < eventx))) {
++      smallest = leftchild;
++    } else {
++      smallest = eventnum;
++    }
++    rightchild = leftchild + 1;
++    if (rightchild < heapsize) {
++      if ((heap[rightchild]->ykey < heap[smallest]->ykey) ||
++          ((heap[rightchild]->ykey == heap[smallest]->ykey)
++           && (heap[rightchild]->xkey < heap[smallest]->xkey))) {
++        smallest = rightchild;
++      }
++    }
++    if (smallest == eventnum) {
++      notdone = 0;
++    } else {
++      heap[eventnum] = heap[smallest];
++      heap[eventnum]->heapposition = eventnum;
++      heap[smallest] = thisevent;
++      thisevent->heapposition = smallest;
++
++      eventnum = smallest;
++      leftchild = 2 * eventnum + 1;
++      notdone = leftchild < heapsize;
++    }
++  }
++}
++
++#endif /* not REDUCED */
++
++#ifndef REDUCED
++
++void eventheapdelete(heap, heapsize, eventnum)
++struct event **heap;
++int heapsize;
++int eventnum;
++{
++  struct event *moveevent;
++  REAL eventx, eventy;
++  int parent;
++  int notdone;
++
++  moveevent = heap[heapsize - 1];
++  if (eventnum > 0) {
++    eventx = moveevent->xkey;
++    eventy = moveevent->ykey;
++    do {
++      parent = (eventnum - 1) >> 1;
++      if ((heap[parent]->ykey < eventy) ||
++          ((heap[parent]->ykey == eventy)
++           && (heap[parent]->xkey <= eventx))) {
++        notdone = 0;
++      } else {
++        heap[eventnum] = heap[parent];
++        heap[eventnum]->heapposition = eventnum;
++
++        eventnum = parent;
++        notdone = eventnum > 0;
++      }
++    } while (notdone);
++  }
++  heap[eventnum] = moveevent;
++  moveevent->heapposition = eventnum;
++  eventheapify(heap, heapsize - 1, eventnum);
++}
++
++#endif /* not REDUCED */
++
++#ifndef REDUCED
++
++void createeventheap(eventheap, events, freeevents)
++struct event ***eventheap;
++struct event **events;
++struct event **freeevents;
++{
++  point thispoint;
++  int maxevents;
++  int i;
++
++  maxevents = (3 * inpoints) / 2;
++  *eventheap = (struct event **) malloc(maxevents * sizeof(struct event *));
++  if (*eventheap == (struct event **) NULL) {
++    printf("Error:  Out of memory.\n");
++    exit(1);
++  }
++  *events = (struct event *) malloc(maxevents * sizeof(struct event));
++  if (*events == (struct event *) NULL) {
++    printf("Error:  Out of memory.\n");
++    exit(1);
++  }
++  traversalinit(&points);
++  for (i = 0; i < inpoints; i++) {
++    thispoint = pointtraverse();
++    (*events)[i].eventptr = (VOID *) thispoint;
++    (*events)[i].xkey = thispoint[0];
++    (*events)[i].ykey = thispoint[1];
++    eventheapinsert(*eventheap, i, *events + i);
++  }
++  *freeevents = (struct event *) NULL;
++  for (i = maxevents - 1; i >= inpoints; i--) {
++    (*events)[i].eventptr = (VOID *) *freeevents;
++    *freeevents = *events + i;
++  }
++}
++
++#endif /* not REDUCED */
++
++#ifndef REDUCED
++
++int rightofhyperbola(fronttri, newsite)
++struct triedge *fronttri;
++point newsite;
++{
++  point leftpoint, rightpoint;
++  REAL dxa, dya, dxb, dyb;
++
++  hyperbolacount++;
++
++  dest(*fronttri, leftpoint);
++  apex(*fronttri, rightpoint);
++  if ((leftpoint[1] < rightpoint[1])
++      || ((leftpoint[1] == rightpoint[1]) && (leftpoint[0] < rightpoint[0]))) {
++    if (newsite[0] >= rightpoint[0]) {
++      return 1;
++    }
++  } else {
++    if (newsite[0] <= leftpoint[0]) {
++      return 0;
++    }
++  }
++  dxa = leftpoint[0] - newsite[0];
++  dya = leftpoint[1] - newsite[1];
++  dxb = rightpoint[0] - newsite[0];
++  dyb = rightpoint[1] - newsite[1];
++  return dya * (dxb * dxb + dyb * dyb) > dyb * (dxa * dxa + dya * dya);
++}
++
++#endif /* not REDUCED */
++
++#ifndef REDUCED
++
++REAL circletop(pa, pb, pc, ccwabc)
++point pa;
++point pb;
++point pc;
++REAL ccwabc;
++{
++  REAL xac, yac, xbc, ybc, xab, yab;
++  REAL aclen2, bclen2, ablen2;
++
++  circletopcount++;
++
++  xac = pa[0] - pc[0];
++  yac = pa[1] - pc[1];
++  xbc = pb[0] - pc[0];
++  ybc = pb[1] - pc[1];
++  xab = pa[0] - pb[0];
++  yab = pa[1] - pb[1];
++  aclen2 = xac * xac + yac * yac;
++  bclen2 = xbc * xbc + ybc * ybc;
++  ablen2 = xab * xab + yab * yab;
++  return pc[1] + (xac * bclen2 - xbc * aclen2 + sqrt(aclen2 * bclen2 * ablen2))
++               / (2.0 * ccwabc);
++}
++
++#endif /* not REDUCED */
++
++#ifndef REDUCED
++
++void check4deadevent(checktri, freeevents, eventheap, heapsize)
++struct triedge *checktri;
++struct event **freeevents;
++struct event **eventheap;
++int *heapsize;
++{
++  struct event *deadevent;
++  point eventpoint;
++  int eventnum;
++
++  org(*checktri, eventpoint);
++  if (eventpoint != (point) NULL) {
++    deadevent = (struct event *) eventpoint;
++    eventnum = deadevent->heapposition;
++    deadevent->eventptr = (VOID *) *freeevents;
++    *freeevents = deadevent;
++    eventheapdelete(eventheap, *heapsize, eventnum);
++    (*heapsize)--;
++    setorg(*checktri, NULL);
++  }
++}
++
++#endif /* not REDUCED */
++
++#ifndef REDUCED
++
++struct splaynode *splay(splaytree, searchpoint, searchtri)
++struct splaynode *splaytree;
++point searchpoint;
++struct triedge *searchtri;
++{
++  struct splaynode *child, *grandchild;
++  struct splaynode *lefttree, *righttree;
++  struct splaynode *leftright;
++  point checkpoint;
++  int rightofroot, rightofchild;
++
++  if (splaytree == (struct splaynode *) NULL) {
++    return (struct splaynode *) NULL;
++  }
++  dest(splaytree->keyedge, checkpoint);
++  if (checkpoint == splaytree->keydest) {
++    rightofroot = rightofhyperbola(&splaytree->keyedge, searchpoint);
++    if (rightofroot) {
++      triedgecopy(splaytree->keyedge, *searchtri);
++      child = splaytree->rchild;
++    } else {
++      child = splaytree->lchild;
++    }
++    if (child == (struct splaynode *) NULL) {
++      return splaytree;
++    }
++    dest(child->keyedge, checkpoint);
++    if (checkpoint != child->keydest) {
++      child = splay(child, searchpoint, searchtri);
++      if (child == (struct splaynode *) NULL) {
++        if (rightofroot) {
++          splaytree->rchild = (struct splaynode *) NULL;
++        } else {
++          splaytree->lchild = (struct splaynode *) NULL;
++        }
++        return splaytree;
++      }
++    }
++    rightofchild = rightofhyperbola(&child->keyedge, searchpoint);
++    if (rightofchild) {
++      triedgecopy(child->keyedge, *searchtri);
++      grandchild = splay(child->rchild, searchpoint, searchtri);
++      child->rchild = grandchild;
++    } else {
++      grandchild = splay(child->lchild, searchpoint, searchtri);
++      child->lchild = grandchild;
++    }
++    if (grandchild == (struct splaynode *) NULL) {
++      if (rightofroot) {
++        splaytree->rchild = child->lchild;
++        child->lchild = splaytree;
++      } else {
++        splaytree->lchild = child->rchild;
++        child->rchild = splaytree;
++      }
++      return child;
++    }
++    if (rightofchild) {
++      if (rightofroot) {
++        splaytree->rchild = child->lchild;
++        child->lchild = splaytree;
++      } else {
++        splaytree->lchild = grandchild->rchild;
++        grandchild->rchild = splaytree;
++      }
++      child->rchild = grandchild->lchild;
++      grandchild->lchild = child;
++    } else {
++      if (rightofroot) {
++        splaytree->rchild = grandchild->lchild;
++        grandchild->lchild = splaytree;
++      } else {
++        splaytree->lchild = child->rchild;
++        child->rchild = splaytree;
++      }
++      child->lchild = grandchild->rchild;
++      grandchild->rchild = child;
++    }
++    return grandchild;
++  } else {
++    lefttree = splay(splaytree->lchild, searchpoint, searchtri);
++    righttree = splay(splaytree->rchild, searchpoint, searchtri);
++
++    pooldealloc(&splaynodes, (VOID *) splaytree);
++    if (lefttree == (struct splaynode *) NULL) {
++      return righttree;
++    } else if (righttree == (struct splaynode *) NULL) {
++      return lefttree;
++    } else if (lefttree->rchild == (struct splaynode *) NULL) {
++      lefttree->rchild = righttree->lchild;
++      righttree->lchild = lefttree;
++      return righttree;
++    } else if (righttree->lchild == (struct splaynode *) NULL) {
++      righttree->lchild = lefttree->rchild;
++      lefttree->rchild = righttree;
++      return lefttree;
++    } else {
++/*      printf("Holy Toledo!!!\n"); */
++      leftright = lefttree->rchild;
++      while (leftright->rchild != (struct splaynode *) NULL) {
++        leftright = leftright->rchild;
++      }
++      leftright->rchild = righttree;
++      return lefttree;
++    }
++  }
++}
++
++#endif /* not REDUCED */
++
++#ifndef REDUCED
++
++struct splaynode *splayinsert(splayroot, newkey, searchpoint)
++struct splaynode *splayroot;
++struct triedge *newkey;
++point searchpoint;
++{
++  struct splaynode *newsplaynode;
++
++  newsplaynode = (struct splaynode *) poolalloc(&splaynodes);
++  triedgecopy(*newkey, newsplaynode->keyedge);
++  dest(*newkey, newsplaynode->keydest);
++  if (splayroot == (struct splaynode *) NULL) {
++    newsplaynode->lchild = (struct splaynode *) NULL;
++    newsplaynode->rchild = (struct splaynode *) NULL;
++  } else if (rightofhyperbola(&splayroot->keyedge, searchpoint)) {
++    newsplaynode->lchild = splayroot;
++    newsplaynode->rchild = splayroot->rchild;
++    splayroot->rchild = (struct splaynode *) NULL;
++  } else {
++    newsplaynode->lchild = splayroot->lchild;
++    newsplaynode->rchild = splayroot;
++    splayroot->lchild = (struct splaynode *) NULL;
++  }
++  return newsplaynode;
++}
++
++#endif /* not REDUCED */
++
++#ifndef REDUCED
++
++struct splaynode *circletopinsert(splayroot, newkey, pa, pb, pc, topy)
++struct splaynode *splayroot;
++struct triedge *newkey;
++point pa;
++point pb;
++point pc;
++REAL topy;
++{
++  REAL ccwabc;
++  REAL xac, yac, xbc, ybc;
++  REAL aclen2, bclen2;
++  REAL searchpoint[2];
++  struct triedge dummytri;
++
++  ccwabc = counterclockwise(pa, pb, pc);
++  xac = pa[0] - pc[0];
++  yac = pa[1] - pc[1];
++  xbc = pb[0] - pc[0];
++  ybc = pb[1] - pc[1];
++  aclen2 = xac * xac + yac * yac;
++  bclen2 = xbc * xbc + ybc * ybc;
++  searchpoint[0] = pc[0] - (yac * bclen2 - ybc * aclen2) / (2.0 * ccwabc);
++  searchpoint[1] = topy;
++  return splayinsert(splay(splayroot, (point) searchpoint, &dummytri), newkey,
++                     (point) searchpoint);
++}
++
++#endif /* not REDUCED */
++
++#ifndef REDUCED
++
++struct splaynode *frontlocate(splayroot, bottommost, searchpoint, searchtri,
++                              farright)
++struct splaynode *splayroot;
++struct triedge *bottommost;
++point searchpoint;
++struct triedge *searchtri;
++int *farright;
++{
++  int farrightflag;
++  triangle ptr;                       /* Temporary variable used by onext(). */
++
++  triedgecopy(*bottommost, *searchtri);
++  splayroot = splay(splayroot, searchpoint, searchtri);
++
++  farrightflag = 0;
++  while (!farrightflag && rightofhyperbola(searchtri, searchpoint)) {
++    onextself(*searchtri);
++    farrightflag = triedgeequal(*searchtri, *bottommost);
++  }
++  *farright = farrightflag;
++  return splayroot;
++}
++
++#endif /* not REDUCED */
++
++#ifndef REDUCED
++
++long sweeplinedelaunay()
++{
++  struct event **eventheap;
++  struct event *events;
++  struct event *freeevents;
++  struct event *nextevent;
++  struct event *newevent;
++  struct splaynode *splayroot;
++  struct triedge bottommost;
++  struct triedge searchtri;
++  struct triedge fliptri;
++  struct triedge lefttri, righttri, farlefttri, farrighttri;
++  struct triedge inserttri;
++  point firstpoint, secondpoint;
++  point nextpoint, lastpoint;
++  point connectpoint;
++  point leftpoint, midpoint, rightpoint;
++  REAL lefttest, righttest;
++  int heapsize;
++  int check4events, farrightflag;
++  triangle ptr;   /* Temporary variable used by sym(), onext(), and oprev(). */
++
++  poolinit(&splaynodes, sizeof(struct splaynode), SPLAYNODEPERBLOCK, POINTER,
++           0);
++  splayroot = (struct splaynode *) NULL;
++
++  if (verbose) {
++    printf("  Placing points in event heap.\n");
++  }
++  createeventheap(&eventheap, &events, &freeevents);
++  heapsize = inpoints;
++
++  if (verbose) {
++    printf("  Forming triangulation.\n");
++  }
++  maketriangle(&lefttri);
++  maketriangle(&righttri);
++  bond(lefttri, righttri);
++  lnextself(lefttri);
++  lprevself(righttri);
++  bond(lefttri, righttri);
++  lnextself(lefttri);
++  lprevself(righttri);
++  bond(lefttri, righttri);
++  firstpoint = (point) eventheap[0]->eventptr;
++  eventheap[0]->eventptr = (VOID *) freeevents;
++  freeevents = eventheap[0];
++  eventheapdelete(eventheap, heapsize, 0);
++  heapsize--;
++  do {
++    if (heapsize == 0) {
++      printf("Error:  Input points are all identical.\n");
++      exit(1);
++    }
++    secondpoint = (point) eventheap[0]->eventptr;
++    eventheap[0]->eventptr = (VOID *) freeevents;
++    freeevents = eventheap[0];
++    eventheapdelete(eventheap, heapsize, 0);
++    heapsize--;
++    if ((firstpoint[0] == secondpoint[0])
++        && (firstpoint[1] == secondpoint[1])) {
++      printf(
++"Warning:  A duplicate point at (%.12g, %.12g) appeared and was ignored.\n",
++             secondpoint[0], secondpoint[1]);
++/*  Commented out - would eliminate point from output .node file.
++      setpointmark(secondpoint, DEADPOINT);
++*/
++    }
++  } while ((firstpoint[0] == secondpoint[0])
++           && (firstpoint[1] == secondpoint[1]));
++  setorg(lefttri, firstpoint);
++  setdest(lefttri, secondpoint);
++  setorg(righttri, secondpoint);
++  setdest(righttri, firstpoint);
++  lprev(lefttri, bottommost);
++  lastpoint = secondpoint;
++  while (heapsize > 0) {
++    nextevent = eventheap[0];
++    eventheapdelete(eventheap, heapsize, 0);
++    heapsize--;
++    check4events = 1;
++    if (nextevent->xkey < xmin) {
++      decode(nextevent->eventptr, fliptri);
++      oprev(fliptri, farlefttri);
++      check4deadevent(&farlefttri, &freeevents, eventheap, &heapsize);
++      onext(fliptri, farrighttri);
++      check4deadevent(&farrighttri, &freeevents, eventheap, &heapsize);
++
++      if (triedgeequal(farlefttri, bottommost)) {
++        lprev(fliptri, bottommost);
++      }
++      flip(&fliptri);
++      setapex(fliptri, NULL);
++      lprev(fliptri, lefttri);
++      lnext(fliptri, righttri);
++      sym(lefttri, farlefttri);
++
++      if (randomnation(SAMPLERATE) == 0) {
++        symself(fliptri);
++        dest(fliptri, leftpoint);
++        apex(fliptri, midpoint);
++        org(fliptri, rightpoint);
++        splayroot = circletopinsert(splayroot, &lefttri, leftpoint, midpoint,
++                                    rightpoint, nextevent->ykey);
++      }
++    } else {
++      nextpoint = (point) nextevent->eventptr;
++      if ((nextpoint[0] == lastpoint[0]) && (nextpoint[1] == lastpoint[1])) {
++        printf(
++"Warning:  A duplicate point at (%.12g, %.12g) appeared and was ignored.\n",
++               nextpoint[0], nextpoint[1]);
++/*  Commented out - would eliminate point from output .node file.
++        setpointmark(nextpoint, DEADPOINT);
++*/
++        check4events = 0;
++      } else {
++        lastpoint = nextpoint;
++
++        splayroot = frontlocate(splayroot, &bottommost, nextpoint, &searchtri,
++                                &farrightflag);
++/*
++        triedgecopy(bottommost, searchtri);
++        farrightflag = 0;
++        while (!farrightflag && rightofhyperbola(&searchtri, nextpoint)) {
++          onextself(searchtri);
++          farrightflag = triedgeequal(searchtri, bottommost);
++        }
++*/
++
++        check4deadevent(&searchtri, &freeevents, eventheap, &heapsize);
++
++        triedgecopy(searchtri, farrighttri);
++        sym(searchtri, farlefttri);
++        maketriangle(&lefttri);
++        maketriangle(&righttri);
++        dest(farrighttri, connectpoint);
++        setorg(lefttri, connectpoint);
++        setdest(lefttri, nextpoint);
++        setorg(righttri, nextpoint);
++        setdest(righttri, connectpoint);
++        bond(lefttri, righttri);
++        lnextself(lefttri);
++        lprevself(righttri);
++        bond(lefttri, righttri);
++        lnextself(lefttri);
++        lprevself(righttri);
++        bond(lefttri, farlefttri);
++        bond(righttri, farrighttri);
++        if (!farrightflag && triedgeequal(farrighttri, bottommost)) {
++          triedgecopy(lefttri, bottommost);
++        }
++
++        if (randomnation(SAMPLERATE) == 0) {
++          splayroot = splayinsert(splayroot, &lefttri, nextpoint);
++        } else if (randomnation(SAMPLERATE) == 0) {
++          lnext(righttri, inserttri);
++          splayroot = splayinsert(splayroot, &inserttri, nextpoint);
++        }
++      }
++    }
++    nextevent->eventptr = (VOID *) freeevents;
++    freeevents = nextevent;
++
++    if (check4events) {
++      apex(farlefttri, leftpoint);
++      dest(lefttri, midpoint);
++      apex(lefttri, rightpoint);
++      lefttest = counterclockwise(leftpoint, midpoint, rightpoint);
++      if (lefttest > 0.0) {
++        newevent = freeevents;
++        freeevents = (struct event *) freeevents->eventptr;
++        newevent->xkey = xminextreme;
++        newevent->ykey = circletop(leftpoint, midpoint, rightpoint,
++                                   lefttest);
++        newevent->eventptr = (VOID *) encode(lefttri);
++        eventheapinsert(eventheap, heapsize, newevent);
++        heapsize++;
++        setorg(lefttri, newevent);
++      }
++      apex(righttri, leftpoint);
++      org(righttri, midpoint);
++      apex(farrighttri, rightpoint);
++      righttest = counterclockwise(leftpoint, midpoint, rightpoint);
++      if (righttest > 0.0) {
++        newevent = freeevents;
++        freeevents = (struct event *) freeevents->eventptr;
++        newevent->xkey = xminextreme;
++        newevent->ykey = circletop(leftpoint, midpoint, rightpoint,
++                                   righttest);
++        newevent->eventptr = (VOID *) encode(farrighttri);
++        eventheapinsert(eventheap, heapsize, newevent);
++        heapsize++;
++        setorg(farrighttri, newevent);
++      }
++    }
++  }
++
++  pooldeinit(&splaynodes);
++  lprevself(bottommost);
++  return removeghosts(&bottommost);
++}
++
++#endif /* not REDUCED */
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Sweepline Delaunay triangulation ends here                *********/
++
++/********* General mesh construction routines begin here             *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  delaunay()   Form a Delaunay triangulation.                              */
++/*                                                                           */
++/*****************************************************************************/
++
++long delaunay()
++{
++  eextras = 0;
++  initializetrisegpools();
++
++#ifdef REDUCED
++  if (!quiet) {
++    printf(
++      "Constructing Delaunay triangulation by divide-and-conquer method.\n");
++  }
++  return divconqdelaunay();
++#else /* not REDUCED */
++  if (!quiet) {
++    printf("Constructing Delaunay triangulation ");
++    if (incremental) {
++      printf("by incremental method.\n");
++    } else if (sweepline) {
++      printf("by sweepline method.\n");
++    } else {
++      printf("by divide-and-conquer method.\n");
++    }
++  }
++  if (incremental) {
++    return incrementaldelaunay();
++  } else if (sweepline) {
++    return sweeplinedelaunay();
++  } else {
++    return divconqdelaunay();
++  }
++#endif /* not REDUCED */
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  reconstruct()   Reconstruct a triangulation from its .ele (and possibly  */
++/*                  .poly) file.  Used when the -r switch is used.           */
++/*                                                                           */
++/*  Reads an .ele file and reconstructs the original mesh.  If the -p switch */
++/*  is used, this procedure will also read a .poly file and reconstruct the  */
++/*  shell edges of the original mesh.  If the -a switch is used, this        */
++/*  procedure will also read an .area file and set a maximum area constraint */
++/*  on each triangle.                                                        */
++/*                                                                           */
++/*  Points that are not corners of triangles, such as nodes on edges of      */
++/*  subparametric elements, are discarded.                                   */
++/*                                                                           */
++/*  This routine finds the adjacencies between triangles (and shell edges)   */
++/*  by forming one stack of triangles for each vertex.  Each triangle is on  */
++/*  three different stacks simultaneously.  Each triangle's shell edge       */
++/*  pointers are used to link the items in each stack.  This memory-saving   */
++/*  feature makes the code harder to read.  The most important thing to keep */
++/*  in mind is that each triangle is removed from a stack precisely when     */
++/*  the corresponding pointer is adjusted to refer to a shell edge rather    */
++/*  than the next triangle of the stack.                                     */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++#ifdef TRILIBRARY
++
++int reconstruct(trianglelist, triangleattriblist, trianglearealist, elements,
++                corners, attribs, segmentlist, segmentmarkerlist,
++                numberofsegments)
++int *trianglelist;
++REAL *triangleattriblist;
++REAL *trianglearealist;
++int elements;
++int corners;
++int attribs;
++int *segmentlist;
++int *segmentmarkerlist;
++int numberofsegments;
++
++#else /* not TRILIBRARY */
++
++long reconstruct(elefilename, areafilename, polyfilename, polyfile)
++char *elefilename;
++char *areafilename;
++char *polyfilename;
++FILE *polyfile;
++
++#endif /* not TRILIBRARY */
++
++{
++#ifdef TRILIBRARY
++  int pointindex;
++  int attribindex;
++#else /* not TRILIBRARY */
++  FILE *elefile;
++  FILE *areafile;
++  char inputline[INPUTLINESIZE];
++  char *stringptr;
++  int areaelements;
++#endif /* not TRILIBRARY */
++  struct triedge triangleloop;
++  struct triedge triangleleft;
++  struct triedge checktri;
++  struct triedge checkleft;
++  struct triedge checkneighbor;
++  struct edge shelleloop;
++  triangle *vertexarray;
++  triangle *prevlink;
++  triangle nexttri;
++  point tdest, tapex;
++  point checkdest, checkapex;
++  point shorg;
++  point killpoint;
++  REAL area;
++  int corner[3];
++  int end[2];
++  int killpointindex;
++  int incorners;
++  int segmentmarkers;
++  int boundmarker;
++  int aroundpoint;
++  long hullsize;
++  int notfound;
++  int elementnumber, segmentnumber;
++  int i, j;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++
++#ifdef TRILIBRARY
++  inelements = elements;
++  incorners = corners;
++  if (incorners < 3) {
++    printf("Error:  Triangles must have at least 3 points.\n");
++    exit(1);
++  }
++  eextras = attribs;
++#else /* not TRILIBRARY */
++  /* Read the triangles from an .ele file. */
++  if (!quiet) {
++    printf("Opening %s.\n", elefilename);
++  }
++  elefile = fopen(elefilename, "r");
++  if (elefile == (FILE *) NULL) {
++    printf("  Error:  Cannot access file %s.\n", elefilename);
++    exit(1);
++  }
++  /* Read number of triangles, number of points per triangle, and */
++  /*   number of triangle attributes from .ele file.              */
++  stringptr = readline(inputline, elefile, elefilename);
++  inelements = (int) strtol (stringptr, &stringptr, 0);
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    incorners = 3;
++  } else {
++    incorners = (int) strtol (stringptr, &stringptr, 0);
++    if (incorners < 3) {
++      printf("Error:  Triangles in %s must have at least 3 points.\n",
++             elefilename);
++      exit(1);
++    }
++  }
++  stringptr = findfield(stringptr);
++  if (*stringptr == '\0') {
++    eextras = 0;
++  } else {
++    eextras = (int) strtol (stringptr, &stringptr, 0);
++  }
++#endif /* not TRILIBRARY */
++
++  initializetrisegpools();
++
++  /* Create the triangles. */
++  for (elementnumber = 1; elementnumber <= inelements; elementnumber++) {
++    maketriangle(&triangleloop);
++    /* Mark the triangle as living. */
++    triangleloop.tri[3] = (triangle) triangleloop.tri;
++  }
++
++  if (poly) {
++#ifdef TRILIBRARY
++    insegments = numberofsegments;
++    segmentmarkers = segmentmarkerlist != (int *) NULL;
++#else /* not TRILIBRARY */
++    /* Read number of segments and number of segment */
++    /*   boundary markers from .poly file.           */
++    stringptr = readline(inputline, polyfile, inpolyfilename);
++    insegments = (int) strtol (stringptr, &stringptr, 0);
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      segmentmarkers = 0;
++    } else {
++      segmentmarkers = (int) strtol (stringptr, &stringptr, 0);
++    }
++#endif /* not TRILIBRARY */
++
++    /* Create the shell edges. */
++    for (segmentnumber = 1; segmentnumber <= insegments; segmentnumber++) {
++      makeshelle(&shelleloop);
++      /* Mark the shell edge as living. */
++      shelleloop.sh[2] = (shelle) shelleloop.sh;
++    }
++  }
++
++#ifdef TRILIBRARY
++  pointindex = 0;
++  attribindex = 0;
++#else /* not TRILIBRARY */
++  if (vararea) {
++    /* Open an .area file, check for consistency with the .ele file. */
++    if (!quiet) {
++      printf("Opening %s.\n", areafilename);
++    }
++    areafile = fopen(areafilename, "r");
++    if (areafile == (FILE *) NULL) {
++      printf("  Error:  Cannot access file %s.\n", areafilename);
++      exit(1);
++    }
++    stringptr = readline(inputline, areafile, areafilename);
++    areaelements = (int) strtol (stringptr, &stringptr, 0);
++    if (areaelements != inelements) {
++      printf("Error:  %s and %s disagree on number of triangles.\n",
++             elefilename, areafilename);
++      exit(1);
++    }
++  }
++#endif /* not TRILIBRARY */
++
++  if (!quiet) {
++    printf("Reconstructing mesh.\n");
++  }
++  /* Allocate a temporary array that maps each point to some adjacent  */
++  /*   triangle.  I took care to allocate all the permanent memory for */
++  /*   triangles and shell edges first.                                */
++  vertexarray = (triangle *) malloc(points.items * sizeof(triangle));
++  if (vertexarray == (triangle *) NULL) {
++    printf("Error:  Out of memory.\n");
++    exit(1);
++  }
++  /* Each point is initially unrepresented. */
++  for (i = 0; i < points.items; i++) {
++    vertexarray[i] = (triangle) dummytri;
++  }
++
++  if (verbose) {
++    printf("  Assembling triangles.\n");
++  }
++  /* Read the triangles from the .ele file, and link */
++  /*   together those that share an edge.            */
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  elementnumber = firstnumber;
++  while (triangleloop.tri != (triangle *) NULL) {
++#ifdef TRILIBRARY
++    /* Copy the triangle's three corners. */
++    for (j = 0; j < 3; j++) {
++      corner[j] = trianglelist[pointindex++];
++      if ((corner[j] < firstnumber) || (corner[j] >= firstnumber + inpoints)) {
++        printf("Error:  Triangle %d has an invalid vertex index.\n",
++               elementnumber);
++        exit(1);
++      }
++    }
++#else /* not TRILIBRARY */
++    /* Read triangle number and the triangle's three corners. */
++    stringptr = readline(inputline, elefile, elefilename);
++    for (j = 0; j < 3; j++) {
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        printf("Error:  Triangle %d is missing point %d in %s.\n",
++               elementnumber, j + 1, elefilename);
++        exit(1);
++      } else {
++        corner[j] = (int) strtol (stringptr, &stringptr, 0);
++        if ((corner[j] < firstnumber) ||
++            (corner[j] >= firstnumber + inpoints)) {
++          printf("Error:  Triangle %d has an invalid vertex index.\n",
++                 elementnumber);
++          exit(1);
++        }
++      }
++    }
++#endif /* not TRILIBRARY */
++
++    /* Find out about (and throw away) extra nodes. */
++    for (j = 3; j < incorners; j++) {
++#ifdef TRILIBRARY
++      killpointindex = trianglelist[pointindex++];
++#else /* not TRILIBRARY */
++      stringptr = findfield(stringptr);
++      if (*stringptr != '\0') {
++        killpointindex = (int) strtol (stringptr, &stringptr, 0);
++#endif /* not TRILIBRARY */
++        if ((killpointindex >= firstnumber) &&
++            (killpointindex < firstnumber + inpoints)) {
++          /* Delete the non-corner point if it's not already deleted. */
++          killpoint = getpoint(killpointindex);
++          if (pointmark(killpoint) != DEADPOINT) {
++            pointdealloc(killpoint);
++          }
++        }
++#ifndef TRILIBRARY
++      }
++#endif /* not TRILIBRARY */
++    }
++
++    /* Read the triangle's attributes. */
++    for (j = 0; j < eextras; j++) {
++#ifdef TRILIBRARY
++      setelemattribute(triangleloop, j, triangleattriblist[attribindex++]);
++#else /* not TRILIBRARY */
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        setelemattribute(triangleloop, j, 0);
++      } else {
++        setelemattribute(triangleloop, j,
++                         (REAL) strtod (stringptr, &stringptr));
++      }
++#endif /* not TRILIBRARY */
++    }
++
++    if (vararea) {
++#ifdef TRILIBRARY
++      area = trianglearealist[elementnumber - firstnumber];
++#else /* not TRILIBRARY */
++      /* Read an area constraint from the .area file. */
++      stringptr = readline(inputline, areafile, areafilename);
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        area = -1.0;                      /* No constraint on this triangle. */
++      } else {
++        area = (REAL) strtod(stringptr, &stringptr);
++      }
++#endif /* not TRILIBRARY */
++      setareabound(triangleloop, area);
++    }
++
++    /* Set the triangle's vertices. */
++    triangleloop.orient = 0;
++    setorg(triangleloop, getpoint(corner[0]));
++    setdest(triangleloop, getpoint(corner[1]));
++    setapex(triangleloop, getpoint(corner[2]));
++    /* Try linking the triangle to others that share these vertices. */
++    for (triangleloop.orient = 0; triangleloop.orient < 3;
++         triangleloop.orient++) {
++      /* Take the number for the origin of triangleloop. */
++      aroundpoint = corner[triangleloop.orient];
++      /* Look for other triangles having this vertex. */
++      nexttri = vertexarray[aroundpoint - firstnumber];
++      /* Link the current triangle to the next one in the stack. */
++      triangleloop.tri[6 + triangleloop.orient] = nexttri;
++      /* Push the current triangle onto the stack. */
++      vertexarray[aroundpoint - firstnumber] = encode(triangleloop);
++      decode(nexttri, checktri);
++      if (checktri.tri != dummytri) {
++        dest(triangleloop, tdest);
++        apex(triangleloop, tapex);
++        /* Look for other triangles that share an edge. */
++        do {
++          dest(checktri, checkdest);
++          apex(checktri, checkapex);
++          if (tapex == checkdest) {
++            /* The two triangles share an edge; bond them together. */
++            lprev(triangleloop, triangleleft);
++            bond(triangleleft, checktri);
++          }
++          if (tdest == checkapex) {
++            /* The two triangles share an edge; bond them together. */
++            lprev(checktri, checkleft);
++            bond(triangleloop, checkleft);
++          }
++          /* Find the next triangle in the stack. */
++          nexttri = checktri.tri[6 + checktri.orient];
++          decode(nexttri, checktri);
++        } while (checktri.tri != dummytri);
++      }
++    }
++    triangleloop.tri = triangletraverse();
++    elementnumber++;
++  }
++
++#ifdef TRILIBRARY
++  pointindex = 0;
++#else /* not TRILIBRARY */
++  fclose(elefile);
++  if (vararea) {
++    fclose(areafile);
++  }
++#endif /* not TRILIBRARY */
++
++  hullsize = 0;                      /* Prepare to count the boundary edges. */
++  if (poly) {
++    if (verbose) {
++      printf("  Marking segments in triangulation.\n");
++    }
++    /* Read the segments from the .poly file, and link them */
++    /*   to their neighboring triangles.                    */
++    boundmarker = 0;
++    traversalinit(&shelles);
++    shelleloop.sh = shelletraverse();
++    segmentnumber = firstnumber;
++    while (shelleloop.sh != (shelle *) NULL) {
++#ifdef TRILIBRARY
++      end[0] = segmentlist[pointindex++];
++      end[1] = segmentlist[pointindex++];
++      if (segmentmarkers) {
++        boundmarker = segmentmarkerlist[segmentnumber - firstnumber];
++      }
++#else /* not TRILIBRARY */
++      /* Read the endpoints of each segment, and possibly a boundary marker. */
++      stringptr = readline(inputline, polyfile, inpolyfilename);
++      /* Skip the first (segment number) field. */
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        printf("Error:  Segment %d has no endpoints in %s.\n", segmentnumber,
++               polyfilename);
++        exit(1);
++      } else {
++        end[0] = (int) strtol (stringptr, &stringptr, 0);
++      }
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        printf("Error:  Segment %d is missing its second endpoint in %s.\n",
++               segmentnumber, polyfilename);
++        exit(1);
++      } else {
++        end[1] = (int) strtol (stringptr, &stringptr, 0);
++      }
++      if (segmentmarkers) {
++        stringptr = findfield(stringptr);
++        if (*stringptr == '\0') {
++          boundmarker = 0;
++        } else {
++          boundmarker = (int) strtol (stringptr, &stringptr, 0);
++        }
++      }
++#endif /* not TRILIBRARY */
++      for (j = 0; j < 2; j++) {
++        if ((end[j] < firstnumber) || (end[j] >= firstnumber + inpoints)) {
++          printf("Error:  Segment %d has an invalid vertex index.\n", 
++                 segmentnumber);
++          exit(1);
++        }
++      }
++
++      /* set the shell edge's vertices. */
++      shelleloop.shorient = 0;
++      setsorg(shelleloop, getpoint(end[0]));
++      setsdest(shelleloop, getpoint(end[1]));
++      setmark(shelleloop, boundmarker);
++      /* Try linking the shell edge to triangles that share these vertices. */
++      for (shelleloop.shorient = 0; shelleloop.shorient < 2;
++           shelleloop.shorient++) {
++        /* Take the number for the destination of shelleloop. */
++        aroundpoint = end[1 - shelleloop.shorient];
++        /* Look for triangles having this vertex. */
++        prevlink = &vertexarray[aroundpoint - firstnumber];
++        nexttri = vertexarray[aroundpoint - firstnumber];
++        decode(nexttri, checktri);
++        sorg(shelleloop, shorg);
++        notfound = 1;
++        /* Look for triangles having this edge.  Note that I'm only       */
++        /*   comparing each triangle's destination with the shell edge;   */
++        /*   each triangle's apex is handled through a different vertex.  */
++        /*   Because each triangle appears on three vertices' lists, each */
++        /*   occurrence of a triangle on a list can (and does) represent  */
++        /*   an edge.  In this way, most edges are represented twice, and */
++        /*   every triangle-segment bond is represented once.             */
++        while (notfound && (checktri.tri != dummytri)) {
++          dest(checktri, checkdest);
++          if (shorg == checkdest) {
++            /* We have a match.  Remove this triangle from the list. */
++            *prevlink = checktri.tri[6 + checktri.orient];
++            /* Bond the shell edge to the triangle. */
++            tsbond(checktri, shelleloop);
++            /* Check if this is a boundary edge. */
++            sym(checktri, checkneighbor);
++            if (checkneighbor.tri == dummytri) {
++              /* The next line doesn't insert a shell edge (because there's */
++              /*   already one there), but it sets the boundary markers of  */
++              /*   the existing shell edge and its vertices.                */
++              insertshelle(&checktri, 1);
++              hullsize++;
++            }
++            notfound = 0;
++          }
++          /* Find the next triangle in the stack. */
++          prevlink = &checktri.tri[6 + checktri.orient];
++          nexttri = checktri.tri[6 + checktri.orient];
++          decode(nexttri, checktri);
++        }
++      }
++      shelleloop.sh = shelletraverse();
++      segmentnumber++;
++    }
++  }
++
++  /* Mark the remaining edges as not being attached to any shell edge. */
++  /* Also, count the (yet uncounted) boundary edges.                   */
++  for (i = 0; i < points.items; i++) {
++    /* Search the stack of triangles adjacent to a point. */
++    nexttri = vertexarray[i];
++    decode(nexttri, checktri);
++    while (checktri.tri != dummytri) {
++      /* Find the next triangle in the stack before this */
++      /*   information gets overwritten.                 */
++      nexttri = checktri.tri[6 + checktri.orient];
++      /* No adjacent shell edge.  (This overwrites the stack info.) */
++      tsdissolve(checktri);
++      sym(checktri, checkneighbor);
++      if (checkneighbor.tri == dummytri) {
++        insertshelle(&checktri, 1);
++        hullsize++;
++      }
++      decode(nexttri, checktri);
++    }
++  }
++
++  free(vertexarray);
++  return hullsize;
++}
++
++#endif /* not CDT_ONLY */
++
++/**                                                                         **/
++/**                                                                         **/
++/********* General mesh construction routines end here               *********/
++
++/********* Segment (shell edge) insertion begins here                *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  finddirection()   Find the first triangle on the path from one point     */
++/*                    to another.                                            */
++/*                                                                           */
++/*  Finds the triangle that intersects a line segment drawn from the         */
++/*  origin of `searchtri' to the point `endpoint', and returns the result    */
++/*  in `searchtri'.  The origin of `searchtri' does not change, even though  */
++/*  the triangle returned may differ from the one passed in.  This routine   */
++/*  is used to find the direction to move in to get from one point to        */
++/*  another.                                                                 */
++/*                                                                           */
++/*  The return value notes whether the destination or apex of the found      */
++/*  triangle is collinear with the two points in question.                   */
++/*                                                                           */
++/*****************************************************************************/
++
++enum finddirectionresult finddirection(searchtri, endpoint)
++struct triedge *searchtri;
++point endpoint;
++{
++  struct triedge checktri;
++  point startpoint;
++  point leftpoint, rightpoint;
++  REAL leftccw, rightccw;
++  int leftflag, rightflag;
++  triangle ptr;           /* Temporary variable used by onext() and oprev(). */
++
++  org(*searchtri, startpoint);
++  dest(*searchtri, rightpoint);
++  apex(*searchtri, leftpoint);
++  /* Is `endpoint' to the left? */
++  leftccw = counterclockwise(endpoint, startpoint, leftpoint);
++  leftflag = leftccw > 0.0;
++  /* Is `endpoint' to the right? */
++  rightccw = counterclockwise(startpoint, endpoint, rightpoint);
++  rightflag = rightccw > 0.0;
++  if (leftflag && rightflag) {
++    /* `searchtri' faces directly away from `endpoint'.  We could go */
++    /*   left or right.  Ask whether it's a triangle or a boundary   */
++    /*   on the left.                                                */
++    onext(*searchtri, checktri);
++    if (checktri.tri == dummytri) {
++      leftflag = 0;
++    } else {
++      rightflag = 0;
++    }
++  }
++  while (leftflag) {
++    /* Turn left until satisfied. */
++    onextself(*searchtri);
++    if (searchtri->tri == dummytri) {
++      printf("Internal error in finddirection():  Unable to find a\n");
++      printf("  triangle leading from (%.12g, %.12g) to", startpoint[0],
++             startpoint[1]);
++      printf("  (%.12g, %.12g).\n", endpoint[0], endpoint[1]);
++      internalerror();
++    }
++    apex(*searchtri, leftpoint);
++    rightccw = leftccw;
++    leftccw = counterclockwise(endpoint, startpoint, leftpoint);
++    leftflag = leftccw > 0.0;
++  }
++  while (rightflag) {
++    /* Turn right until satisfied. */
++    oprevself(*searchtri);
++    if (searchtri->tri == dummytri) {
++      printf("Internal error in finddirection():  Unable to find a\n");
++      printf("  triangle leading from (%.12g, %.12g) to", startpoint[0],
++             startpoint[1]);
++      printf("  (%.12g, %.12g).\n", endpoint[0], endpoint[1]);
++      internalerror();
++    }
++    dest(*searchtri, rightpoint);
++    leftccw = rightccw;
++    rightccw = counterclockwise(startpoint, endpoint, rightpoint);
++    rightflag = rightccw > 0.0;
++  }
++  if (leftccw == 0.0) {
++    return LEFTCOLLINEAR;
++  } else if (rightccw == 0.0) {
++    return RIGHTCOLLINEAR;
++  } else {
++    return WITHIN;
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  segmentintersection()   Find the intersection of an existing segment     */
++/*                          and a segment that is being inserted.  Insert    */
++/*                          a point at the intersection, splitting an        */
++/*                          existing shell edge.                             */
++/*                                                                           */
++/*  The segment being inserted connects the apex of splittri to endpoint2.   */
++/*  splitshelle is the shell edge being split, and MUST be opposite          */
++/*  splittri.  Hence, the edge being split connects the origin and           */
++/*  destination of splittri.                                                 */
++/*                                                                           */
++/*  On completion, splittri is a handle having the newly inserted            */
++/*  intersection point as its origin, and endpoint1 as its destination.      */
++/*                                                                           */
++/*****************************************************************************/
++
++void segmentintersection(splittri, splitshelle, endpoint2)
++struct triedge *splittri;
++struct edge *splitshelle;
++point endpoint2;
++{
++  point endpoint1;
++  point torg, tdest;
++  point leftpoint, rightpoint;
++  point newpoint;
++  enum insertsiteresult success;
++  enum finddirectionresult collinear;
++  REAL ex, ey;
++  REAL tx, ty;
++  REAL etx, ety;
++  REAL split, denom;
++  int i;
++  triangle ptr;                       /* Temporary variable used by onext(). */
++
++  /* Find the other three segment endpoints. */
++  apex(*splittri, endpoint1);
++  org(*splittri, torg);
++  dest(*splittri, tdest);
++  /* Segment intersection formulae; see the Antonio reference. */
++  tx = tdest[0] - torg[0];
++  ty = tdest[1] - torg[1];
++  ex = endpoint2[0] - endpoint1[0];
++  ey = endpoint2[1] - endpoint1[1];
++  etx = torg[0] - endpoint2[0];
++  ety = torg[1] - endpoint2[1];
++  denom = ty * ex - tx * ey;
++  if (denom == 0.0) {
++    printf("Internal error in segmentintersection():");
++    printf("  Attempt to find intersection of parallel segments.\n");
++    internalerror();
++  }
++  split = (ey * etx - ex * ety) / denom;
++  /* Create the new point. */
++  newpoint = (point) poolalloc(&points);
++  /* Interpolate its coordinate and attributes. */
++  for (i = 0; i < 2 + nextras; i++) {
++    newpoint[i] = torg[i] + split * (tdest[i] - torg[i]);
++  }
++  setpointmark(newpoint, mark(*splitshelle));
++  if (verbose > 1) {
++    printf(
++    "  Splitting edge (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n",
++           torg[0], torg[1], tdest[0], tdest[1], newpoint[0], newpoint[1]);
++  }
++  /* Insert the intersection point.  This should always succeed. */
++  success = insertsite(newpoint, splittri, splitshelle, 0, 0);
++  if (success != SUCCESSFULPOINT) {
++    printf("Internal error in segmentintersection():\n");
++    printf("  Failure to split a segment.\n");
++    internalerror();
++  }
++  if (steinerleft > 0) {
++    steinerleft--;
++  }
++  /* Inserting the point may have caused edge flips.  We wish to rediscover */
++  /*   the edge connecting endpoint1 to the new intersection point.         */
++  collinear = finddirection(splittri, endpoint1);
++  dest(*splittri, rightpoint);
++  apex(*splittri, leftpoint);
++  if ((leftpoint[0] == endpoint1[0]) && (leftpoint[1] == endpoint1[1])) {
++    onextself(*splittri);
++  } else if ((rightpoint[0] != endpoint1[0]) ||
++             (rightpoint[1] != endpoint1[1])) {
++    printf("Internal error in segmentintersection():\n");
++    printf("  Topological inconsistency after splitting a segment.\n");
++    internalerror();
++  }
++  /* `splittri' should have destination endpoint1. */
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  scoutsegment()   Scout the first triangle on the path from one endpoint  */
++/*                   to another, and check for completion (reaching the      */
++/*                   second endpoint), a collinear point, and the            */
++/*                   intersection of two segments.                           */
++/*                                                                           */
++/*  Returns one if the entire segment is successfully inserted, and zero if  */
++/*  the job must be finished by conformingedge() or constrainededge().       */
++/*                                                                           */
++/*  If the first triangle on the path has the second endpoint as its         */
++/*  destination or apex, a shell edge is inserted and the job is done.       */
++/*                                                                           */
++/*  If the first triangle on the path has a destination or apex that lies on */
++/*  the segment, a shell edge is inserted connecting the first endpoint to   */
++/*  the collinear point, and the search is continued from the collinear      */
++/*  point.                                                                   */
++/*                                                                           */
++/*  If the first triangle on the path has a shell edge opposite its origin,  */
++/*  then there is a segment that intersects the segment being inserted.      */
++/*  Their intersection point is inserted, splitting the shell edge.          */
++/*                                                                           */
++/*  Otherwise, return zero.                                                  */
++/*                                                                           */
++/*****************************************************************************/
++
++int scoutsegment(searchtri, endpoint2, newmark)
++struct triedge *searchtri;
++point endpoint2;
++int newmark;
++{
++  struct triedge crosstri;
++  struct edge crossedge;
++  point leftpoint, rightpoint;
++  point endpoint1;
++  enum finddirectionresult collinear;
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  collinear = finddirection(searchtri, endpoint2);
++  dest(*searchtri, rightpoint);
++  apex(*searchtri, leftpoint);
++  if (((leftpoint[0] == endpoint2[0]) && (leftpoint[1] == endpoint2[1])) ||
++      ((rightpoint[0] == endpoint2[0]) && (rightpoint[1] == endpoint2[1]))) {
++    /* The segment is already an edge in the mesh. */
++    if ((leftpoint[0] == endpoint2[0]) && (leftpoint[1] == endpoint2[1])) {
++      lprevself(*searchtri);
++    }
++    /* Insert a shell edge, if there isn't already one there. */
++    insertshelle(searchtri, newmark);
++    return 1;
++  } else if (collinear == LEFTCOLLINEAR) {
++    /* We've collided with a point between the segment's endpoints. */
++    /* Make the collinear point be the triangle's origin. */
++    lprevself(*searchtri);
++    insertshelle(searchtri, newmark);
++    /* Insert the remainder of the segment. */
++    return scoutsegment(searchtri, endpoint2, newmark);
++  } else if (collinear == RIGHTCOLLINEAR) {
++    /* We've collided with a point between the segment's endpoints. */
++    insertshelle(searchtri, newmark);
++    /* Make the collinear point be the triangle's origin. */
++    lnextself(*searchtri);
++    /* Insert the remainder of the segment. */
++    return scoutsegment(searchtri, endpoint2, newmark);
++  } else {
++    lnext(*searchtri, crosstri);
++    tspivot(crosstri, crossedge);
++    /* Check for a crossing segment. */
++    if (crossedge.sh == dummysh) {
++      return 0;
++    } else {
++      org(*searchtri, endpoint1);
++      /* Insert a point at the intersection. */
++      segmentintersection(&crosstri, &crossedge, endpoint2);
++      triedgecopy(crosstri, *searchtri);
++      insertshelle(searchtri, newmark);
++      /* Insert the remainder of the segment. */
++      return scoutsegment(searchtri, endpoint2, newmark);
++    }
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  conformingedge()   Force a segment into a conforming Delaunay            */
++/*                     triangulation by inserting a point at its midpoint,   */
++/*                     and recursively forcing in the two half-segments if   */
++/*                     necessary.                                            */
++/*                                                                           */
++/*  Generates a sequence of edges connecting `endpoint1' to `endpoint2'.     */
++/*  `newmark' is the boundary marker of the segment, assigned to each new    */
++/*  splitting point and shell edge.                                          */
++/*                                                                           */
++/*  Note that conformingedge() does not always maintain the conforming       */
++/*  Delaunay property.  Once inserted, segments are locked into place;       */
++/*  points inserted later (to force other segments in) may render these      */
++/*  fixed segments non-Delaunay.  The conforming Delaunay property will be   */
++/*  restored by enforcequality() by splitting encroached segments.           */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef REDUCED
++#ifndef CDT_ONLY
++
++void conformingedge(endpoint1, endpoint2, newmark)
++point endpoint1;
++point endpoint2;
++int newmark;
++{
++  struct triedge searchtri1, searchtri2;
++  struct edge brokenshelle;
++  point newpoint;
++  point midpoint1, midpoint2;
++  enum insertsiteresult success;
++  int result1, result2;
++  int i;
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  if (verbose > 2) {
++    printf("Forcing segment into triangulation by recursive splitting:\n");
++    printf("  (%.12g, %.12g) (%.12g, %.12g)\n", endpoint1[0], endpoint1[1],
++           endpoint2[0], endpoint2[1]);
++  }
++  /* Create a new point to insert in the middle of the segment. */
++  newpoint = (point) poolalloc(&points);
++  /* Interpolate coordinates and attributes. */
++  for (i = 0; i < 2 + nextras; i++) {
++    newpoint[i] = 0.5 * (endpoint1[i] + endpoint2[i]);
++  }
++  setpointmark(newpoint, newmark);
++  /* Find a boundary triangle to search from. */
++  searchtri1.tri = (triangle *) NULL;
++  /* Attempt to insert the new point. */
++  success = insertsite(newpoint, &searchtri1, (struct edge *) NULL, 0, 0);
++  if (success == DUPLICATEPOINT) {
++    if (verbose > 2) {
++      printf("  Segment intersects existing point (%.12g, %.12g).\n",
++             newpoint[0], newpoint[1]);
++    }
++    /* Use the point that's already there. */
++    pointdealloc(newpoint);
++    org(searchtri1, newpoint);
++  } else {
++    if (success == VIOLATINGPOINT) {
++      if (verbose > 2) {
++        printf("  Two segments intersect at (%.12g, %.12g).\n",
++               newpoint[0], newpoint[1]);
++      }
++      /* By fluke, we've landed right on another segment.  Split it. */
++      tspivot(searchtri1, brokenshelle);
++      success = insertsite(newpoint, &searchtri1, &brokenshelle, 0, 0);
++      if (success != SUCCESSFULPOINT) {
++        printf("Internal error in conformingedge():\n");
++        printf("  Failure to split a segment.\n");
++        internalerror();
++      }
++    }
++    /* The point has been inserted successfully. */
++    if (steinerleft > 0) {
++      steinerleft--;
++    }
++  }
++  triedgecopy(searchtri1, searchtri2);
++  result1 = scoutsegment(&searchtri1, endpoint1, newmark);
++  result2 = scoutsegment(&searchtri2, endpoint2, newmark);
++  if (!result1) {
++    /* The origin of searchtri1 may have changed if a collision with an */
++    /*   intervening vertex on the segment occurred.                    */
++    org(searchtri1, midpoint1);
++    conformingedge(midpoint1, endpoint1, newmark);
++  }
++  if (!result2) {
++    /* The origin of searchtri2 may have changed if a collision with an */
++    /*   intervening vertex on the segment occurred.                    */
++    org(searchtri2, midpoint2);
++    conformingedge(midpoint2, endpoint2, newmark);
++  }
++}
++
++#endif /* not CDT_ONLY */
++#endif /* not REDUCED */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  delaunayfixup()   Enforce the Delaunay condition at an edge, fanning out */
++/*                    recursively from an existing point.  Pay special       */
++/*                    attention to stacking inverted triangles.              */
++/*                                                                           */
++/*  This is a support routine for inserting segments into a constrained      */
++/*  Delaunay triangulation.                                                  */
++/*                                                                           */
++/*  The origin of fixuptri is treated as if it has just been inserted, and   */
++/*  the local Delaunay condition needs to be enforced.  It is only enforced  */
++/*  in one sector, however, that being the angular range defined by          */
++/*  fixuptri.                                                                */
++/*                                                                           */
++/*  This routine also needs to make decisions regarding the "stacking" of    */
++/*  triangles.  (Read the description of constrainededge() below before      */
++/*  reading on here, so you understand the algorithm.)  If the position of   */
++/*  the new point (the origin of fixuptri) indicates that the vertex before  */
++/*  it on the polygon is a reflex vertex, then "stack" the triangle by       */
++/*  doing nothing.  (fixuptri is an inverted triangle, which is how stacked  */
++/*  triangles are identified.)                                               */
++/*                                                                           */
++/*  Otherwise, check whether the vertex before that was a reflex vertex.     */
++/*  If so, perform an edge flip, thereby eliminating an inverted triangle    */
++/*  (popping it off the stack).  The edge flip may result in the creation    */
++/*  of a new inverted triangle, depending on whether or not the new vertex   */
++/*  is visible to the vertex three edges behind on the polygon.              */
++/*                                                                           */
++/*  If neither of the two vertices behind the new vertex are reflex          */
++/*  vertices, fixuptri and fartri, the triangle opposite it, are not         */
++/*  inverted; hence, ensure that the edge between them is locally Delaunay.  */
++/*                                                                           */
++/*  `leftside' indicates whether or not fixuptri is to the left of the       */
++/*  segment being inserted.  (Imagine that the segment is pointing up from   */
++/*  endpoint1 to endpoint2.)                                                 */
++/*                                                                           */
++/*****************************************************************************/
++
++void delaunayfixup(fixuptri, leftside)
++struct triedge *fixuptri;
++int leftside;
++{
++  struct triedge neartri;
++  struct triedge fartri;
++  struct edge faredge;
++  point nearpoint, leftpoint, rightpoint, farpoint;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  lnext(*fixuptri, neartri);
++  sym(neartri, fartri);
++  /* Check if the edge opposite the origin of fixuptri can be flipped. */
++  if (fartri.tri == dummytri) {
++    return;
++  }
++  tspivot(neartri, faredge);
++  if (faredge.sh != dummysh) {
++    return;
++  }
++  /* Find all the relevant vertices. */
++  apex(neartri, nearpoint);
++  org(neartri, leftpoint);
++  dest(neartri, rightpoint);
++  apex(fartri, farpoint);
++  /* Check whether the previous polygon vertex is a reflex vertex. */
++  if (leftside) {
++    if (counterclockwise(nearpoint, leftpoint, farpoint) <= 0.0) {
++      /* leftpoint is a reflex vertex too.  Nothing can */
++      /*   be done until a convex section is found.     */
++      return;
++    }
++  } else {
++    if (counterclockwise(farpoint, rightpoint, nearpoint) <= 0.0) {
++      /* rightpoint is a reflex vertex too.  Nothing can */
++      /*   be done until a convex section is found.      */
++      return;
++    }
++  }
++  if (counterclockwise(rightpoint, leftpoint, farpoint) > 0.0) {
++    /* fartri is not an inverted triangle, and farpoint is not a reflex */
++    /*   vertex.  As there are no reflex vertices, fixuptri isn't an    */
++    /*   inverted triangle, either.  Hence, test the edge between the   */
++    /*   triangles to ensure it is locally Delaunay.                    */
++    if (incircle(leftpoint, farpoint, rightpoint, nearpoint) <= 0.0) {
++      return;
++    }
++    /* Not locally Delaunay; go on to an edge flip. */
++  }        /* else fartri is inverted; remove it from the stack by flipping. */
++  flip(&neartri);
++  lprevself(*fixuptri);    /* Restore the origin of fixuptri after the flip. */
++  /* Recursively process the two triangles that result from the flip. */
++  delaunayfixup(fixuptri, leftside);
++  delaunayfixup(&fartri, leftside);
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  constrainededge()   Force a segment into a constrained Delaunay          */
++/*                      triangulation by deleting the triangles it           */
++/*                      intersects, and triangulating the polygons that      */
++/*                      form on each side of it.                             */
++/*                                                                           */
++/*  Generates a single edge connecting `endpoint1' to `endpoint2'.  The      */
++/*  triangle `starttri' has `endpoint1' as its origin.  `newmark' is the     */
++/*  boundary marker of the segment.                                          */
++/*                                                                           */
++/*  To insert a segment, every triangle whose interior intersects the        */
++/*  segment is deleted.  The union of these deleted triangles is a polygon   */
++/*  (which is not necessarily monotone, but is close enough), which is       */
++/*  divided into two polygons by the new segment.  This routine's task is    */
++/*  to generate the Delaunay triangulation of these two polygons.            */
++/*                                                                           */
++/*  You might think of this routine's behavior as a two-step process.  The   */
++/*  first step is to walk from endpoint1 to endpoint2, flipping each edge    */
++/*  encountered.  This step creates a fan of edges connected to endpoint1,   */
++/*  including the desired edge to endpoint2.  The second step enforces the   */
++/*  Delaunay condition on each side of the segment in an incremental manner: */
++/*  proceeding along the polygon from endpoint1 to endpoint2 (this is done   */
++/*  independently on each side of the segment), each vertex is "enforced"    */
++/*  as if it had just been inserted, but affecting only the previous         */
++/*  vertices.  The result is the same as if the vertices had been inserted   */
++/*  in the order they appear on the polygon, so the result is Delaunay.      */
++/*                                                                           */
++/*  In truth, constrainededge() interleaves these two steps.  The procedure  */
++/*  walks from endpoint1 to endpoint2, and each time an edge is encountered  */
++/*  and flipped, the newly exposed vertex (at the far end of the flipped     */
++/*  edge) is "enforced" upon the previously flipped edges, usually affecting */
++/*  only one side of the polygon (depending upon which side of the segment   */
++/*  the vertex falls on).                                                    */
++/*                                                                           */
++/*  The algorithm is complicated by the need to handle polygons that are not */
++/*  convex.  Although the polygon is not necessarily monotone, it can be     */
++/*  triangulated in a manner similar to the stack-based algorithms for       */
++/*  monotone polygons.  For each reflex vertex (local concavity) of the      */
++/*  polygon, there will be an inverted triangle formed by one of the edge    */
++/*  flips.  (An inverted triangle is one with negative area - that is, its   */
++/*  vertices are arranged in clockwise order - and is best thought of as a   */
++/*  wrinkle in the fabric of the mesh.)  Each inverted triangle can be       */
++/*  thought of as a reflex vertex pushed on the stack, waiting to be fixed   */
++/*  later.                                                                   */
++/*                                                                           */
++/*  A reflex vertex is popped from the stack when a vertex is inserted that  */
++/*  is visible to the reflex vertex.  (However, if the vertex behind the     */
++/*  reflex vertex is not visible to the reflex vertex, a new inverted        */
++/*  triangle will take its place on the stack.)  These details are handled   */
++/*  by the delaunayfixup() routine above.                                    */
++/*                                                                           */
++/*****************************************************************************/
++
++void constrainededge(starttri, endpoint2, newmark)
++struct triedge *starttri;
++point endpoint2;
++int newmark;
++{
++  struct triedge fixuptri, fixuptri2;
++  struct edge fixupedge;
++  point endpoint1;
++  point farpoint;
++  REAL area;
++  int collision;
++  int done;
++  triangle ptr;             /* Temporary variable used by sym() and oprev(). */
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  org(*starttri, endpoint1);
++  lnext(*starttri, fixuptri);
++  flip(&fixuptri);
++  /* `collision' indicates whether we have found a point directly */
++  /*   between endpoint1 and endpoint2.                           */
++  collision = 0;
++  done = 0;
++  do {
++    org(fixuptri, farpoint);
++    /* `farpoint' is the extreme point of the polygon we are "digging" */
++    /*   to get from endpoint1 to endpoint2.                           */
++    if ((farpoint[0] == endpoint2[0]) && (farpoint[1] == endpoint2[1])) {
++      oprev(fixuptri, fixuptri2);
++      /* Enforce the Delaunay condition around endpoint2. */
++      delaunayfixup(&fixuptri, 0);
++      delaunayfixup(&fixuptri2, 1);
++      done = 1;
++    } else {
++      /* Check whether farpoint is to the left or right of the segment */
++      /*   being inserted, to decide which edge of fixuptri to dig     */
++      /*   through next.                                               */
++      area = counterclockwise(endpoint1, endpoint2, farpoint);
++      if (area == 0.0) {
++        /* We've collided with a point between endpoint1 and endpoint2. */
++        collision = 1;
++        oprev(fixuptri, fixuptri2);
++        /* Enforce the Delaunay condition around farpoint. */
++        delaunayfixup(&fixuptri, 0);
++        delaunayfixup(&fixuptri2, 1);
++        done = 1;
++      } else {
++        if (area > 0.0) {         /* farpoint is to the left of the segment. */
++          oprev(fixuptri, fixuptri2);
++          /* Enforce the Delaunay condition around farpoint, on the */
++          /*   left side of the segment only.                       */
++          delaunayfixup(&fixuptri2, 1);
++          /* Flip the edge that crosses the segment.  After the edge is */
++          /*   flipped, one of its endpoints is the fan vertex, and the */
++          /*   destination of fixuptri is the fan vertex.               */
++          lprevself(fixuptri);
++        } else {                 /* farpoint is to the right of the segment. */
++          delaunayfixup(&fixuptri, 0);
++          /* Flip the edge that crosses the segment.  After the edge is */
++          /*   flipped, one of its endpoints is the fan vertex, and the */
++          /*   destination of fixuptri is the fan vertex.               */
++          oprevself(fixuptri);
++        }
++        /* Check for two intersecting segments. */
++        tspivot(fixuptri, fixupedge);
++        if (fixupedge.sh == dummysh) {
++          flip(&fixuptri);   /* May create an inverted triangle on the left. */
++        } else {
++          /* We've collided with a segment between endpoint1 and endpoint2. */
++          collision = 1;
++          /* Insert a point at the intersection. */
++          segmentintersection(&fixuptri, &fixupedge, endpoint2);
++          done = 1;
++        }
++      }
++    }
++  } while (!done);
++  /* Insert a shell edge to make the segment permanent. */
++  insertshelle(&fixuptri, newmark);
++  /* If there was a collision with an interceding vertex, install another */
++  /*   segment connecting that vertex with endpoint2.                     */
++  if (collision) {
++    /* Insert the remainder of the segment. */
++    if (!scoutsegment(&fixuptri, endpoint2, newmark)) {
++      constrainededge(&fixuptri, endpoint2, newmark);
++    }
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  insertsegment()   Insert a PSLG segment into a triangulation.            */
++/*                                                                           */
++/*****************************************************************************/
++
++void insertsegment(endpoint1, endpoint2, newmark)
++point endpoint1;
++point endpoint2;
++int newmark;
++{
++  struct triedge searchtri1, searchtri2;
++  triangle encodedtri;
++  point checkpoint;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++
++  if (verbose > 1) {
++    printf("  Connecting (%.12g, %.12g) to (%.12g, %.12g).\n",
++           endpoint1[0], endpoint1[1], endpoint2[0], endpoint2[1]);
++  }
++
++  /* Find a triangle whose origin is the segment's first endpoint. */
++  checkpoint = (point) NULL;
++  encodedtri = point2tri(endpoint1);
++  if (encodedtri != (triangle) NULL) {
++    decode(encodedtri, searchtri1);
++    org(searchtri1, checkpoint);
++  }
++  if (checkpoint != endpoint1) {
++    /* Find a boundary triangle to search from. */
++    searchtri1.tri = dummytri;
++    searchtri1.orient = 0;
++    symself(searchtri1);
++    /* Search for the segment's first endpoint by point location. */
++    if (locate(endpoint1, &searchtri1) != ONVERTEX) {
++      printf(
++        "Internal error in insertsegment():  Unable to locate PSLG point\n");
++      printf("  (%.12g, %.12g) in triangulation.\n",
++             endpoint1[0], endpoint1[1]);
++      internalerror();
++    }
++  }
++  /* Remember this triangle to improve subsequent point location. */
++  triedgecopy(searchtri1, recenttri);
++  /* Scout the beginnings of a path from the first endpoint */
++  /*   toward the second.                                   */
++  if (scoutsegment(&searchtri1, endpoint2, newmark)) {
++    /* The segment was easily inserted. */
++    return;
++  }
++  /* The first endpoint may have changed if a collision with an intervening */
++  /*   vertex on the segment occurred.                                      */
++  org(searchtri1, endpoint1);
++
++  /* Find a triangle whose origin is the segment's second endpoint. */
++  checkpoint = (point) NULL;
++  encodedtri = point2tri(endpoint2);
++  if (encodedtri != (triangle) NULL) {
++    decode(encodedtri, searchtri2);
++    org(searchtri2, checkpoint);
++  }
++  if (checkpoint != endpoint2) {
++    /* Find a boundary triangle to search from. */
++    searchtri2.tri = dummytri;
++    searchtri2.orient = 0;
++    symself(searchtri2);
++    /* Search for the segment's second endpoint by point location. */
++    if (locate(endpoint2, &searchtri2) != ONVERTEX) {
++      printf(
++        "Internal error in insertsegment():  Unable to locate PSLG point\n");
++      printf("  (%.12g, %.12g) in triangulation.\n",
++             endpoint2[0], endpoint2[1]);
++      internalerror();
++    }
++  }
++  /* Remember this triangle to improve subsequent point location. */
++  triedgecopy(searchtri2, recenttri);
++  /* Scout the beginnings of a path from the second endpoint */
++  /*   toward the first.                                     */
++  if (scoutsegment(&searchtri2, endpoint1, newmark)) {
++    /* The segment was easily inserted. */
++    return;
++  }
++  /* The second endpoint may have changed if a collision with an intervening */
++  /*   vertex on the segment occurred.                                       */
++  org(searchtri2, endpoint2);
++
++#ifndef REDUCED
++#ifndef CDT_ONLY
++  if (splitseg) {
++    /* Insert vertices to force the segment into the triangulation. */
++    conformingedge(endpoint1, endpoint2, newmark);
++  } else {
++#endif /* not CDT_ONLY */
++#endif /* not REDUCED */
++    /* Insert the segment directly into the triangulation. */
++    constrainededge(&searchtri1, endpoint2, newmark);
++#ifndef REDUCED
++#ifndef CDT_ONLY
++  }
++#endif /* not CDT_ONLY */
++#endif /* not REDUCED */
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  markhull()   Cover the convex hull of a triangulation with shell edges.  */
++/*                                                                           */
++/*****************************************************************************/
++
++void markhull()
++{
++  struct triedge hulltri;
++  struct triedge nexttri;
++  struct triedge starttri;
++  triangle ptr;             /* Temporary variable used by sym() and oprev(). */
++
++  /* Find a triangle handle on the hull. */
++  hulltri.tri = dummytri;
++  hulltri.orient = 0;
++  symself(hulltri);
++  /* Remember where we started so we know when to stop. */
++  triedgecopy(hulltri, starttri);
++  /* Go once counterclockwise around the convex hull. */
++  do {
++    /* Create a shell edge if there isn't already one here. */
++    insertshelle(&hulltri, 1);
++    /* To find the next hull edge, go clockwise around the next vertex. */
++    lnextself(hulltri);
++    oprev(hulltri, nexttri);
++    while (nexttri.tri != dummytri) {
++      triedgecopy(nexttri, hulltri);
++      oprev(hulltri, nexttri);
++    }
++  } while (!triedgeequal(hulltri, starttri));
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  formskeleton()   Create the shell edges of a triangulation, including    */
++/*                   PSLG edges and edges on the convex hull.                */
++/*                                                                           */
++/*  The PSLG edges are read from a .poly file.  The return value is the      */
++/*  number of segments in the file.                                          */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifdef TRILIBRARY
++
++int formskeleton(segmentlist, segmentmarkerlist, numberofsegments)
++int *segmentlist;
++int *segmentmarkerlist;
++int numberofsegments;
++
++#else /* not TRILIBRARY */
++
++int formskeleton(polyfile, polyfilename)
++FILE *polyfile;
++char *polyfilename;
++
++#endif /* not TRILIBRARY */
++
++{
++#ifdef TRILIBRARY
++  char polyfilename[6];
++  int index;
++#else /* not TRILIBRARY */
++  char inputline[INPUTLINESIZE];
++  char *stringptr;
++#endif /* not TRILIBRARY */
++  point endpoint1, endpoint2;
++  int segments;
++  int segmentmarkers;
++  int end1, end2;
++  int boundmarker;
++  int i;
++
++  if (poly) {
++    if (!quiet) {
++      printf("Inserting segments into Delaunay triangulation.\n");
++    }
++#ifdef TRILIBRARY
++    strcpy(polyfilename, "input");
++    segments = numberofsegments;
++    segmentmarkers = segmentmarkerlist != (int *) NULL;
++    index = 0;
++#else /* not TRILIBRARY */
++    /* Read the segments from a .poly file. */
++    /* Read number of segments and number of boundary markers. */
++    stringptr = readline(inputline, polyfile, polyfilename);
++    segments = (int) strtol (stringptr, &stringptr, 0);
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      segmentmarkers = 0;
++    } else {
++      segmentmarkers = (int) strtol (stringptr, &stringptr, 0);
++    }
++#endif /* not TRILIBRARY */
++    /* If segments are to be inserted, compute a mapping */
++    /*   from points to triangles.                       */
++    if (segments > 0) {
++      if (verbose) {
++        printf("  Inserting PSLG segments.\n");
++      }
++      makepointmap();
++    }
++
++    boundmarker = 0;
++    /* Read and insert the segments. */
++    for (i = 1; i <= segments; i++) {
++#ifdef TRILIBRARY
++      end1 = segmentlist[index++];
++      end2 = segmentlist[index++];
++      if (segmentmarkers) {
++        boundmarker = segmentmarkerlist[i - 1];
++      }
++#else /* not TRILIBRARY */
++      stringptr = readline(inputline, polyfile, inpolyfilename);
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        printf("Error:  Segment %d has no endpoints in %s.\n", i,
++               polyfilename);
++        exit(1);
++      } else {
++        end1 = (int) strtol (stringptr, &stringptr, 0);
++      }
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        printf("Error:  Segment %d is missing its second endpoint in %s.\n", i,
++               polyfilename);
++        exit(1);
++      } else {
++        end2 = (int) strtol (stringptr, &stringptr, 0);
++      }
++      if (segmentmarkers) {
++        stringptr = findfield(stringptr);
++        if (*stringptr == '\0') {
++          boundmarker = 0;
++        } else {
++          boundmarker = (int) strtol (stringptr, &stringptr, 0);
++        }
++      }
++#endif /* not TRILIBRARY */
++      if ((end1 < firstnumber) || (end1 >= firstnumber + inpoints)) {
++        if (!quiet) {
++          printf("Warning:  Invalid first endpoint of segment %d in %s.\n", i,
++                 polyfilename);
++        }
++      } else if ((end2 < firstnumber) || (end2 >= firstnumber + inpoints)) {
++        if (!quiet) {
++          printf("Warning:  Invalid second endpoint of segment %d in %s.\n", i,
++                 polyfilename);
++        }
++      } else {
++        endpoint1 = getpoint(end1);
++        endpoint2 = getpoint(end2);
++        if ((endpoint1[0] == endpoint2[0]) && (endpoint1[1] == endpoint2[1])) {
++          if (!quiet) {
++            printf("Warning:  Endpoints of segment %d are coincident in %s.\n",
++                   i, polyfilename);
++          }
++        } else {
++          insertsegment(endpoint1, endpoint2, boundmarker);
++        }
++      }
++    }
++  } else {
++    segments = 0;
++  }
++  if (convex || !poly) {
++    /* Enclose the convex hull with shell edges. */
++    if (verbose) {
++      printf("  Enclosing convex hull with segments.\n");
++    }
++    markhull();
++  }
++  return segments;
++}
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Segment (shell edge) insertion ends here                  *********/
++
++/********* Carving out holes and concavities begins here             *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  infecthull()   Virally infect all of the triangles of the convex hull    */
++/*                 that are not protected by shell edges.  Where there are   */
++/*                 shell edges, set boundary markers as appropriate.         */
++/*                                                                           */
++/*****************************************************************************/
++
++void infecthull()
++{
++  struct triedge hulltri;
++  struct triedge nexttri;
++  struct triedge starttri;
++  struct edge hulledge;
++  triangle **deadtri;
++  point horg, hdest;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  if (verbose) {
++    printf("  Marking concavities (external triangles) for elimination.\n");
++  }
++  /* Find a triangle handle on the hull. */
++  hulltri.tri = dummytri;
++  hulltri.orient = 0;
++  symself(hulltri);
++  /* Remember where we started so we know when to stop. */
++  triedgecopy(hulltri, starttri);
++  /* Go once counterclockwise around the convex hull. */
++  do {
++    /* Ignore triangles that are already infected. */
++    if (!infected(hulltri)) {
++      /* Is the triangle protected by a shell edge? */
++      tspivot(hulltri, hulledge);
++      if (hulledge.sh == dummysh) {
++        /* The triangle is not protected; infect it. */
++        infect(hulltri);
++        deadtri = (triangle **) poolalloc(&viri);
++        *deadtri = hulltri.tri;
++      } else {
++        /* The triangle is protected; set boundary markers if appropriate. */
++        if (mark(hulledge) == 0) {
++          setmark(hulledge, 1);
++          org(hulltri, horg);
++          dest(hulltri, hdest);
++          if (pointmark(horg) == 0) {
++            setpointmark(horg, 1);
++          }
++          if (pointmark(hdest) == 0) {
++            setpointmark(hdest, 1);
++          }
++        }
++      }
++    }
++    /* To find the next hull edge, go clockwise around the next vertex. */
++    lnextself(hulltri);
++    oprev(hulltri, nexttri);
++    while (nexttri.tri != dummytri) {
++      triedgecopy(nexttri, hulltri);
++      oprev(hulltri, nexttri);
++    }
++  } while (!triedgeequal(hulltri, starttri));
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  plague()   Spread the virus from all infected triangles to any neighbors */
++/*             not protected by shell edges.  Delete all infected triangles. */
++/*                                                                           */
++/*  This is the procedure that actually creates holes and concavities.       */
++/*                                                                           */
++/*  This procedure operates in two phases.  The first phase identifies all   */
++/*  the triangles that will die, and marks them as infected.  They are       */
++/*  marked to ensure that each triangle is added to the virus pool only      */
++/*  once, so the procedure will terminate.                                   */
++/*                                                                           */
++/*  The second phase actually eliminates the infected triangles.  It also    */
++/*  eliminates orphaned points.                                              */
++/*                                                                           */
++/*****************************************************************************/
++
++void plague()
++{
++  struct triedge testtri;
++  struct triedge neighbor;
++  triangle **virusloop;
++  triangle **deadtri;
++  struct edge neighborshelle;
++  point testpoint;
++  point norg, ndest;
++  point deadorg, deaddest, deadapex;
++  int killorg;
++  triangle ptr;             /* Temporary variable used by sym() and onext(). */
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  if (verbose) {
++    printf("  Marking neighbors of marked triangles.\n");
++  }
++  /* Loop through all the infected triangles, spreading the virus to */
++  /*   their neighbors, then to their neighbors' neighbors.          */
++  traversalinit(&viri);
++  virusloop = (triangle **) traverse(&viri);
++  while (virusloop != (triangle **) NULL) {
++    testtri.tri = *virusloop;
++    /* A triangle is marked as infected by messing with one of its shell */
++    /*   edges, setting it to an illegal value.  Hence, we have to       */
++    /*   temporarily uninfect this triangle so that we can examine its   */
++    /*   adjacent shell edges.                                           */
++    uninfect(testtri);
++    if (verbose > 2) {
++      /* Assign the triangle an orientation for convenience in */
++      /*   checking its points.                                */
++      testtri.orient = 0;
++      org(testtri, deadorg);
++      dest(testtri, deaddest);
++      apex(testtri, deadapex);
++      printf("    Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
++             deadorg[0], deadorg[1], deaddest[0], deaddest[1],
++             deadapex[0], deadapex[1]);
++    }
++    /* Check each of the triangle's three neighbors. */
++    for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
++      /* Find the neighbor. */
++      sym(testtri, neighbor);
++      /* Check for a shell between the triangle and its neighbor. */
++      tspivot(testtri, neighborshelle);
++      /* Check if the neighbor is nonexistent or already infected. */
++      if ((neighbor.tri == dummytri) || infected(neighbor)) {
++        if (neighborshelle.sh != dummysh) {
++          /* There is a shell edge separating the triangle from its */
++          /*   neighbor, but both triangles are dying, so the shell */
++          /*   edge dies too.                                       */
++          shelledealloc(neighborshelle.sh);
++          if (neighbor.tri != dummytri) {
++            /* Make sure the shell edge doesn't get deallocated again */
++            /*   later when the infected neighbor is visited.         */
++            uninfect(neighbor);
++            tsdissolve(neighbor);
++            infect(neighbor);
++          }
++        }
++      } else {                   /* The neighbor exists and is not infected. */
++        if (neighborshelle.sh == dummysh) {
++          /* There is no shell edge protecting the neighbor, so */
++          /*   the neighbor becomes infected.                   */
++          if (verbose > 2) {
++            org(neighbor, deadorg);
++            dest(neighbor, deaddest);
++            apex(neighbor, deadapex);
++            printf(
++              "    Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
++                   deadorg[0], deadorg[1], deaddest[0], deaddest[1],
++                   deadapex[0], deadapex[1]);
++          }
++          infect(neighbor);
++          /* Ensure that the neighbor's neighbors will be infected. */
++          deadtri = (triangle **) poolalloc(&viri);
++          *deadtri = neighbor.tri;
++        } else {               /* The neighbor is protected by a shell edge. */
++          /* Remove this triangle from the shell edge. */
++          stdissolve(neighborshelle);
++          /* The shell edge becomes a boundary.  Set markers accordingly. */
++          if (mark(neighborshelle) == 0) {
++            setmark(neighborshelle, 1);
++          }
++          org(neighbor, norg);
++          dest(neighbor, ndest);
++          if (pointmark(norg) == 0) {
++            setpointmark(norg, 1);
++          }
++          if (pointmark(ndest) == 0) {
++            setpointmark(ndest, 1);
++          }
++        }
++      }
++    }
++    /* Remark the triangle as infected, so it doesn't get added to the */
++    /*   virus pool again.                                             */
++    infect(testtri);
++    virusloop = (triangle **) traverse(&viri);
++  }
++
++  if (verbose) {
++    printf("  Deleting marked triangles.\n");
++  }
++  traversalinit(&viri);
++  virusloop = (triangle **) traverse(&viri);
++  while (virusloop != (triangle **) NULL) {
++    testtri.tri = *virusloop;
++
++    /* Check each of the three corners of the triangle for elimination. */
++    /*   This is done by walking around each point, checking if it is   */
++    /*   still connected to at least one live triangle.                 */
++    for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
++      org(testtri, testpoint);
++      /* Check if the point has already been tested. */
++      if (testpoint != (point) NULL) {
++        killorg = 1;
++        /* Mark the corner of the triangle as having been tested. */
++        setorg(testtri, NULL);
++        /* Walk counterclockwise about the point. */
++        onext(testtri, neighbor);
++        /* Stop upon reaching a boundary or the starting triangle. */
++        while ((neighbor.tri != dummytri)
++               && (!triedgeequal(neighbor, testtri))) {
++          if (infected(neighbor)) {
++            /* Mark the corner of this triangle as having been tested. */
++            setorg(neighbor, NULL);
++          } else {
++            /* A live triangle.  The point survives. */
++            killorg = 0;
++          }
++          /* Walk counterclockwise about the point. */
++          onextself(neighbor);
++        }
++        /* If we reached a boundary, we must walk clockwise as well. */
++        if (neighbor.tri == dummytri) {
++          /* Walk clockwise about the point. */
++          oprev(testtri, neighbor);
++          /* Stop upon reaching a boundary. */
++          while (neighbor.tri != dummytri) {
++            if (infected(neighbor)) {
++            /* Mark the corner of this triangle as having been tested. */
++              setorg(neighbor, NULL);
++            } else {
++              /* A live triangle.  The point survives. */
++              killorg = 0;
++            }
++            /* Walk clockwise about the point. */
++            oprevself(neighbor);
++          }
++        }
++        if (killorg) {
++          if (verbose > 1) {
++            printf("    Deleting point (%.12g, %.12g)\n",
++                   testpoint[0], testpoint[1]);
++          }
++          pointdealloc(testpoint);
++        }
++      }
++    }
++
++    /* Record changes in the number of boundary edges, and disconnect */
++    /*   dead triangles from their neighbors.                         */
++    for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
++      sym(testtri, neighbor);
++      if (neighbor.tri == dummytri) {
++        /* There is no neighboring triangle on this edge, so this edge    */
++        /*   is a boundary edge.  This triangle is being deleted, so this */
++        /*   boundary edge is deleted.                                    */
++        hullsize--;
++      } else {
++        /* Disconnect the triangle from its neighbor. */
++        dissolve(neighbor);
++        /* There is a neighboring triangle on this edge, so this edge */
++        /*   becomes a boundary edge when this triangle is deleted.   */
++        hullsize++;
++      }
++    }
++    /* Return the dead triangle to the pool of triangles. */
++    triangledealloc(testtri.tri);
++    virusloop = (triangle **) traverse(&viri);
++  }
++  /* Empty the virus pool. */
++  poolrestart(&viri);
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  regionplague()   Spread regional attributes and/or area constraints      */
++/*                   (from a .poly file) throughout the mesh.                */
++/*                                                                           */
++/*  This procedure operates in two phases.  The first phase spreads an       */
++/*  attribute and/or an area constraint through a (segment-bounded) region.  */
++/*  The triangles are marked to ensure that each triangle is added to the    */
++/*  virus pool only once, so the procedure will terminate.                   */
++/*                                                                           */
++/*  The second phase uninfects all infected triangles, returning them to     */
++/*  normal.                                                                  */
++/*                                                                           */
++/*****************************************************************************/
++
++void regionplague(attribute, area)
++REAL attribute;
++REAL area;
++{
++  struct triedge testtri;
++  struct triedge neighbor;
++  triangle **virusloop;
++  triangle **regiontri;
++  struct edge neighborshelle;
++  point regionorg, regiondest, regionapex;
++  triangle ptr;             /* Temporary variable used by sym() and onext(). */
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  if (verbose > 1) {
++    printf("  Marking neighbors of marked triangles.\n");
++  }
++  /* Loop through all the infected triangles, spreading the attribute      */
++  /*   and/or area constraint to their neighbors, then to their neighbors' */
++  /*   neighbors.                                                          */
++  traversalinit(&viri);
++  virusloop = (triangle **) traverse(&viri);
++  while (virusloop != (triangle **) NULL) {
++    testtri.tri = *virusloop;
++    /* A triangle is marked as infected by messing with one of its shell */
++    /*   edges, setting it to an illegal value.  Hence, we have to       */
++    /*   temporarily uninfect this triangle so that we can examine its   */
++    /*   adjacent shell edges.                                           */
++    uninfect(testtri);
++    if (regionattrib) {
++      /* Set an attribute. */
++      setelemattribute(testtri, eextras, attribute);
++    }
++    if (vararea) {
++      /* Set an area constraint. */
++      setareabound(testtri, area);
++    }
++    if (verbose > 2) {
++      /* Assign the triangle an orientation for convenience in */
++      /*   checking its points.                                */
++      testtri.orient = 0;
++      org(testtri, regionorg);
++      dest(testtri, regiondest);
++      apex(testtri, regionapex);
++      printf("    Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
++             regionorg[0], regionorg[1], regiondest[0], regiondest[1],
++             regionapex[0], regionapex[1]);
++    }
++    /* Check each of the triangle's three neighbors. */
++    for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
++      /* Find the neighbor. */
++      sym(testtri, neighbor);
++      /* Check for a shell between the triangle and its neighbor. */
++      tspivot(testtri, neighborshelle);
++      /* Make sure the neighbor exists, is not already infected, and */
++      /*   isn't protected by a shell edge.                          */
++      if ((neighbor.tri != dummytri) && !infected(neighbor)
++          && (neighborshelle.sh == dummysh)) {
++        if (verbose > 2) {
++          org(neighbor, regionorg);
++          dest(neighbor, regiondest);
++          apex(neighbor, regionapex);
++          printf("    Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
++                 regionorg[0], regionorg[1], regiondest[0], regiondest[1],
++                 regionapex[0], regionapex[1]);
++        }
++        /* Infect the neighbor. */
++        infect(neighbor);
++        /* Ensure that the neighbor's neighbors will be infected. */
++        regiontri = (triangle **) poolalloc(&viri);
++        *regiontri = neighbor.tri;
++      }
++    }
++    /* Remark the triangle as infected, so it doesn't get added to the */
++    /*   virus pool again.                                             */
++    infect(testtri);
++    virusloop = (triangle **) traverse(&viri);
++  }
++
++  /* Uninfect all triangles. */
++  if (verbose > 1) {
++    printf("  Unmarking marked triangles.\n");
++  }
++  traversalinit(&viri);
++  virusloop = (triangle **) traverse(&viri);
++  while (virusloop != (triangle **) NULL) {
++    testtri.tri = *virusloop;
++    uninfect(testtri);
++    virusloop = (triangle **) traverse(&viri);
++  }
++  /* Empty the virus pool. */
++  poolrestart(&viri);
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  carveholes()   Find the holes and infect them.  Find the area            */
++/*                 constraints and infect them.  Infect the convex hull.     */
++/*                 Spread the infection and kill triangles.  Spread the      */
++/*                 area constraints.                                         */
++/*                                                                           */
++/*  This routine mainly calls other routines to carry out all these          */
++/*  functions.                                                               */
++/*                                                                           */
++/*****************************************************************************/
++
++void carveholes(holelist, holes, regionlist, regions)
++REAL *holelist;
++int holes;
++REAL *regionlist;
++int regions;
++{
++  struct triedge searchtri;
++  struct triedge triangleloop;
++  struct triedge *regiontris;
++  triangle **holetri;
++  triangle **regiontri;
++  point searchorg, searchdest;
++  enum locateresult intersect;
++  int i;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++
++  if (!(quiet || (noholes && convex))) {
++    printf("Removing unwanted triangles.\n");
++    if (verbose && (holes > 0)) {
++      printf("  Marking holes for elimination.\n");
++    }
++  }
++
++  if (regions > 0) {
++    /* Allocate storage for the triangles in which region points fall. */
++    regiontris = (struct triedge *) malloc(regions * sizeof(struct triedge));
++    if (regiontris == (struct triedge *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++
++  if (((holes > 0) && !noholes) || !convex || (regions > 0)) {
++    /* Initialize a pool of viri to be used for holes, concavities, */
++    /*   regional attributes, and/or regional area constraints.     */
++    poolinit(&viri, sizeof(triangle *), VIRUSPERBLOCK, POINTER, 0);
++  }
++
++  if (!convex) {
++    /* Mark as infected any unprotected triangles on the boundary. */
++    /*   This is one way by which concavities are created.         */
++    infecthull();
++  }
++
++  if ((holes > 0) && !noholes) {
++    /* Infect each triangle in which a hole lies. */
++    for (i = 0; i < 2 * holes; i += 2) {
++      /* Ignore holes that aren't within the bounds of the mesh. */
++      if ((holelist[i] >= xmin) && (holelist[i] <= xmax)
++          && (holelist[i + 1] >= ymin) && (holelist[i + 1] <= ymax)) {
++        /* Start searching from some triangle on the outer boundary. */
++        searchtri.tri = dummytri;
++        searchtri.orient = 0;
++        symself(searchtri);
++        /* Ensure that the hole is to the left of this boundary edge; */
++        /*   otherwise, locate() will falsely report that the hole    */
++        /*   falls within the starting triangle.                      */
++        org(searchtri, searchorg);
++        dest(searchtri, searchdest);
++        if (counterclockwise(searchorg, searchdest, &holelist[i]) > 0.0) {
++          /* Find a triangle that contains the hole. */
++          intersect = locate(&holelist[i], &searchtri);
++          if ((intersect != OUTSIDE) && (!infected(searchtri))) {
++            /* Infect the triangle.  This is done by marking the triangle */
++            /*   as infect and including the triangle in the virus pool.  */
++            infect(searchtri);
++            holetri = (triangle **) poolalloc(&viri);
++            *holetri = searchtri.tri;
++          }
++        }
++      }
++    }
++  }
++
++  /* Now, we have to find all the regions BEFORE we carve the holes, because */
++  /*   locate() won't work when the triangulation is no longer convex.       */
++  /*   (Incidentally, this is the reason why regional attributes and area    */
++  /*   constraints can't be used when refining a preexisting mesh, which     */
++  /*   might not be convex; they can only be used with a freshly             */
++  /*   triangulated PSLG.)                                                   */
++  if (regions > 0) {
++    /* Find the starting triangle for each region. */
++    for (i = 0; i < regions; i++) {
++      regiontris[i].tri = dummytri;
++      /* Ignore region points that aren't within the bounds of the mesh. */
++      if ((regionlist[4 * i] >= xmin) && (regionlist[4 * i] <= xmax) &&
++          (regionlist[4 * i + 1] >= ymin) && (regionlist[4 * i + 1] <= ymax)) {
++        /* Start searching from some triangle on the outer boundary. */
++        searchtri.tri = dummytri;
++        searchtri.orient = 0;
++        symself(searchtri);
++        /* Ensure that the region point is to the left of this boundary */
++        /*   edge; otherwise, locate() will falsely report that the     */
++        /*   region point falls within the starting triangle.           */
++        org(searchtri, searchorg);
++        dest(searchtri, searchdest);
++        if (counterclockwise(searchorg, searchdest, &regionlist[4 * i]) >
++            0.0) {
++          /* Find a triangle that contains the region point. */
++          intersect = locate(&regionlist[4 * i], &searchtri);
++          if ((intersect != OUTSIDE) && (!infected(searchtri))) {
++            /* Record the triangle for processing after the */
++            /*   holes have been carved.                    */
++            triedgecopy(searchtri, regiontris[i]);
++          }
++        }
++      }
++    }
++  }
++
++  if (viri.items > 0) {
++    /* Carve the holes and concavities. */
++    plague();
++  }
++  /* The virus pool should be empty now. */
++
++  if (regions > 0) {
++    if (!quiet) {
++      if (regionattrib) {
++        if (vararea) {
++          printf("Spreading regional attributes and area constraints.\n");
++        } else {
++          printf("Spreading regional attributes.\n");
++        }
++      } else { 
++        printf("Spreading regional area constraints.\n");
++      }
++    }
++    if (regionattrib && !refine) {
++      /* Assign every triangle a regional attribute of zero. */
++      traversalinit(&triangles);
++      triangleloop.orient = 0;
++      triangleloop.tri = triangletraverse();
++      while (triangleloop.tri != (triangle *) NULL) {
++        setelemattribute(triangleloop, eextras, 0.0);
++        triangleloop.tri = triangletraverse();
++      }
++    }
++    for (i = 0; i < regions; i++) {
++      if (regiontris[i].tri != dummytri) {
++        /* Make sure the triangle under consideration still exists. */
++        /*   It may have been eaten by the virus.                   */
++        if (regiontris[i].tri[3] != (triangle) NULL) {
++          /* Put one triangle in the virus pool. */
++          infect(regiontris[i]);
++          regiontri = (triangle **) poolalloc(&viri);
++          *regiontri = regiontris[i].tri;
++          /* Apply one region's attribute and/or area constraint. */
++          regionplague(regionlist[4 * i + 2], regionlist[4 * i + 3]);
++          /* The virus pool should be empty now. */
++        }
++      }
++    }
++    if (regionattrib && !refine) {
++      /* Note the fact that each triangle has an additional attribute. */
++      eextras++;
++    }
++  }
++
++  /* Free up memory. */
++  if (((holes > 0) && !noholes) || !convex || (regions > 0)) {
++    pooldeinit(&viri);
++  }
++  if (regions > 0) {
++    free(regiontris);
++  }
++}
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Carving out holes and concavities ends here               *********/
++
++/********* Mesh quality maintenance begins here                      *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  tallyencs()   Traverse the entire list of shell edges, check each edge   */
++/*                to see if it is encroached.  If so, add it to the list.    */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++void tallyencs()
++{
++  struct edge edgeloop;
++  int dummy;
++
++  traversalinit(&shelles);
++  edgeloop.shorient = 0;
++  edgeloop.sh = shelletraverse();
++  while (edgeloop.sh != (shelle *) NULL) {
++    /* If the segment is encroached, add it to the list. */
++    dummy = checkedge4encroach(&edgeloop);
++    edgeloop.sh = shelletraverse();
++  }
++}
++
++#endif /* not CDT_ONLY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  precisionerror()  Print an error message for precision problems.         */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++void precisionerror()
++{
++  printf("Try increasing the area criterion and/or reducing the minimum\n");
++  printf("  allowable angle so that tiny triangles are not created.\n");
++#ifdef SINGLE
++  printf("Alternatively, try recompiling me with double precision\n");
++  printf("  arithmetic (by removing \"#define SINGLE\" from the\n");
++  printf("  source file or \"-DSINGLE\" from the makefile).\n");
++#endif /* SINGLE */
++}
++
++#endif /* not CDT_ONLY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  repairencs()   Find and repair all the encroached segments.              */
++/*                                                                           */
++/*  Encroached segments are repaired by splitting them by inserting a point  */
++/*  at or near their centers.                                                */
++/*                                                                           */
++/*  `flaws' is a flag that specifies whether one should take note of new     */
++/*  encroached segments and bad triangles that result from inserting points  */
++/*  to repair existing encroached segments.                                  */
++/*                                                                           */
++/*  When a segment is split, the two resulting subsegments are always        */
++/*  tested to see if they are encroached upon, regardless of the value       */
++/*  of `flaws'.                                                              */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++void repairencs(flaws)
++int flaws;
++{
++  struct triedge enctri;
++  struct triedge testtri;
++  struct edge *encloop;
++  struct edge testsh;
++  point eorg, edest;
++  point newpoint;
++  enum insertsiteresult success;
++  REAL segmentlength, nearestpoweroftwo;
++  REAL split;
++  int acuteorg, acutedest;
++  int dummy;
++  int i;
++  triangle ptr;                     /* Temporary variable used by stpivot(). */
++  shelle sptr;                        /* Temporary variable used by snext(). */
++
++  while ((badsegments.items > 0) && (steinerleft != 0)) {
++    traversalinit(&badsegments);
++    encloop = badsegmenttraverse();
++    while ((encloop != (struct edge *) NULL) && (steinerleft != 0)) {
++      /* To decide where to split a segment, we need to know if the  */
++      /*   segment shares an endpoint with an adjacent segment.      */
++      /*   The concern is that, if we simply split every encroached  */
++      /*   segment in its center, two adjacent segments with a small */
++      /*   angle between them might lead to an infinite loop; each   */
++      /*   point added to split one segment will encroach upon the   */
++      /*   other segment, which must then be split with a point that */
++      /*   will encroach upon the first segment, and so on forever.  */
++      /* To avoid this, imagine a set of concentric circles, whose   */
++      /*   radii are powers of two, about each segment endpoint.     */
++      /*   These concentric circles determine where the segment is   */
++      /*   split.  (If both endpoints are shared with adjacent       */
++      /*   segments, split the segment in the middle, and apply the  */
++      /*   concentric shells for later splittings.)                  */
++
++      /* Is the origin shared with another segment? */
++      stpivot(*encloop, enctri);
++      lnext(enctri, testtri);
++      tspivot(testtri, testsh);
++      acuteorg = testsh.sh != dummysh;
++      /* Is the destination shared with another segment? */
++      lnextself(testtri);
++      tspivot(testtri, testsh);
++      acutedest = testsh.sh != dummysh;
++      /* Now, check the other side of the segment, if there's a triangle */
++      /*   there.                                                        */
++      sym(enctri, testtri);
++      if (testtri.tri != dummytri) {
++        /* Is the destination shared with another segment? */
++        lnextself(testtri);
++        tspivot(testtri, testsh);
++        acutedest = acutedest || (testsh.sh != dummysh);
++        /* Is the origin shared with another segment? */
++        lnextself(testtri);
++        tspivot(testtri, testsh);
++        acuteorg = acuteorg || (testsh.sh != dummysh);
++      }
++
++      sorg(*encloop, eorg);
++      sdest(*encloop, edest);
++      /* Use the concentric circles if exactly one endpoint is shared */
++      /*   with another adjacent segment.                             */
++      if (acuteorg ^ acutedest) {
++        segmentlength = sqrt((edest[0] - eorg[0]) * (edest[0] - eorg[0])
++                             + (edest[1] - eorg[1]) * (edest[1] - eorg[1]));
++        /* Find the power of two nearest the segment's length. */
++        nearestpoweroftwo = 1.0;
++        while (segmentlength > SQUAREROOTTWO * nearestpoweroftwo) {
++          nearestpoweroftwo *= 2.0;
++        }
++        while (segmentlength < (0.5 * SQUAREROOTTWO) * nearestpoweroftwo) {
++          nearestpoweroftwo *= 0.5;
++        }
++        /* Where do we split the segment? */
++        split = 0.5 * nearestpoweroftwo / segmentlength;
++        if (acutedest) {
++          split = 1.0 - split;
++        }
++      } else {
++        /* If we're not worried about adjacent segments, split */
++        /*   this segment in the middle.                       */
++        split = 0.5;
++      }
++
++      /* Create the new point. */
++      newpoint = (point) poolalloc(&points);
++      /* Interpolate its coordinate and attributes. */
++      for (i = 0; i < 2 + nextras; i++) {
++        newpoint[i] = (1.0 - split) * eorg[i] + split * edest[i];
++      }
++      setpointmark(newpoint, mark(*encloop));
++      if (verbose > 1) {
++        printf(
++        "  Splitting edge (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n",
++               eorg[0], eorg[1], edest[0], edest[1], newpoint[0], newpoint[1]);
++      }
++      /* Check whether the new point lies on an endpoint. */
++      if (((newpoint[0] == eorg[0]) && (newpoint[1] == eorg[1]))
++        || ((newpoint[0] == edest[0]) && (newpoint[1] == edest[1]))) {
++        printf("Error:  Ran out of precision at (%.12g, %.12g).\n",
++               newpoint[0], newpoint[1]);
++        printf("I attempted to split a segment to a smaller size than can\n");
++        printf("  be accommodated by the finite precision of floating point\n"
++               );
++        printf("  arithmetic.\n");
++        precisionerror();
++        exit(1);
++      }
++      /* Insert the splitting point.  This should always succeed. */
++      success = insertsite(newpoint, &enctri, encloop, flaws, flaws);
++      if ((success != SUCCESSFULPOINT) && (success != ENCROACHINGPOINT)) {
++        printf("Internal error in repairencs():\n");
++        printf("  Failure to split a segment.\n");
++        internalerror();
++      }
++      if (steinerleft > 0) {
++        steinerleft--;
++      }
++      /* Check the two new subsegments to see if they're encroached. */
++      dummy = checkedge4encroach(encloop);
++      snextself(*encloop);
++      dummy = checkedge4encroach(encloop);
++
++      badsegmentdealloc(encloop);
++      encloop = badsegmenttraverse();
++    }
++  }
++}
++
++#endif /* not CDT_ONLY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  tallyfaces()   Test every triangle in the mesh for quality measures.     */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++void tallyfaces()
++{
++  struct triedge triangleloop;
++
++  if (verbose) {
++    printf("  Making a list of bad triangles.\n");
++  }
++  traversalinit(&triangles);
++  triangleloop.orient = 0;
++  triangleloop.tri = triangletraverse();
++  while (triangleloop.tri != (triangle *) NULL) {
++    /* If the triangle is bad, enqueue it. */
++    testtriangle(&triangleloop);
++    triangleloop.tri = triangletraverse();
++  }
++}
++
++#endif /* not CDT_ONLY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  findcircumcenter()   Find the circumcenter of a triangle.                */
++/*                                                                           */
++/*  The result is returned both in terms of x-y coordinates and xi-eta       */
++/*  coordinates.  The xi-eta coordinate system is defined in terms of the    */
++/*  triangle:  the origin of the triangle is the origin of the coordinate    */
++/*  system; the destination of the triangle is one unit along the xi axis;   */
++/*  and the apex of the triangle is one unit along the eta axis.             */
++/*                                                                           */
++/*  The return value indicates which edge of the triangle is shortest.       */
++/*                                                                           */
++/*****************************************************************************/
++
++enum circumcenterresult findcircumcenter(torg, tdest, tapex, circumcenter,
++                                         xi, eta)
++point torg;
++point tdest;
++point tapex;
++point circumcenter;
++REAL *xi;
++REAL *eta;
++{
++  REAL xdo, ydo, xao, yao, xad, yad;
++  REAL dodist, aodist, addist;
++  REAL denominator;
++  REAL dx, dy;
++
++  circumcentercount++;
++
++  /* Compute the circumcenter of the triangle. */
++  xdo = tdest[0] - torg[0];
++  ydo = tdest[1] - torg[1];
++  xao = tapex[0] - torg[0];
++  yao = tapex[1] - torg[1];
++  dodist = xdo * xdo + ydo * ydo;
++  aodist = xao * xao + yao * yao;
++  if (noexact) {
++    denominator = 0.5 / (xdo * yao - xao * ydo);
++  } else {
++    /* Use the counterclockwise() routine to ensure a positive (and */
++    /*   reasonably accurate) result, avoiding any possibility of   */
++    /*   division by zero.                                          */
++    denominator = 0.5 / counterclockwise(tdest, tapex, torg);
++    /* Don't count the above as an orientation test. */
++    counterclockcount--;
++  }
++  circumcenter[0] = torg[0] - (ydo * aodist - yao * dodist) * denominator;  
++  circumcenter[1] = torg[1] + (xdo * aodist - xao * dodist) * denominator;  
++
++  /* To interpolate point attributes for the new point inserted at  */
++  /*   the circumcenter, define a coordinate system with a xi-axis, */
++  /*   directed from the triangle's origin to its destination, and  */
++  /*   an eta-axis, directed from its origin to its apex.           */
++  /*   Calculate the xi and eta coordinates of the circumcenter.    */
++  dx = circumcenter[0] - torg[0];
++  dy = circumcenter[1] - torg[1];
++  *xi = (dx * yao - xao * dy) * (2.0 * denominator);
++  *eta = (xdo * dy - dx * ydo) * (2.0 * denominator);
++
++  xad = tapex[0] - tdest[0];
++  yad = tapex[1] - tdest[1];
++  addist = xad * xad + yad * yad;
++  if ((addist < dodist) && (addist < aodist)) {
++    return OPPOSITEORG;
++  } else if (dodist < aodist) {
++    return OPPOSITEAPEX;
++  } else {
++    return OPPOSITEDEST;
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  splittriangle()   Inserts a point at the circumcenter of a triangle.     */
++/*                    Deletes the newly inserted point if it encroaches upon */
++/*                    a segment.                                             */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++void splittriangle(badtri)
++struct badface *badtri;
++{
++  point borg, bdest, bapex;
++  point newpoint;
++  REAL xi, eta;
++  enum insertsiteresult success;
++  enum circumcenterresult shortedge;
++  int errorflag;
++  int i;
++
++  org(badtri->badfacetri, borg);
++  dest(badtri->badfacetri, bdest);
++  apex(badtri->badfacetri, bapex);
++  /* Make sure that this triangle is still the same triangle it was      */
++  /*   when it was tested and determined to be of bad quality.           */
++  /*   Subsequent transformations may have made it a different triangle. */
++  if ((borg == badtri->faceorg) && (bdest == badtri->facedest) &&
++      (bapex == badtri->faceapex)) {
++    if (verbose > 1) {
++      printf("  Splitting this triangle at its circumcenter:\n");
++      printf("    (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", borg[0],
++             borg[1], bdest[0], bdest[1], bapex[0], bapex[1]);
++    }
++    errorflag = 0;
++    /* Create a new point at the triangle's circumcenter. */
++    newpoint = (point) poolalloc(&points);
++    shortedge = findcircumcenter(borg, bdest, bapex, newpoint, &xi, &eta);
++    /* Check whether the new point lies on a triangle vertex. */
++    if (((newpoint[0] == borg[0]) && (newpoint[1] == borg[1]))
++        || ((newpoint[0] == bdest[0]) && (newpoint[1] == bdest[1]))
++        || ((newpoint[0] == bapex[0]) && (newpoint[1] == bapex[1]))) {
++      if (!quiet) {
++        printf("Warning:  New point (%.12g, %.12g) falls on existing vertex.\n"
++               , newpoint[0], newpoint[1]);
++        errorflag = 1;
++      }
++      pointdealloc(newpoint);
++    } else {
++      for (i = 2; i < 2 + nextras; i++) {
++        /* Interpolate the point attributes at the circumcenter. */
++        newpoint[i] = borg[i] + xi * (bdest[i] - borg[i])
++                             + eta * (bapex[i] - borg[i]);
++      }
++      /* The new point must be in the interior, and have a marker of zero. */
++      setpointmark(newpoint, 0);
++      /* Ensure that the handle `badtri->badfacetri' represents the shortest */
++      /*   edge of the triangle.  This ensures that the circumcenter must    */
++      /*   fall to the left of this edge, so point location will work.       */
++      if (shortedge == OPPOSITEORG) {
++        lnextself(badtri->badfacetri);
++      } else if (shortedge == OPPOSITEDEST) {
++        lprevself(badtri->badfacetri);
++      }
++      /* Insert the circumcenter, searching from the edge of the triangle, */
++      /*   and maintain the Delaunay property of the triangulation.        */
++      success = insertsite(newpoint, &(badtri->badfacetri),
++                           (struct edge *) NULL, 1, 1);
++      if (success == SUCCESSFULPOINT) {
++        if (steinerleft > 0) {
++          steinerleft--;
++        }
++      } else if (success == ENCROACHINGPOINT) {
++        /* If the newly inserted point encroaches upon a segment, delete it. */
++        deletesite(&(badtri->badfacetri));
++      } else if (success == VIOLATINGPOINT) {
++        /* Failed to insert the new point, but some segment was */
++        /*   marked as being encroached.                        */
++        pointdealloc(newpoint);
++      } else {                                  /* success == DUPLICATEPOINT */
++        /* Failed to insert the new point because a vertex is already there. */
++        if (!quiet) {
++          printf(
++            "Warning:  New point (%.12g, %.12g) falls on existing vertex.\n"
++                 , newpoint[0], newpoint[1]);
++          errorflag = 1;
++        }
++        pointdealloc(newpoint);
++      }
++    }
++    if (errorflag) {
++      if (verbose) {
++        printf("  The new point is at the circumcenter of triangle\n");
++        printf("    (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
++               borg[0], borg[1], bdest[0], bdest[1], bapex[0], bapex[1]);
++      }
++      printf("This probably means that I am trying to refine triangles\n");
++      printf("  to a smaller size than can be accommodated by the finite\n");
++      printf("  precision of floating point arithmetic.  (You can be\n");
++      printf("  sure of this if I fail to terminate.)\n");
++      precisionerror();
++    }
++  }
++  /* Return the bad triangle to the pool. */
++  pooldealloc(&badtriangles, (VOID *) badtri);
++}
++
++#endif /* not CDT_ONLY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  enforcequality()   Remove all the encroached edges and bad triangles     */
++/*                     from the triangulation.                               */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef CDT_ONLY
++
++void enforcequality()
++{
++  int i;
++
++  if (!quiet) {
++    printf("Adding Steiner points to enforce quality.\n");
++  }
++  /* Initialize the pool of encroached segments. */
++  poolinit(&badsegments, sizeof(struct edge), BADSEGMENTPERBLOCK, POINTER, 0);
++  if (verbose) {
++    printf("  Looking for encroached segments.\n");
++  }
++  /* Test all segments to see if they're encroached. */
++  tallyencs();
++  if (verbose && (badsegments.items > 0)) {
++    printf("  Splitting encroached segments.\n");
++  }
++  /* Note that steinerleft == -1 if an unlimited number */
++  /*   of Steiner points is allowed.                    */
++  while ((badsegments.items > 0) && (steinerleft != 0)) {
++    /* Fix the segments without noting newly encroached segments or   */
++    /*   bad triangles.  The reason we don't want to note newly       */
++    /*   encroached segments is because some encroached segments are  */
++    /*   likely to be noted multiple times, and would then be blindly */
++    /*   split multiple times.  I should fix that some time.          */
++    repairencs(0);
++    /* Now, find all the segments that became encroached while adding */
++    /*   points to split encroached segments.                         */
++    tallyencs();
++  }
++  /* At this point, if we haven't run out of Steiner points, the */
++  /*   triangulation should be (conforming) Delaunay.            */
++
++  /* Next, we worry about enforcing triangle quality. */
++  if ((minangle > 0.0) || vararea || fixedarea) {
++    /* Initialize the pool of bad triangles. */
++    poolinit(&badtriangles, sizeof(struct badface), BADTRIPERBLOCK, POINTER,
++             0);
++    /* Initialize the queues of bad triangles. */
++    for (i = 0; i < 64; i++) {
++      queuefront[i] = (struct badface *) NULL;
++      queuetail[i] = &queuefront[i];
++    }
++    /* Test all triangles to see if they're bad. */
++    tallyfaces();
++    if (verbose) {
++      printf("  Splitting bad triangles.\n");
++    }
++    while ((badtriangles.items > 0) && (steinerleft != 0)) {
++      /* Fix one bad triangle by inserting a point at its circumcenter. */
++      splittriangle(dequeuebadtri());
++      /* Fix any encroached segments that may have resulted.  Record */
++      /*   any new bad triangles or encroached segments that result. */
++      if (badsegments.items > 0) {
++        repairencs(1);
++      }
++    }
++  }
++  /* At this point, if we haven't run out of Steiner points, the */
++  /*   triangulation should be (conforming) Delaunay and have no */
++  /*   low-quality triangles.                                    */
++
++  /* Might we have run out of Steiner points too soon? */
++  if (!quiet && (badsegments.items > 0) && (steinerleft == 0)) {
++    printf("\nWarning:  I ran out of Steiner points, but the mesh has\n");
++    if (badsegments.items == 1) {
++      printf("  an encroached segment, and therefore might not be truly\n");
++    } else {
++      printf("  %ld encroached segments, and therefore might not be truly\n",
++             badsegments.items);
++    }
++    printf("  Delaunay.  If the Delaunay property is important to you,\n");
++    printf("  try increasing the number of Steiner points (controlled by\n");
++    printf("  the -S switch) slightly and try again.\n\n");
++  }
++}
++
++#endif /* not CDT_ONLY */
++
++/**                                                                         **/
++/**                                                                         **/
++/********* Mesh quality maintenance ends here                        *********/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  highorder()   Create extra nodes for quadratic subparametric elements.   */
++/*                                                                           */
++/*****************************************************************************/
++
++void highorder()
++{
++  struct triedge triangleloop, trisym;
++  struct edge checkmark;
++  point newpoint;
++  point torg, tdest;
++  int i;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++  if (!quiet) {
++    printf("Adding vertices for second-order triangles.\n");
++  }
++  /* The following line ensures that dead items in the pool of nodes    */
++  /*   cannot be allocated for the extra nodes associated with high     */
++  /*   order elements.  This ensures that the primary nodes (at the     */
++  /*   corners of elements) will occur earlier in the output files, and */
++  /*   have lower indices, than the extra nodes.                        */
++  points.deaditemstack = (VOID *) NULL;
++
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  /* To loop over the set of edges, loop over all triangles, and look at   */
++  /*   the three edges of each triangle.  If there isn't another triangle  */
++  /*   adjacent to the edge, operate on the edge.  If there is another     */
++  /*   adjacent triangle, operate on the edge only if the current triangle */
++  /*   has a smaller pointer than its neighbor.  This way, each edge is    */
++  /*   considered only once.                                               */
++  while (triangleloop.tri != (triangle *) NULL) {
++    for (triangleloop.orient = 0; triangleloop.orient < 3;
++         triangleloop.orient++) {
++      sym(triangleloop, trisym);
++      if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) {
++        org(triangleloop, torg);
++        dest(triangleloop, tdest);
++        /* Create a new node in the middle of the edge.  Interpolate */
++        /*   its attributes.                                         */
++        newpoint = (point) poolalloc(&points);
++        for (i = 0; i < 2 + nextras; i++) {
++          newpoint[i] = 0.5 * (torg[i] + tdest[i]);
++        }
++        /* Set the new node's marker to zero or one, depending on */
++        /*   whether it lies on a boundary.                       */
++        setpointmark(newpoint, trisym.tri == dummytri);
++        if (useshelles) {
++          tspivot(triangleloop, checkmark);
++          /* If this edge is a segment, transfer the marker to the new node. */
++          if (checkmark.sh != dummysh) {
++            setpointmark(newpoint, mark(checkmark));
++          }
++        }
++        if (verbose > 1) {
++          printf("  Creating (%.12g, %.12g).\n", newpoint[0], newpoint[1]);
++        }
++        /* Record the new node in the (one or two) adjacent elements. */
++        triangleloop.tri[highorderindex + triangleloop.orient] =
++                (triangle) newpoint;
++        if (trisym.tri != dummytri) {
++          trisym.tri[highorderindex + trisym.orient] = (triangle) newpoint;
++        }
++      }
++    }
++    triangleloop.tri = triangletraverse();
++  }
++}
++
++/********* File I/O routines begin here                              *********/
++/**                                                                         **/
++/**                                                                         **/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  readline()   Read a nonempty line from a file.                           */
++/*                                                                           */
++/*  A line is considered "nonempty" if it contains something that looks like */
++/*  a number.                                                                */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef TRILIBRARY
++
++char *readline(string, infile, infilename)
++char *string;
++FILE *infile;
++char *infilename;
++{
++  char *result;
++
++  /* Search for something that looks like a number. */
++  do {
++    result = fgets(string, INPUTLINESIZE, infile);
++    if (result == (char *) NULL) {
++      printf("  Error:  Unexpected end of file in %s.\n", infilename);
++      exit(1);
++    }
++    /* Skip anything that doesn't look like a number, a comment, */
++    /*   or the end of a line.                                   */
++    while ((*result != '\0') && (*result != '#')
++           && (*result != '.') && (*result != '+') && (*result != '-')
++           && ((*result < '0') || (*result > '9'))) {
++      result++;
++    }
++  /* If it's a comment or end of line, read another line and try again. */
++  } while ((*result == '#') || (*result == '\0'));
++  return result;
++}
++
++#endif /* not TRILIBRARY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  findfield()   Find the next field of a string.                           */
++/*                                                                           */
++/*  Jumps past the current field by searching for whitespace, then jumps     */
++/*  past the whitespace to find the next field.                              */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef TRILIBRARY
++
++char *findfield(string)
++char *string;
++{
++  char *result;
++
++  result = string;
++  /* Skip the current field.  Stop upon reaching whitespace. */
++  while ((*result != '\0') && (*result != '#')
++         && (*result != ' ') && (*result != '\t')) {
++    result++;
++  }
++  /* Now skip the whitespace and anything else that doesn't look like a */
++  /*   number, a comment, or the end of a line.                         */
++  while ((*result != '\0') && (*result != '#')
++         && (*result != '.') && (*result != '+') && (*result != '-')
++         && ((*result < '0') || (*result > '9'))) {
++    result++;
++  }
++  /* Check for a comment (prefixed with `#'). */
++  if (*result == '#') {
++    *result = '\0';
++  }
++  return result;
++}
++
++#endif /* not TRILIBRARY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  readnodes()   Read the points from a file, which may be a .node or .poly */
++/*                file.                                                      */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef TRILIBRARY
++
++void readnodes(nodefilename, polyfilename, polyfile)
++char *nodefilename;
++char *polyfilename;
++FILE **polyfile;
++{
++  FILE *infile;
++  point pointloop;
++  char inputline[INPUTLINESIZE];
++  char *stringptr;
++  char *infilename;
++  REAL x, y;
++  int firstnode;
++  int nodemarkers;
++  int currentmarker;
++  int i, j;
++
++  if (poly) {
++    /* Read the points from a .poly file. */
++    if (!quiet) {
++      printf("Opening %s.\n", polyfilename);
++    }
++    *polyfile = fopen(polyfilename, "r");
++    if (*polyfile == (FILE *) NULL) {
++      printf("  Error:  Cannot access file %s.\n", polyfilename);
++      exit(1);
++    }
++    /* Read number of points, number of dimensions, number of point */
++    /*   attributes, and number of boundary markers.                */
++    stringptr = readline(inputline, *polyfile, polyfilename);
++    inpoints = (int) strtol (stringptr, &stringptr, 0);
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      mesh_dim = 2;
++    } else {
++      mesh_dim = (int) strtol (stringptr, &stringptr, 0);
++    }
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      nextras = 0;
++    } else {
++      nextras = (int) strtol (stringptr, &stringptr, 0);
++    }
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      nodemarkers = 0;
++    } else {
++      nodemarkers = (int) strtol (stringptr, &stringptr, 0);
++    }
++    if (inpoints > 0) {
++      infile = *polyfile;
++      infilename = polyfilename;
++      readnodefile = 0;
++    } else {
++      /* If the .poly file claims there are zero points, that means that */
++      /*   the points should be read from a separate .node file.         */
++      readnodefile = 1;
++      infilename = innodefilename;
++    }
++  } else {
++    readnodefile = 1;
++    infilename = innodefilename;
++    *polyfile = (FILE *) NULL;
++  }
++
++  if (readnodefile) {
++    /* Read the points from a .node file. */
++    if (!quiet) {
++      printf("Opening %s.\n", innodefilename);
++    }
++    infile = fopen(innodefilename, "r");
++    if (infile == (FILE *) NULL) {
++      printf("  Error:  Cannot access file %s.\n", innodefilename);
++      exit(1);
++    }
++    /* Read number of points, number of dimensions, number of point */
++    /*   attributes, and number of boundary markers.                */
++    stringptr = readline(inputline, infile, innodefilename);
++    inpoints = (int) strtol (stringptr, &stringptr, 0);
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      mesh_dim = 2;
++    } else {
++      mesh_dim = (int) strtol (stringptr, &stringptr, 0);
++    }
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      nextras = 0;
++    } else {
++      nextras = (int) strtol (stringptr, &stringptr, 0);
++    }
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      nodemarkers = 0;
++    } else {
++      nodemarkers = (int) strtol (stringptr, &stringptr, 0);
++    }
++  }
++
++  if (inpoints < 3) {
++    printf("Error:  Input must have at least three input points.\n");
++    exit(1);
++  }
++  if (mesh_dim != 2) {
++    printf("Error:  Triangle only works with two-dimensional meshes.\n");
++    exit(1);
++  }
++
++  initializepointpool();
++
++  /* Read the points. */
++  for (i = 0; i < inpoints; i++) {
++    pointloop = (point) poolalloc(&points);
++    stringptr = readline(inputline, infile, infilename);
++    if (i == 0) {
++      firstnode = (int) strtol (stringptr, &stringptr, 0);
++      if ((firstnode == 0) || (firstnode == 1)) {
++        firstnumber = firstnode;
++      }
++    }
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      printf("Error:  Point %d has no x coordinate.\n", firstnumber + i);
++      exit(1);
++    }
++    x = (REAL) strtod(stringptr, &stringptr);
++    stringptr = findfield(stringptr);
++    if (*stringptr == '\0') {
++      printf("Error:  Point %d has no y coordinate.\n", firstnumber + i);
++      exit(1);
++    }
++    y = (REAL) strtod(stringptr, &stringptr);
++    pointloop[0] = x;
++    pointloop[1] = y;
++    /* Read the point attributes. */
++    for (j = 2; j < 2 + nextras; j++) {
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        pointloop[j] = 0.0;
++      } else {
++        pointloop[j] = (REAL) strtod(stringptr, &stringptr);
++      }
++    }
++    if (nodemarkers) {
++      /* Read a point marker. */
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        setpointmark(pointloop, 0);
++      } else {
++        currentmarker = (int) strtol (stringptr, &stringptr, 0);
++        setpointmark(pointloop, currentmarker);
++      }
++    } else {
++      /* If no markers are specified in the file, they default to zero. */
++      setpointmark(pointloop, 0);
++    }
++    /* Determine the smallest and largest x and y coordinates. */
++    if (i == 0) {
++      xmin = xmax = x;
++      ymin = ymax = y;
++    } else {
++      xmin = (x < xmin) ? x : xmin;
++      xmax = (x > xmax) ? x : xmax;
++      ymin = (y < ymin) ? y : ymin;
++      ymax = (y > ymax) ? y : ymax;
++    }
++  }
++  if (readnodefile) {
++    fclose(infile);
++  }
++
++  /* Nonexistent x value used as a flag to mark circle events in sweepline */
++  /*   Delaunay algorithm.                                                 */
++  xminextreme = 10 * xmin - 9 * xmax;
++}
++
++#endif /* not TRILIBRARY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  transfernodes()   Read the points from memory.                           */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifdef TRILIBRARY
++
++void transfernodes(pointlist, pointattriblist, pointmarkerlist, numberofpoints,
++                   numberofpointattribs)
++REAL *pointlist;
++REAL *pointattriblist;
++int *pointmarkerlist;
++int numberofpoints;
++int numberofpointattribs;
++{
++  point pointloop;
++  REAL x, y;
++  int i, j;
++  int coordindex;
++  int attribindex;
++
++  inpoints = numberofpoints;
++  mesh_dim = 2;
++  nextras = numberofpointattribs;
++  readnodefile = 0;
++  if (inpoints < 3) {
++    printf("Error:  Input must have at least three input points.\n");
++    exit(1);
++  }
++
++  initializepointpool();
++
++  /* Read the points. */
++  coordindex = 0;
++  attribindex = 0;
++  for (i = 0; i < inpoints; i++) {
++    pointloop = (point) poolalloc(&points);
++    /* Read the point coordinates. */
++    x = pointloop[0] = pointlist[coordindex++];
++    y = pointloop[1] = pointlist[coordindex++];
++    /* Read the point attributes. */
++    for (j = 0; j < numberofpointattribs; j++) {
++      pointloop[2 + j] = pointattriblist[attribindex++];
++    }
++    if (pointmarkerlist != (int *) NULL) {
++      /* Read a point marker. */
++      setpointmark(pointloop, pointmarkerlist[i]);
++    } else {
++      /* If no markers are specified, they default to zero. */
++      setpointmark(pointloop, 0);
++    }
++    x = pointloop[0];
++    y = pointloop[1];
++    /* Determine the smallest and largest x and y coordinates. */
++    if (i == 0) {
++      xmin = xmax = x;
++      ymin = ymax = y;
++    } else {
++      xmin = (x < xmin) ? x : xmin;
++      xmax = (x > xmax) ? x : xmax;
++      ymin = (y < ymin) ? y : ymin;
++      ymax = (y > ymax) ? y : ymax;
++    }
++  }
++
++  /* Nonexistent x value used as a flag to mark circle events in sweepline */
++  /*   Delaunay algorithm.                                                 */
++  xminextreme = 10 * xmin - 9 * xmax;
++}
++
++#endif /* TRILIBRARY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  readholes()   Read the holes, and possibly regional attributes and area  */
++/*                constraints, from a .poly file.                            */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef TRILIBRARY
++
++void readholes(polyfile, polyfilename, hlist, holes, rlist, regions)
++FILE *polyfile;
++char *polyfilename;
++REAL **hlist;
++int *holes;
++REAL **rlist;
++int *regions;
++{
++  REAL *holelist;
++  REAL *regionlist;
++  char inputline[INPUTLINESIZE];
++  char *stringptr;
++  int index;
++  int i;
++
++  /* Read the holes. */
++  stringptr = readline(inputline, polyfile, polyfilename);
++  *holes = (int) strtol (stringptr, &stringptr, 0);
++  if (*holes > 0) {
++    holelist = (REAL *) malloc(2 * *holes * sizeof(REAL));
++    *hlist = holelist;
++    if (holelist == (REAL *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++    for (i = 0; i < 2 * *holes; i += 2) {
++      stringptr = readline(inputline, polyfile, polyfilename);
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        printf("Error:  Hole %d has no x coordinate.\n",
++               firstnumber + (i >> 1));
++        exit(1);
++      } else {
++        holelist[i] = (REAL) strtod(stringptr, &stringptr);
++      }
++      stringptr = findfield(stringptr);
++      if (*stringptr == '\0') {
++        printf("Error:  Hole %d has no y coordinate.\n",
++               firstnumber + (i >> 1));
++        exit(1);
++      } else {
++        holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
++      }
++    }
++  } else {
++    *hlist = (REAL *) NULL;
++  }
++
++#ifndef CDT_ONLY
++  if ((regionattrib || vararea) && !refine) {
++    /* Read the area constraints. */
++    stringptr = readline(inputline, polyfile, polyfilename);
++    *regions = (int) strtol (stringptr, &stringptr, 0);
++    if (*regions > 0) {
++      regionlist = (REAL *) malloc(4 * *regions * sizeof(REAL));
++      *rlist = regionlist;
++      if (regionlist == (REAL *) NULL) {
++        printf("Error:  Out of memory.\n");
++        exit(1);
++      }
++      index = 0;
++      for (i = 0; i < *regions; i++) {
++        stringptr = readline(inputline, polyfile, polyfilename);
++        stringptr = findfield(stringptr);
++        if (*stringptr == '\0') {
++          printf("Error:  Region %d has no x coordinate.\n",
++                 firstnumber + i);
++          exit(1);
++        } else {
++          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
++        }
++        stringptr = findfield(stringptr);
++        if (*stringptr == '\0') {
++          printf("Error:  Region %d has no y coordinate.\n",
++                 firstnumber + i);
++          exit(1);
++        } else {
++          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
++        }
++        stringptr = findfield(stringptr);
++        if (*stringptr == '\0') {
++          printf(
++            "Error:  Region %d has no region attribute or area constraint.\n",
++                 firstnumber + i);
++          exit(1);
++        } else {
++          regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
++        }
++        stringptr = findfield(stringptr);
++        if (*stringptr == '\0') {
++          regionlist[index] = regionlist[index - 1];
++        } else {
++          regionlist[index] = (REAL) strtod(stringptr, &stringptr);
++        }
++        index++;
++      }
++    }
++  } else {
++    /* Set `*regions' to zero to avoid an accidental free() later. */
++    *regions = 0;
++    *rlist = (REAL *) NULL;
++  }
++#endif /* not CDT_ONLY */
++
++  fclose(polyfile);
++}
++
++#endif /* not TRILIBRARY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  finishfile()   Write the command line to the output file so the user     */
++/*                 can remember how the file was generated.  Close the file. */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef TRILIBRARY
++
++void finishfile(outfile, argc, argv)
++FILE *outfile;
++int argc;
++char **argv;
++{
++  int i;
++
++  fprintf(outfile, "# Generated by");
++  for (i = 0; i < argc; i++) {
++    fprintf(outfile, " ");
++    fputs(argv[i], outfile);
++  }
++  fprintf(outfile, "\n");
++  fclose(outfile);
++}
++
++#endif /* not TRILIBRARY */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  writenodes()   Number the points and write them to a .node file.         */
++/*                                                                           */
++/*  To save memory, the point numbers are written over the shell markers     */
++/*  after the points are written to a file.                                  */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifdef TRILIBRARY
++
++void writenodes(pointlist, pointattriblist, pointmarkerlist)
++REAL **pointlist;
++REAL **pointattriblist;
++int **pointmarkerlist;
++
++#else /* not TRILIBRARY */
++
++void writenodes(nodefilename, argc, argv)
++char *nodefilename;
++int argc;
++char **argv;
++
++#endif /* not TRILIBRARY */
++
++{
++#ifdef TRILIBRARY
++  REAL *plist;
++  REAL *palist;
++  int *pmlist;
++  int coordindex;
++  int attribindex;
++#else /* not TRILIBRARY */
++  FILE *outfile;
++#endif /* not TRILIBRARY */
++  point pointloop;
++  int pointnumber;
++  int i;
++
++#ifdef TRILIBRARY
++  if (!quiet) {
++    printf("Writing points.\n");
++  }
++  /* Allocate memory for output points if necessary. */
++  if (*pointlist == (REAL *) NULL) {
++    *pointlist = (REAL *) malloc(points.items * 2 * sizeof(REAL));
++    if (*pointlist == (REAL *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  /* Allocate memory for output point attributes if necessary. */
++  if ((nextras > 0) && (*pointattriblist == (REAL *) NULL)) {
++    *pointattriblist = (REAL *) malloc(points.items * nextras * sizeof(REAL));
++    if (*pointattriblist == (REAL *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  /* Allocate memory for output point markers if necessary. */
++  if (!nobound && (*pointmarkerlist == (int *) NULL)) {
++    *pointmarkerlist = (int *) malloc(points.items * sizeof(int));
++    if (*pointmarkerlist == (int *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  plist = *pointlist;
++  palist = *pointattriblist;
++  pmlist = *pointmarkerlist;
++  coordindex = 0;
++  attribindex = 0;
++#else /* not TRILIBRARY */
++  if (!quiet) {
++    printf("Writing %s.\n", nodefilename);
++  }
++  outfile = fopen(nodefilename, "w");
++  if (outfile == (FILE *) NULL) {
++    printf("  Error:  Cannot create file %s.\n", nodefilename);
++    exit(1);
++  }
++  /* Number of points, number of dimensions, number of point attributes, */
++  /*   and number of boundary markers (zero or one).                     */
++  fprintf(outfile, "%ld  %d  %d  %d\n", points.items, mesh_dim, nextras,
++          1 - nobound);
++#endif /* not TRILIBRARY */
++
++  traversalinit(&points);
++  pointloop = pointtraverse();
++  pointnumber = firstnumber;
++  while (pointloop != (point) NULL) {
++#ifdef TRILIBRARY
++    /* X and y coordinates. */
++    plist[coordindex++] = pointloop[0];
++    plist[coordindex++] = pointloop[1];
++    /* Point attributes. */
++    for (i = 0; i < nextras; i++) {
++      palist[attribindex++] = pointloop[2 + i];
++    }
++    if (!nobound) {
++      /* Copy the boundary marker. */
++      pmlist[pointnumber - firstnumber] = pointmark(pointloop);
++    }
++#else /* not TRILIBRARY */
++    /* Point number, x and y coordinates. */
++    fprintf(outfile, "%4d    %.17g  %.17g", pointnumber, pointloop[0],
++            pointloop[1]);
++    for (i = 0; i < nextras; i++) {
++      /* Write an attribute. */
++      fprintf(outfile, "  %.17g", pointloop[i + 2]);
++    }
++    if (nobound) {
++      fprintf(outfile, "\n");
++    } else {
++      /* Write the boundary marker. */
++      fprintf(outfile, "    %d\n", pointmark(pointloop));
++    }
++#endif /* not TRILIBRARY */
++
++    setpointmark(pointloop, pointnumber);
++    pointloop = pointtraverse();
++    pointnumber++;
++  }
++
++#ifndef TRILIBRARY
++  finishfile(outfile, argc, argv);
++#endif /* not TRILIBRARY */
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  numbernodes()   Number the points.                                       */
++/*                                                                           */
++/*  Each point is assigned a marker equal to its number.                     */
++/*                                                                           */
++/*  Used when writenodes() is not called because no .node file is written.   */
++/*                                                                           */
++/*****************************************************************************/
++
++void numbernodes()
++{
++  point pointloop;
++  int pointnumber;
++
++  traversalinit(&points);
++  pointloop = pointtraverse();
++  pointnumber = firstnumber;
++  while (pointloop != (point) NULL) {
++    setpointmark(pointloop, pointnumber);
++    pointloop = pointtraverse();
++    pointnumber++;
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  writeelements()   Write the triangles to an .ele file.                   */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifdef TRILIBRARY
++
++void writeelements(trianglelist, triangleattriblist)
++int **trianglelist;
++REAL **triangleattriblist;
++
++#else /* not TRILIBRARY */
++
++void writeelements(elefilename, argc, argv)
++char *elefilename;
++int argc;
++char **argv;
++
++#endif /* not TRILIBRARY */
++
++{
++#ifdef TRILIBRARY
++  int *tlist;
++  REAL *talist;
++  int pointindex;
++  int attribindex;
++#else /* not TRILIBRARY */
++  FILE *outfile;
++#endif /* not TRILIBRARY */
++  struct triedge triangleloop;
++  point p1, p2, p3;
++  point mid1, mid2, mid3;
++  int elementnumber;
++  int i;
++
++#ifdef TRILIBRARY
++  if (!quiet) {
++    printf("Writing triangles.\n");
++  }
++  /* Allocate memory for output triangles if necessary. */
++  if (*trianglelist == (int *) NULL) {
++    *trianglelist = (int *) malloc(triangles.items *
++                               ((order + 1) * (order + 2) / 2) * sizeof(int));
++    if (*trianglelist == (int *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  /* Allocate memory for output triangle attributes if necessary. */
++  if ((eextras > 0) && (*triangleattriblist == (REAL *) NULL)) {
++    *triangleattriblist = (REAL *) malloc(triangles.items * eextras *
++                                          sizeof(REAL));
++    if (*triangleattriblist == (REAL *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  tlist = *trianglelist;
++  talist = *triangleattriblist;
++  pointindex = 0;
++  attribindex = 0;
++#else /* not TRILIBRARY */
++  if (!quiet) {
++    printf("Writing %s.\n", elefilename);
++  }
++  outfile = fopen(elefilename, "w");
++  if (outfile == (FILE *) NULL) {
++    printf("  Error:  Cannot create file %s.\n", elefilename);
++    exit(1);
++  }
++  /* Number of triangles, points per triangle, attributes per triangle. */
++  fprintf(outfile, "%ld  %d  %d\n", triangles.items,
++          (order + 1) * (order + 2) / 2, eextras);
++#endif /* not TRILIBRARY */
++
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  triangleloop.orient = 0;
++  elementnumber = firstnumber;
++  while (triangleloop.tri != (triangle *) NULL) {
++    org(triangleloop, p1);
++    dest(triangleloop, p2);
++    apex(triangleloop, p3);
++    if (order == 1) {
++#ifdef TRILIBRARY
++      tlist[pointindex++] = pointmark(p1);
++      tlist[pointindex++] = pointmark(p2);
++      tlist[pointindex++] = pointmark(p3);
++#else /* not TRILIBRARY */
++      /* Triangle number, indices for three points. */
++      fprintf(outfile, "%4d    %4d  %4d  %4d", elementnumber,
++              pointmark(p1), pointmark(p2), pointmark(p3));
++#endif /* not TRILIBRARY */
++    } else {
++      mid1 = (point) triangleloop.tri[highorderindex + 1];
++      mid2 = (point) triangleloop.tri[highorderindex + 2];
++      mid3 = (point) triangleloop.tri[highorderindex];
++#ifdef TRILIBRARY
++      tlist[pointindex++] = pointmark(p1);
++      tlist[pointindex++] = pointmark(p2);
++      tlist[pointindex++] = pointmark(p3);
++      tlist[pointindex++] = pointmark(mid1);
++      tlist[pointindex++] = pointmark(mid2);
++      tlist[pointindex++] = pointmark(mid3);
++#else /* not TRILIBRARY */
++      /* Triangle number, indices for six points. */
++      fprintf(outfile, "%4d    %4d  %4d  %4d  %4d  %4d  %4d", elementnumber,
++              pointmark(p1), pointmark(p2), pointmark(p3), pointmark(mid1),
++              pointmark(mid2), pointmark(mid3));
++#endif /* not TRILIBRARY */
++    }
++
++#ifdef TRILIBRARY
++    for (i = 0; i < eextras; i++) {
++      talist[attribindex++] = elemattribute(triangleloop, i);
++    }
++#else /* not TRILIBRARY */
++    for (i = 0; i < eextras; i++) {
++      fprintf(outfile, "  %.17g", elemattribute(triangleloop, i));
++    }
++    fprintf(outfile, "\n");
++#endif /* not TRILIBRARY */
++
++    triangleloop.tri = triangletraverse();
++    elementnumber++;
++  }
++
++#ifndef TRILIBRARY
++  finishfile(outfile, argc, argv);
++#endif /* not TRILIBRARY */
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  writepoly()   Write the segments and holes to a .poly file.              */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifdef TRILIBRARY
++
++void writepoly(segmentlist, segmentmarkerlist)
++int **segmentlist;
++int **segmentmarkerlist;
++
++#else /* not TRILIBRARY */
++
++void writepoly(polyfilename, holelist, holes, regionlist, regions, argc, argv)
++char *polyfilename;
++REAL *holelist;
++int holes;
++REAL *regionlist;
++int regions;
++int argc;
++char **argv;
++
++#endif /* not TRILIBRARY */
++
++{
++#ifdef TRILIBRARY
++  int *slist;
++  int *smlist;
++  int index;
++#else /* not TRILIBRARY */
++  FILE *outfile;
++  int i;
++#endif /* not TRILIBRARY */
++  struct edge shelleloop;
++  point endpoint1, endpoint2;
++  int shellenumber;
++
++#ifdef TRILIBRARY
++  if (!quiet) {
++    printf("Writing segments.\n");
++  }
++  /* Allocate memory for output segments if necessary. */
++  if (*segmentlist == (int *) NULL) {
++    *segmentlist = (int *) malloc(shelles.items * 2 * sizeof(int));
++    if (*segmentlist == (int *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  /* Allocate memory for output segment markers if necessary. */
++  if (!nobound && (*segmentmarkerlist == (int *) NULL)) {
++    *segmentmarkerlist = (int *) malloc(shelles.items * sizeof(int));
++    if (*segmentmarkerlist == (int *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  slist = *segmentlist;
++  smlist = *segmentmarkerlist;
++  index = 0;
++#else /* not TRILIBRARY */
++  if (!quiet) {
++    printf("Writing %s.\n", polyfilename);
++  }
++  outfile = fopen(polyfilename, "w");
++  if (outfile == (FILE *) NULL) {
++    printf("  Error:  Cannot create file %s.\n", polyfilename);
++    exit(1);
++  }
++  /* The zero indicates that the points are in a separate .node file. */
++  /*   Followed by number of dimensions, number of point attributes,  */
++  /*   and number of boundary markers (zero or one).                  */
++  fprintf(outfile, "%d  %d  %d  %d\n", 0, mesh_dim, nextras, 1 - nobound);
++  /* Number of segments, number of boundary markers (zero or one). */
++  fprintf(outfile, "%ld  %d\n", shelles.items, 1 - nobound);
++#endif /* not TRILIBRARY */
++
++  traversalinit(&shelles);
++  shelleloop.sh = shelletraverse();
++  shelleloop.shorient = 0;
++  shellenumber = firstnumber;
++  while (shelleloop.sh != (shelle *) NULL) {
++    sorg(shelleloop, endpoint1);
++    sdest(shelleloop, endpoint2);
++#ifdef TRILIBRARY
++    /* Copy indices of the segment's two endpoints. */
++    slist[index++] = pointmark(endpoint1);
++    slist[index++] = pointmark(endpoint2);
++    if (!nobound) {
++      /* Copy the boundary marker. */
++      smlist[shellenumber - firstnumber] = mark(shelleloop);
++    }
++#else /* not TRILIBRARY */
++    /* Segment number, indices of its two endpoints, and possibly a marker. */
++    if (nobound) {
++      fprintf(outfile, "%4d    %4d  %4d\n", shellenumber,
++              pointmark(endpoint1), pointmark(endpoint2));
++    } else {
++      fprintf(outfile, "%4d    %4d  %4d    %4d\n", shellenumber,
++              pointmark(endpoint1), pointmark(endpoint2), mark(shelleloop));
++    }
++#endif /* not TRILIBRARY */
++
++    shelleloop.sh = shelletraverse();
++    shellenumber++;
++  }
++
++#ifndef TRILIBRARY
++#ifndef CDT_ONLY
++  fprintf(outfile, "%d\n", holes);
++  if (holes > 0) {
++    for (i = 0; i < holes; i++) {
++      /* Hole number, x and y coordinates. */
++      fprintf(outfile, "%4d   %.17g  %.17g\n", firstnumber + i,
++              holelist[2 * i], holelist[2 * i + 1]);
++    }
++  }
++  if (regions > 0) {
++    fprintf(outfile, "%d\n", regions);
++    for (i = 0; i < regions; i++) {
++      /* Region number, x and y coordinates, attribute, maximum area. */
++      fprintf(outfile, "%4d   %.17g  %.17g  %.17g  %.17g\n", firstnumber + i,
++              regionlist[4 * i], regionlist[4 * i + 1],
++              regionlist[4 * i + 2], regionlist[4 * i + 3]);
++    }
++  }
++#endif /* not CDT_ONLY */
++
++  finishfile(outfile, argc, argv);
++#endif /* not TRILIBRARY */
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  writeedges()   Write the edges to a .edge file.                          */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifdef TRILIBRARY
++
++void writeedges(edgelist, edgemarkerlist)
++int **edgelist;
++int **edgemarkerlist;
++
++#else /* not TRILIBRARY */
++
++void writeedges(edgefilename, argc, argv)
++char *edgefilename;
++int argc;
++char **argv;
++
++#endif /* not TRILIBRARY */
++
++{
++#ifdef TRILIBRARY
++  int *elist;
++  int *emlist;
++  int index;
++#else /* not TRILIBRARY */
++  FILE *outfile;
++#endif /* not TRILIBRARY */
++  struct triedge triangleloop, trisym;
++  struct edge checkmark;
++  point p1, p2;
++  int edgenumber;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++  shelle sptr;                      /* Temporary variable used by tspivot(). */
++
++#ifdef TRILIBRARY
++  if (!quiet) {
++    printf("Writing edges.\n");
++  }
++  /* Allocate memory for edges if necessary. */
++  if (*edgelist == (int *) NULL) {
++    *edgelist = (int *) malloc(edges * 2 * sizeof(int));
++    if (*edgelist == (int *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  /* Allocate memory for edge markers if necessary. */
++  if (!nobound && (*edgemarkerlist == (int *) NULL)) {
++    *edgemarkerlist = (int *) malloc(edges * sizeof(int));
++    if (*edgemarkerlist == (int *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  elist = *edgelist;
++  emlist = *edgemarkerlist;
++  index = 0;
++#else /* not TRILIBRARY */
++  if (!quiet) {
++    printf("Writing %s.\n", edgefilename);
++  }
++  outfile = fopen(edgefilename, "w");
++  if (outfile == (FILE *) NULL) {
++    printf("  Error:  Cannot create file %s.\n", edgefilename);
++    exit(1);
++  }
++  /* Number of edges, number of boundary markers (zero or one). */
++  fprintf(outfile, "%ld  %d\n", edges, 1 - nobound);
++#endif /* not TRILIBRARY */
++
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  edgenumber = firstnumber;
++  /* To loop over the set of edges, loop over all triangles, and look at   */
++  /*   the three edges of each triangle.  If there isn't another triangle  */
++  /*   adjacent to the edge, operate on the edge.  If there is another     */
++  /*   adjacent triangle, operate on the edge only if the current triangle */
++  /*   has a smaller pointer than its neighbor.  This way, each edge is    */
++  /*   considered only once.                                               */
++  while (triangleloop.tri != (triangle *) NULL) {
++    for (triangleloop.orient = 0; triangleloop.orient < 3;
++         triangleloop.orient++) {
++      sym(triangleloop, trisym);
++      if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) {
++        org(triangleloop, p1);
++        dest(triangleloop, p2);
++#ifdef TRILIBRARY
++        elist[index++] = pointmark(p1);
++        elist[index++] = pointmark(p2);
++#endif /* TRILIBRARY */
++        if (nobound) {
++#ifndef TRILIBRARY
++          /* Edge number, indices of two endpoints. */
++          fprintf(outfile, "%4d   %d  %d\n", edgenumber,
++                  pointmark(p1), pointmark(p2));
++#endif /* not TRILIBRARY */
++        } else {
++          /* Edge number, indices of two endpoints, and a boundary marker. */
++          /*   If there's no shell edge, the boundary marker is zero.      */
++          if (useshelles) {
++            tspivot(triangleloop, checkmark);
++            if (checkmark.sh == dummysh) {
++#ifdef TRILIBRARY
++              emlist[edgenumber - firstnumber] = 0;
++#else /* not TRILIBRARY */
++              fprintf(outfile, "%4d   %d  %d  %d\n", edgenumber,
++                      pointmark(p1), pointmark(p2), 0);
++#endif /* not TRILIBRARY */
++            } else {
++#ifdef TRILIBRARY
++              emlist[edgenumber - firstnumber] = mark(checkmark);
++#else /* not TRILIBRARY */
++              fprintf(outfile, "%4d   %d  %d  %d\n", edgenumber,
++                      pointmark(p1), pointmark(p2), mark(checkmark));
++#endif /* not TRILIBRARY */
++            }
++          } else {
++#ifdef TRILIBRARY
++            emlist[edgenumber - firstnumber] = trisym.tri == dummytri;
++#else /* not TRILIBRARY */
++            fprintf(outfile, "%4d   %d  %d  %d\n", edgenumber,
++                    pointmark(p1), pointmark(p2), trisym.tri == dummytri);
++#endif /* not TRILIBRARY */
++          }
++        }
++        edgenumber++;
++      }
++    }
++    triangleloop.tri = triangletraverse();
++  }
++
++#ifndef TRILIBRARY
++  finishfile(outfile, argc, argv);
++#endif /* not TRILIBRARY */
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  writevoronoi()   Write the Voronoi diagram to a .v.node and .v.edge      */
++/*                   file.                                                   */
++/*                                                                           */
++/*  The Voronoi diagram is the geometric dual of the Delaunay triangulation. */
++/*  Hence, the Voronoi vertices are listed by traversing the Delaunay        */
++/*  triangles, and the Voronoi edges are listed by traversing the Delaunay   */
++/*  edges.                                                                   */
++/*                                                                           */
++/*  WARNING:  In order to assign numbers to the Voronoi vertices, this       */
++/*  procedure messes up the shell edges or the extra nodes of every          */
++/*  element.  Hence, you should call this procedure last.                    */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifdef TRILIBRARY
++
++void writevoronoi(vpointlist, vpointattriblist, vpointmarkerlist, vedgelist,
++                  vedgemarkerlist, vnormlist)
++REAL **vpointlist;
++REAL **vpointattriblist;
++int **vpointmarkerlist;
++int **vedgelist;
++int **vedgemarkerlist;
++REAL **vnormlist;
++
++#else /* not TRILIBRARY */
++
++void writevoronoi(vnodefilename, vedgefilename, argc, argv)
++char *vnodefilename;
++char *vedgefilename;
++int argc;
++char **argv;
++
++#endif /* not TRILIBRARY */
++
++{
++#ifdef TRILIBRARY
++  REAL *plist;
++  REAL *palist;
++  int *elist;
++  REAL *normlist;
++  int coordindex;
++  int attribindex;
++#else /* not TRILIBRARY */
++  FILE *outfile;
++#endif /* not TRILIBRARY */
++  struct triedge triangleloop, trisym;
++  point torg, tdest, tapex;
++  REAL circumcenter[2];
++  REAL xi, eta;
++  int vnodenumber, vedgenumber;
++  int p1, p2;
++  int i;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++
++#ifdef TRILIBRARY
++  if (!quiet) {
++    printf("Writing Voronoi vertices.\n");
++  }
++  /* Allocate memory for Voronoi vertices if necessary. */
++  if (*vpointlist == (REAL *) NULL) {
++    *vpointlist = (REAL *) malloc(triangles.items * 2 * sizeof(REAL));
++    if (*vpointlist == (REAL *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  /* Allocate memory for Voronoi vertex attributes if necessary. */
++  if (*vpointattriblist == (REAL *) NULL) {
++    *vpointattriblist = (REAL *) malloc(triangles.items * nextras *
++                                        sizeof(REAL));
++    if (*vpointattriblist == (REAL *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  *vpointmarkerlist = (int *) NULL;
++  plist = *vpointlist;
++  palist = *vpointattriblist;
++  coordindex = 0;
++  attribindex = 0;
++#else /* not TRILIBRARY */
++  if (!quiet) {
++    printf("Writing %s.\n", vnodefilename);
++  }
++  outfile = fopen(vnodefilename, "w");
++  if (outfile == (FILE *) NULL) {
++    printf("  Error:  Cannot create file %s.\n", vnodefilename);
++    exit(1);
++  }
++  /* Number of triangles, two dimensions, number of point attributes, */
++  /*   zero markers.                                                  */
++  fprintf(outfile, "%ld  %d  %d  %d\n", triangles.items, 2, nextras, 0);
++#endif /* not TRILIBRARY */
++
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  triangleloop.orient = 0;
++  vnodenumber = firstnumber;
++  while (triangleloop.tri != (triangle *) NULL) {
++    org(triangleloop, torg);
++    dest(triangleloop, tdest);
++    apex(triangleloop, tapex);
++    findcircumcenter(torg, tdest, tapex, circumcenter, &xi, &eta);
++#ifdef TRILIBRARY
++    /* X and y coordinates. */
++    plist[coordindex++] = circumcenter[0];
++    plist[coordindex++] = circumcenter[1];
++    for (i = 2; i < 2 + nextras; i++) {
++      /* Interpolate the point attributes at the circumcenter. */
++      palist[attribindex++] = torg[i] + xi * (tdest[i] - torg[i])
++                                     + eta * (tapex[i] - torg[i]);
++    }
++#else /* not TRILIBRARY */
++    /* Voronoi vertex number, x and y coordinates. */
++    fprintf(outfile, "%4d    %.17g  %.17g", vnodenumber, circumcenter[0],
++            circumcenter[1]);
++    for (i = 2; i < 2 + nextras; i++) {
++      /* Interpolate the point attributes at the circumcenter. */
++      fprintf(outfile, "  %.17g", torg[i] + xi * (tdest[i] - torg[i])
++                                         + eta * (tapex[i] - torg[i]));
++    }
++    fprintf(outfile, "\n");
++#endif /* not TRILIBRARY */
++
++    * (int *) (triangleloop.tri + 6) = vnodenumber;
++    triangleloop.tri = triangletraverse();
++    vnodenumber++;
++  }
++
++#ifndef TRILIBRARY
++  finishfile(outfile, argc, argv);
++#endif /* not TRILIBRARY */
++
++#ifdef TRILIBRARY
++  if (!quiet) {
++    printf("Writing Voronoi edges.\n");
++  }
++  /* Allocate memory for output Voronoi edges if necessary. */
++  if (*vedgelist == (int *) NULL) {
++    *vedgelist = (int *) malloc(edges * 2 * sizeof(int));
++    if (*vedgelist == (int *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  *vedgemarkerlist = (int *) NULL;
++  /* Allocate memory for output Voronoi norms if necessary. */
++  if (*vnormlist == (REAL *) NULL) {
++    *vnormlist = (REAL *) malloc(edges * 2 * sizeof(REAL));
++    if (*vnormlist == (REAL *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  elist = *vedgelist;
++  normlist = *vnormlist;
++  coordindex = 0;
++#else /* not TRILIBRARY */
++  if (!quiet) {
++    printf("Writing %s.\n", vedgefilename);
++  }
++  outfile = fopen(vedgefilename, "w");
++  if (outfile == (FILE *) NULL) {
++    printf("  Error:  Cannot create file %s.\n", vedgefilename);
++    exit(1);
++  }
++  /* Number of edges, zero boundary markers. */
++  fprintf(outfile, "%ld  %d\n", edges, 0);
++#endif /* not TRILIBRARY */
++
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  vedgenumber = firstnumber;
++  /* To loop over the set of edges, loop over all triangles, and look at   */
++  /*   the three edges of each triangle.  If there isn't another triangle  */
++  /*   adjacent to the edge, operate on the edge.  If there is another     */
++  /*   adjacent triangle, operate on the edge only if the current triangle */
++  /*   has a smaller pointer than its neighbor.  This way, each edge is    */
++  /*   considered only once.                                               */
++  while (triangleloop.tri != (triangle *) NULL) {
++    for (triangleloop.orient = 0; triangleloop.orient < 3;
++         triangleloop.orient++) {
++      sym(triangleloop, trisym);
++      if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) {
++        /* Find the number of this triangle (and Voronoi vertex). */
++        p1 = * (int *) (triangleloop.tri + 6);
++        if (trisym.tri == dummytri) {
++          org(triangleloop, torg);
++          dest(triangleloop, tdest);
++#ifdef TRILIBRARY
++          /* Copy an infinite ray.  Index of one endpoint, and -1. */
++          elist[coordindex] = p1;
++          normlist[coordindex++] = tdest[1] - torg[1];
++          elist[coordindex] = -1;
++          normlist[coordindex++] = torg[0] - tdest[0];
++#else /* not TRILIBRARY */
++          /* Write an infinite ray.  Edge number, index of one endpoint, -1, */
++          /*   and x and y coordinates of a vector representing the          */
++          /*   direction of the ray.                                         */
++          fprintf(outfile, "%4d   %d  %d   %.17g  %.17g\n", vedgenumber,
++                  p1, -1, tdest[1] - torg[1], torg[0] - tdest[0]);
++#endif /* not TRILIBRARY */
++        } else {
++          /* Find the number of the adjacent triangle (and Voronoi vertex). */
++          p2 = * (int *) (trisym.tri + 6);
++          /* Finite edge.  Write indices of two endpoints. */
++#ifdef TRILIBRARY
++          elist[coordindex] = p1;
++          normlist[coordindex++] = 0.0;
++          elist[coordindex] = p2;
++          normlist[coordindex++] = 0.0;
++#else /* not TRILIBRARY */
++          fprintf(outfile, "%4d   %d  %d\n", vedgenumber, p1, p2);
++#endif /* not TRILIBRARY */
++        }
++        vedgenumber++;
++      }
++    }
++    triangleloop.tri = triangletraverse();
++  }
++
++#ifndef TRILIBRARY
++  finishfile(outfile, argc, argv);
++#endif /* not TRILIBRARY */
++}
++
++#ifdef TRILIBRARY
++
++void writeneighbors(neighborlist)
++int **neighborlist;
++
++#else /* not TRILIBRARY */
++
++void writeneighbors(neighborfilename, argc, argv)
++char *neighborfilename;
++int argc;
++char **argv;
++
++#endif /* not TRILIBRARY */
++
++{
++#ifdef TRILIBRARY
++  int *nlist;
++  int index;
++#else /* not TRILIBRARY */
++  FILE *outfile;
++#endif /* not TRILIBRARY */
++  struct triedge triangleloop, trisym;
++  int elementnumber;
++  int neighbor1, neighbor2, neighbor3;
++  triangle ptr;                         /* Temporary variable used by sym(). */
++
++#ifdef TRILIBRARY
++  if (!quiet) {
++    printf("Writing neighbors.\n");
++  }
++  /* Allocate memory for neighbors if necessary. */
++  if (*neighborlist == (int *) NULL) {
++    *neighborlist = (int *) malloc(triangles.items * 3 * sizeof(int));
++    if (*neighborlist == (int *) NULL) {
++      printf("Error:  Out of memory.\n");
++      exit(1);
++    }
++  }
++  nlist = *neighborlist;
++  index = 0;
++#else /* not TRILIBRARY */
++  if (!quiet) {
++    printf("Writing %s.\n", neighborfilename);
++  }
++  outfile = fopen(neighborfilename, "w");
++  if (outfile == (FILE *) NULL) {
++    printf("  Error:  Cannot create file %s.\n", neighborfilename);
++    exit(1);
++  }
++  /* Number of triangles, three edges per triangle. */
++  fprintf(outfile, "%ld  %d\n", triangles.items, 3);
++#endif /* not TRILIBRARY */
++
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  triangleloop.orient = 0;
++  elementnumber = firstnumber;
++  while (triangleloop.tri != (triangle *) NULL) {
++    * (int *) (triangleloop.tri + 6) = elementnumber;
++    triangleloop.tri = triangletraverse();
++    elementnumber++;
++  }
++  * (int *) (dummytri + 6) = -1;
++
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  elementnumber = firstnumber;
++  while (triangleloop.tri != (triangle *) NULL) {
++    triangleloop.orient = 1;
++    sym(triangleloop, trisym);
++    neighbor1 = * (int *) (trisym.tri + 6);
++    triangleloop.orient = 2;
++    sym(triangleloop, trisym);
++    neighbor2 = * (int *) (trisym.tri + 6);
++    triangleloop.orient = 0;
++    sym(triangleloop, trisym);
++    neighbor3 = * (int *) (trisym.tri + 6);
++#ifdef TRILIBRARY
++    nlist[index++] = neighbor1;
++    nlist[index++] = neighbor2;
++    nlist[index++] = neighbor3;
++#else /* not TRILIBRARY */
++    /* Triangle number, neighboring triangle numbers. */
++    fprintf(outfile, "%4d    %d  %d  %d\n", elementnumber,
++            neighbor1, neighbor2, neighbor3);
++#endif /* not TRILIBRARY */
++
++    triangleloop.tri = triangletraverse();
++    elementnumber++;
++  }
++
++#ifndef TRILIBRARY
++  finishfile(outfile, argc, argv);
++#endif /* TRILIBRARY */
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  writeoff()   Write the triangulation to an .off file.                    */
++/*                                                                           */
++/*  OFF stands for the Object File Format, a format used by the Geometry     */
++/*  Center's Geomview package.                                               */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifndef TRILIBRARY
++
++void writeoff(offfilename, argc, argv)
++char *offfilename;
++int argc;
++char **argv;
++{
++  FILE *outfile;
++  struct triedge triangleloop;
++  point pointloop;
++  point p1, p2, p3;
++
++  if (!quiet) {
++    printf("Writing %s.\n", offfilename);
++  }
++  outfile = fopen(offfilename, "w");
++  if (outfile == (FILE *) NULL) {
++    printf("  Error:  Cannot create file %s.\n", offfilename);
++    exit(1);
++  }
++  /* Number of points, triangles, and edges. */
++  fprintf(outfile, "OFF\n%ld  %ld  %ld\n", points.items, triangles.items,
++          edges);
++
++  /* Write the points. */
++  traversalinit(&points);
++  pointloop = pointtraverse();
++  while (pointloop != (point) NULL) {
++    /* The "0.0" is here because the OFF format uses 3D coordinates. */
++    fprintf(outfile, " %.17g  %.17g  %.17g\n", pointloop[0],
++            pointloop[1], 0.0);
++    pointloop = pointtraverse();
++  }
++
++  /* Write the triangles. */
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  triangleloop.orient = 0;
++  while (triangleloop.tri != (triangle *) NULL) {
++    org(triangleloop, p1);
++    dest(triangleloop, p2);
++    apex(triangleloop, p3);
++    /* The "3" means a three-vertex polygon. */
++    fprintf(outfile, " 3   %4d  %4d  %4d\n", pointmark(p1) - 1,
++            pointmark(p2) - 1, pointmark(p3) - 1);
++    triangleloop.tri = triangletraverse();
++  }
++  finishfile(outfile, argc, argv);
++}
++
++#endif /* not TRILIBRARY */
++
++/**                                                                         **/
++/**                                                                         **/
++/********* File I/O routines end here                                *********/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  quality_statistics()   Print statistics about the quality of the mesh.   */
++/*                                                                           */
++/*****************************************************************************/
++
++void quality_statistics()
++{
++  struct triedge triangleloop;
++  point p[3];
++  REAL cossquaretable[8];
++  REAL ratiotable[16];
++  REAL dx[3], dy[3];
++  REAL edgelength[3];
++  REAL dotproduct;
++  REAL cossquare;
++  REAL triarea;
++  REAL shortest, longest;
++  REAL trilongest2;
++  REAL smallestarea, biggestarea;
++  REAL triminaltitude2;
++  REAL minaltitude;
++  REAL triaspect2;
++  REAL worstaspect;
++  REAL smallestangle, biggestangle;
++  REAL radconst, degconst;
++  int angletable[18];
++  int aspecttable[16];
++  int aspectindex;
++  int tendegree;
++  int acutebiggest;
++  int i, ii, j, k;
++
++  printf("Mesh quality statistics:\n\n");
++  radconst = PI / 18.0;
++  degconst = 180.0 / PI;
++  for (i = 0; i < 8; i++) {
++    cossquaretable[i] = cos(radconst * (REAL) (i + 1));
++    cossquaretable[i] = cossquaretable[i] * cossquaretable[i];
++  }
++  for (i = 0; i < 18; i++) {
++    angletable[i] = 0;
++  }
++
++  ratiotable[0]  =      1.5;      ratiotable[1]  =     2.0;
++  ratiotable[2]  =      2.5;      ratiotable[3]  =     3.0;
++  ratiotable[4]  =      4.0;      ratiotable[5]  =     6.0;
++  ratiotable[6]  =     10.0;      ratiotable[7]  =    15.0;
++  ratiotable[8]  =     25.0;      ratiotable[9]  =    50.0;
++  ratiotable[10] =    100.0;      ratiotable[11] =   300.0;
++  ratiotable[12] =   1000.0;      ratiotable[13] = 10000.0;
++  ratiotable[14] = 100000.0;      ratiotable[15] =     0.0;
++  for (i = 0; i < 16; i++) {
++    aspecttable[i] = 0;
++  }
++
++  worstaspect = 0.0;
++  minaltitude = xmax - xmin + ymax - ymin;
++  minaltitude = minaltitude * minaltitude;
++  shortest = minaltitude;
++  longest = 0.0;
++  smallestarea = minaltitude;
++  biggestarea = 0.0;
++  worstaspect = 0.0;
++  smallestangle = 0.0;
++  biggestangle = 2.0;
++  acutebiggest = 1;
++
++  traversalinit(&triangles);
++  triangleloop.tri = triangletraverse();
++  triangleloop.orient = 0;
++  while (triangleloop.tri != (triangle *) NULL) {
++    org(triangleloop, p[0]);
++    dest(triangleloop, p[1]);
++    apex(triangleloop, p[2]);
++    trilongest2 = 0.0;
++
++    for (i = 0; i < 3; i++) {
++      j = plus1mod3[i];
++      k = minus1mod3[i];
++      dx[i] = p[j][0] - p[k][0];
++      dy[i] = p[j][1] - p[k][1];
++      edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i];
++      if (edgelength[i] > trilongest2) {
++        trilongest2 = edgelength[i];
++      }
++      if (edgelength[i] > longest) {
++        longest = edgelength[i];
++      }
++      if (edgelength[i] < shortest) {
++        shortest = edgelength[i];
++      }
++    }
++
++    triarea = counterclockwise(p[0], p[1], p[2]);
++    if (triarea < smallestarea) {
++      smallestarea = triarea;
++    }
++    if (triarea > biggestarea) {
++      biggestarea = triarea;
++    }
++    triminaltitude2 = triarea * triarea / trilongest2;
++    if (triminaltitude2 < minaltitude) {
++      minaltitude = triminaltitude2;
++    }
++    triaspect2 = trilongest2 / triminaltitude2;
++    if (triaspect2 > worstaspect) {
++      worstaspect = triaspect2;
++    }
++    aspectindex = 0;
++    while ((triaspect2 > ratiotable[aspectindex] * ratiotable[aspectindex])
++           && (aspectindex < 15)) {
++      aspectindex++;
++    }
++    aspecttable[aspectindex]++;
++
++    for (i = 0; i < 3; i++) {
++      j = plus1mod3[i];
++      k = minus1mod3[i];
++      dotproduct = dx[j] * dx[k] + dy[j] * dy[k];
++      cossquare = dotproduct * dotproduct / (edgelength[j] * edgelength[k]);
++      tendegree = 8;
++      for (ii = 7; ii >= 0; ii--) {
++        if (cossquare > cossquaretable[ii]) {
++          tendegree = ii;
++        }
++      }
++      if (dotproduct <= 0.0) {
++        angletable[tendegree]++;
++        if (cossquare > smallestangle) {
++          smallestangle = cossquare;
++        }
++        if (acutebiggest && (cossquare < biggestangle)) {
++          biggestangle = cossquare;
++        }
++      } else {
++        angletable[17 - tendegree]++;
++        if (acutebiggest || (cossquare > biggestangle)) {
++          biggestangle = cossquare;
++          acutebiggest = 0;
++        }
++      }
++    }
++    triangleloop.tri = triangletraverse();
++  }
++
++  shortest = sqrt(shortest);
++  longest = sqrt(longest);
++  minaltitude = sqrt(minaltitude);
++  worstaspect = sqrt(worstaspect);
++  smallestarea *= 2.0;
++  biggestarea *= 2.0;
++  if (smallestangle >= 1.0) {
++    smallestangle = 0.0;
++  } else {
++    smallestangle = degconst * acos(sqrt(smallestangle));
++  }
++  if (biggestangle >= 1.0) {
++    biggestangle = 180.0;
++  } else {
++    if (acutebiggest) {
++      biggestangle = degconst * acos(sqrt(biggestangle));
++    } else {
++      biggestangle = 180.0 - degconst * acos(sqrt(biggestangle));
++    }
++  }
++
++  printf("  Smallest area: %16.5g   |  Largest area: %16.5g\n",
++         smallestarea, biggestarea);
++  printf("  Shortest edge: %16.5g   |  Longest edge: %16.5g\n",
++         shortest, longest);
++  printf("  Shortest altitude: %12.5g   |  Largest aspect ratio: %8.5g\n\n",
++         minaltitude, worstaspect);
++  printf("  Aspect ratio histogram:\n");
++  printf("  1.1547 - %-6.6g    :  %8d    | %6.6g - %-6.6g     :  %8d\n",
++         ratiotable[0], aspecttable[0], ratiotable[7], ratiotable[8],
++         aspecttable[8]);
++  for (i = 1; i < 7; i++) {
++    printf("  %6.6g - %-6.6g    :  %8d    | %6.6g - %-6.6g     :  %8d\n",
++           ratiotable[i - 1], ratiotable[i], aspecttable[i],
++           ratiotable[i + 7], ratiotable[i + 8], aspecttable[i + 8]);
++  }
++  printf("  %6.6g - %-6.6g    :  %8d    | %6.6g -            :  %8d\n",
++         ratiotable[6], ratiotable[7], aspecttable[7], ratiotable[14],
++         aspecttable[15]);
++  printf(
++"  (Triangle aspect ratio is longest edge divided by shortest altitude)\n\n");
++  printf("  Smallest angle: %15.5g   |  Largest angle: %15.5g\n\n",
++         smallestangle, biggestangle);
++  printf("  Angle histogram:\n");
++  for (i = 0; i < 9; i++) {
++    printf("    %3d - %3d degrees:  %8d    |    %3d - %3d degrees:  %8d\n",
++           i * 10, i * 10 + 10, angletable[i],
++           i * 10 + 90, i * 10 + 100, angletable[i + 9]);
++  }
++  printf("\n");
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  statistics()   Print all sorts of cool facts.                            */
++/*                                                                           */
++/*****************************************************************************/
++
++void statistics()
++{
++  printf("\nStatistics:\n\n");
++  printf("  Input points: %d\n", inpoints);
++  if (refine) {
++    printf("  Input triangles: %d\n", inelements);
++  }
++  if (poly) {
++    printf("  Input segments: %d\n", insegments);
++    if (!refine) {
++      printf("  Input holes: %d\n", holes);
++    }
++  }
++
++  printf("\n  Mesh points: %ld\n", points.items);
++  printf("  Mesh triangles: %ld\n", triangles.items);
++  printf("  Mesh edges: %ld\n", edges);
++  if (poly || refine) {
++    printf("  Mesh boundary edges: %ld\n", hullsize);
++    printf("  Mesh segments: %ld\n\n", shelles.items);
++  } else {
++    printf("  Mesh convex hull edges: %ld\n\n", hullsize);
++  }
++  if (verbose) {
++    quality_statistics();
++    printf("Memory allocation statistics:\n\n");
++    printf("  Maximum number of points: %ld\n", points.maxitems);
++    printf("  Maximum number of triangles: %ld\n", triangles.maxitems);
++    if (shelles.maxitems > 0) {
++      printf("  Maximum number of segments: %ld\n", shelles.maxitems);
++    }
++    if (viri.maxitems > 0) {
++      printf("  Maximum number of viri: %ld\n", viri.maxitems);
++    }
++    if (badsegments.maxitems > 0) {
++      printf("  Maximum number of encroached segments: %ld\n",
++             badsegments.maxitems);
++    }
++    if (badtriangles.maxitems > 0) {
++      printf("  Maximum number of bad triangles: %ld\n",
++             badtriangles.maxitems);
++    }
++    if (splaynodes.maxitems > 0) {
++      printf("  Maximum number of splay tree nodes: %ld\n",
++             splaynodes.maxitems);
++    }
++    printf("  Approximate heap memory use (bytes): %ld\n\n",
++           points.maxitems * points.itembytes
++           + triangles.maxitems * triangles.itembytes
++           + shelles.maxitems * shelles.itembytes
++           + viri.maxitems * viri.itembytes
++           + badsegments.maxitems * badsegments.itembytes
++           + badtriangles.maxitems * badtriangles.itembytes
++           + splaynodes.maxitems * splaynodes.itembytes);
++
++    printf("Algorithmic statistics:\n\n");
++    printf("  Number of incircle tests: %ld\n", incirclecount);
++    printf("  Number of orientation tests: %ld\n", counterclockcount);
++    if (hyperbolacount > 0) {
++      printf("  Number of right-of-hyperbola tests: %ld\n",
++             hyperbolacount);
++    }
++    if (circumcentercount > 0) {
++      printf("  Number of circumcenter computations: %ld\n",
++             circumcentercount);
++    }
++    if (circletopcount > 0) {
++      printf("  Number of circle top computations: %ld\n",
++             circletopcount);
++    }
++    printf("\n");
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  main() or triangulate()   Gosh, do everything.                           */
++/*                                                                           */
++/*  The sequence is roughly as follows.  Many of these steps can be skipped, */
++/*  depending on the command line switches.                                  */
++/*                                                                           */
++/*  - Initialize constants and parse the command line.                       */
++/*  - Read the points from a file and either                                 */
++/*    - triangulate them (no -r), or                                         */
++/*    - read an old mesh from files and reconstruct it (-r).                 */
++/*  - Insert the PSLG segments (-p), and possibly segments on the convex     */
++/*      hull (-c).                                                           */
++/*  - Read the holes (-p), regional attributes (-pA), and regional area      */
++/*      constraints (-pa).  Carve the holes and concavities, and spread the  */
++/*      regional attributes and area constraints.                            */
++/*  - Enforce the constraints on minimum angle (-q) and maximum area (-a).   */
++/*      Also enforce the conforming Delaunay property (-q and -a).           */
++/*  - Compute the number of edges in the resulting mesh.                     */
++/*  - Promote the mesh's linear triangles to higher order elements (-o).     */
++/*  - Write the output files and print the statistics.                       */
++/*  - Check the consistency and Delaunay property of the mesh (-C).          */
++/*                                                                           */
++/*****************************************************************************/
++
++#ifdef TRILIBRARY
++
++void triangulate(triswitches, in, out, vorout)
++char *triswitches;
++struct triangulateio *in;
++struct triangulateio *out;
++struct triangulateio *vorout;
++
++#else /* not TRILIBRARY */
++
++int main(argc, argv)
++int argc;
++char **argv;
++
++#endif /* not TRILIBRARY */
++
++{
++  REAL *holearray;                                        /* Array of holes. */
++  REAL *regionarray;   /* Array of regional attributes and area constraints. */
++#ifndef TRILIBRARY
++  FILE *polyfile;
++#endif /* not TRILIBRARY */
++#ifndef NO_TIMER
++  /* Variables for timing the performance of Triangle.  The types are */
++  /*   defined in sys/time.h.                                         */
++  struct timeval tv0, tv1, tv2, tv3, tv4, tv5, tv6;
++  struct timezone tz;
++#endif /* NO_TIMER */
++
++#ifndef NO_TIMER
++  gettimeofday(&tv0, &tz);
++#endif /* NO_TIMER */
++
++  triangleinit();
++#ifdef TRILIBRARY
++  parsecommandline(1, &triswitches);
++#else /* not TRILIBRARY */
++  parsecommandline(argc, argv);
++#endif /* not TRILIBRARY */
++
++#ifdef TRILIBRARY
++  transfernodes(in->pointlist, in->pointattributelist, in->pointmarkerlist,
++                in->numberofpoints, in->numberofpointattributes);
++#else /* not TRILIBRARY */
++  readnodes(innodefilename, inpolyfilename, &polyfile);
++#endif /* not TRILIBRARY */
++
++#ifndef NO_TIMER
++  if (!quiet) {
++    gettimeofday(&tv1, &tz);
++  }
++#endif /* NO_TIMER */
++
++#ifdef CDT_ONLY
++  hullsize = delaunay();                          /* Triangulate the points. */
++#else /* not CDT_ONLY */
++  if (refine) {
++    /* Read and reconstruct a mesh. */
++#ifdef TRILIBRARY
++    hullsize = reconstruct(in->trianglelist, in->triangleattributelist,
++                           in->trianglearealist, in->numberoftriangles,
++                           in->numberofcorners, in->numberoftriangleattributes,
++                           in->segmentlist, in->segmentmarkerlist,
++                           in->numberofsegments);
++#else /* not TRILIBRARY */
++    hullsize = reconstruct(inelefilename, areafilename, inpolyfilename,
++                           polyfile);
++#endif /* not TRILIBRARY */
++  } else {
++    hullsize = delaunay();                        /* Triangulate the points. */
++  }
++#endif /* not CDT_ONLY */
++
++#ifndef NO_TIMER
++  if (!quiet) {
++    gettimeofday(&tv2, &tz);
++    if (refine) {
++      printf("Mesh reconstruction");
++    } else {
++      printf("Delaunay");
++    }
++    printf(" milliseconds:  %ld\n", 1000l * (tv2.tv_sec - tv1.tv_sec)
++           + (tv2.tv_usec - tv1.tv_usec) / 1000l);
++  }
++#endif /* NO_TIMER */
++
++  /* Ensure that no point can be mistaken for a triangular bounding */
++  /*   box point in insertsite().                                   */
++  infpoint1 = (point) NULL;
++  infpoint2 = (point) NULL;
++  infpoint3 = (point) NULL;
++
++  if (useshelles) {
++    checksegments = 1;                  /* Segments will be introduced next. */
++    if (!refine) {
++      /* Insert PSLG segments and/or convex hull segments. */
++#ifdef TRILIBRARY
++      insegments = formskeleton(in->segmentlist, in->segmentmarkerlist,
++                                in->numberofsegments);
++#else /* not TRILIBRARY */
++      insegments = formskeleton(polyfile, inpolyfilename);
++#endif /* not TRILIBRARY */
++    }
++  }
++
++#ifndef NO_TIMER
++  if (!quiet) {
++    gettimeofday(&tv3, &tz);
++    if (useshelles && !refine) {
++      printf("Segment milliseconds:  %ld\n",
++             1000l * (tv3.tv_sec - tv2.tv_sec)
++             + (tv3.tv_usec - tv2.tv_usec) / 1000l);
++    }
++  }
++#endif /* NO_TIMER */
++
++  if (poly) {
++#ifdef TRILIBRARY
++    holearray = in->holelist;
++    holes = in->numberofholes;
++    regionarray = in->regionlist;
++    regions = in->numberofregions;
++#else /* not TRILIBRARY */
++    readholes(polyfile, inpolyfilename, &holearray, &holes,
++              &regionarray, &regions);
++#endif /* not TRILIBRARY */
++    if (!refine) {
++      /* Carve out holes and concavities. */
++      carveholes(holearray, holes, regionarray, regions);
++    }
++  } else {
++    /* Without a PSLG, there can be no holes or regional attributes   */
++    /*   or area constraints.  The following are set to zero to avoid */
++    /*   an accidental free() later.                                  */
++    holes = 0;
++    regions = 0;
++  }
++
++#ifndef NO_TIMER
++  if (!quiet) {
++    gettimeofday(&tv4, &tz);
++    if (poly && !refine) {
++      printf("Hole milliseconds:  %ld\n", 1000l * (tv4.tv_sec - tv3.tv_sec)
++             + (tv4.tv_usec - tv3.tv_usec) / 1000l);
++    }
++  }
++#endif /* NO_TIMER */
++
++#ifndef CDT_ONLY
++  if (quality) {
++    enforcequality();                 /* Enforce angle and area constraints. */
++  }
++#endif /* not CDT_ONLY */
++
++#ifndef NO_TIMER
++  if (!quiet) {
++    gettimeofday(&tv5, &tz);
++#ifndef CDT_ONLY
++    if (quality) {
++      printf("Quality milliseconds:  %ld\n",
++             1000l * (tv5.tv_sec - tv4.tv_sec)
++             + (tv5.tv_usec - tv4.tv_usec) / 1000l);
++    }
++#endif /* not CDT_ONLY */
++  }
++#endif /* NO_TIMER */
++
++  /* Compute the number of edges. */
++  edges = (3l * triangles.items + hullsize) / 2l;
++
++  if (order > 1) {
++    highorder();             /* Promote elements to higher polynomial order. */
++  }
++  if (!quiet) {
++    printf("\n");
++  }
++
++#ifdef TRILIBRARY
++  out->numberofpoints = points.items;
++  out->numberofpointattributes = nextras;
++  out->numberoftriangles = triangles.items;
++  out->numberofcorners = (order + 1) * (order + 2) / 2;
++  out->numberoftriangleattributes = eextras;
++  out->numberofedges = edges;
++  if (useshelles) {
++    out->numberofsegments = shelles.items;
++  } else {
++    out->numberofsegments = hullsize;
++  }
++  if (vorout != (struct triangulateio *) NULL) {
++    vorout->numberofpoints = triangles.items;
++    vorout->numberofpointattributes = nextras;
++    vorout->numberofedges = edges;
++  }
++#endif /* TRILIBRARY */
++  /* If not using iteration numbers, don't write a .node file if one was */
++  /*   read, because the original one would be overwritten!              */
++  if (nonodewritten || (noiterationnum && readnodefile)) {
++    if (!quiet) {
++#ifdef TRILIBRARY
++      printf("NOT writing points.\n");
++#else /* not TRILIBRARY */
++      printf("NOT writing a .node file.\n");
++#endif /* not TRILIBRARY */
++    }
++    numbernodes();                 /* We must remember to number the points. */
++  } else {
++#ifdef TRILIBRARY
++    writenodes(&out->pointlist, &out->pointattributelist,
++               &out->pointmarkerlist);
++#else /* not TRILIBRARY */
++    writenodes(outnodefilename, argc, argv);      /* Numbers the points too. */
++#endif /* TRILIBRARY */
++  }
++  if (noelewritten) {
++    if (!quiet) {
++#ifdef TRILIBRARY
++      printf("NOT writing triangles.\n");
++#else /* not TRILIBRARY */
++      printf("NOT writing an .ele file.\n");
++#endif /* not TRILIBRARY */
++    }
++  } else {
++#ifdef TRILIBRARY
++    writeelements(&out->trianglelist, &out->triangleattributelist);
++#else /* not TRILIBRARY */
++    writeelements(outelefilename, argc, argv);
++#endif /* not TRILIBRARY */
++  }
++  /* The -c switch (convex switch) causes a PSLG to be written */
++  /*   even if none was read.                                  */
++  if (poly || convex) {
++    /* If not using iteration numbers, don't overwrite the .poly file. */
++    if (nopolywritten || noiterationnum) {
++      if (!quiet) {
++#ifdef TRILIBRARY
++        printf("NOT writing segments.\n");
++#else /* not TRILIBRARY */
++        printf("NOT writing a .poly file.\n");
++#endif /* not TRILIBRARY */
++      }
++    } else {
++#ifdef TRILIBRARY
++      writepoly(&out->segmentlist, &out->segmentmarkerlist);
++      out->numberofholes = holes;
++      out->numberofregions = regions;
++      if (poly) {
++        out->holelist = in->holelist;
++        out->regionlist = in->regionlist;
++      } else {
++        out->holelist = (REAL *) NULL;
++        out->regionlist = (REAL *) NULL;
++      }
++#else /* not TRILIBRARY */
++      writepoly(outpolyfilename, holearray, holes, regionarray, regions,
++                argc, argv);
++#endif /* not TRILIBRARY */
++    }
++  }
++#ifndef TRILIBRARY
++#ifndef CDT_ONLY
++  if (regions > 0) {
++    free(regionarray);
++  }
++#endif /* not CDT_ONLY */
++  if (holes > 0) {
++    free(holearray);
++  }
++  if (geomview) {
++    writeoff(offfilename, argc, argv);
++  }
++#endif /* not TRILIBRARY */
++  if (edgesout) {
++#ifdef TRILIBRARY
++    writeedges(&out->edgelist, &out->edgemarkerlist);
++#else /* not TRILIBRARY */
++    writeedges(edgefilename, argc, argv);
++#endif /* not TRILIBRARY */
++  }
++  if (voronoi) {
++#ifdef TRILIBRARY
++    writevoronoi(&vorout->pointlist, &vorout->pointattributelist,
++                 &vorout->pointmarkerlist, &vorout->edgelist,
++                 &vorout->edgemarkerlist, &vorout->normlist);
++#else /* not TRILIBRARY */
++    writevoronoi(vnodefilename, vedgefilename, argc, argv);
++#endif /* not TRILIBRARY */
++  }
++  if (neighbors) {
++#ifdef TRILIBRARY
++    writeneighbors(&out->neighborlist);
++#else /* not TRILIBRARY */
++    writeneighbors(neighborfilename, argc, argv);
++#endif /* not TRILIBRARY */
++  }
++
++  if (!quiet) {
++#ifndef NO_TIMER
++    gettimeofday(&tv6, &tz);
++    printf("\nOutput milliseconds:  %ld\n",
++           1000l * (tv6.tv_sec - tv5.tv_sec)
++           + (tv6.tv_usec - tv5.tv_usec) / 1000l);
++    printf("Total running milliseconds:  %ld\n",
++           1000l * (tv6.tv_sec - tv0.tv_sec)
++           + (tv6.tv_usec - tv0.tv_usec) / 1000l);
++#endif /* NO_TIMER */
++
++    statistics();
++  }
++
++#ifndef REDUCED
++  if (docheck) {
++    checkmesh();
++    checkdelaunay();
++  }
++#endif /* not REDUCED */
++
++  triangledeinit();
++#ifndef TRILIBRARY
++  return 0;
++#endif /* not TRILIBRARY */
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..28b633978f17790055e07c6bcd41780f249f29d5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,817 @@@
++Triangle
++A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.
++Version 1.3
++
++Copyright 1996 Jonathan Richard Shewchuk  (bugs/comments to jrs@cs.cmu.edu)
++School of Computer Science / Carnegie Mellon University
++5000 Forbes Avenue / Pittsburgh, Pennsylvania  15213-3891
++Created as part of the Archimedes project (tools for parallel FEM).
++Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.
++There is no warranty whatsoever.  Use at your own risk.
++This executable is compiled for double precision arithmetic.
++
++
++Triangle generates exact Delaunay triangulations, constrained Delaunay
++triangulations, and quality conforming Delaunay triangulations.  The latter
++can be generated with no small angles, and are thus suitable for finite
++element analysis.  If no command line switches are specified, your .node
++input file will be read, and the Delaunay triangulation will be returned in
++.node and .ele output files.  The command syntax is:
++
++triangle [-prq__a__AcevngBPNEIOXzo_YS__iFlsCQVh] input_file
++
++Underscores indicate that numbers may optionally follow certain switches;
++do not leave any space between a switch and its numeric parameter.
++input_file must be a file with extension .node, or extension .poly if the
++-p switch is used.  If -r is used, you must supply .node and .ele files,
++and possibly a .poly file and .area file as well.  The formats of these
++files are described below.
++
++Command Line Switches:
++
++    -p  Reads a Planar Straight Line Graph (.poly file), which can specify
++        points, segments, holes, and regional attributes and area
++        constraints.  Will generate a constrained Delaunay triangulation
++        fitting the input; or, if -s, -q, or -a is used, a conforming
++        Delaunay triangulation.  If -p is not used, Triangle reads a .node
++        file by default.
++    -r  Refines a previously generated mesh.  The mesh is read from a .node
++        file and an .ele file.  If -p is also used, a .poly file is read
++        and used to constrain edges in the mesh.  Further details on
++        refinement are given below.
++    -q  Quality mesh generation by Jim Ruppert's Delaunay refinement
++        algorithm.  Adds points to the mesh to ensure that no angles
++        smaller than 20 degrees occur.  An alternative minimum angle may be
++        specified after the `q'.  If the minimum angle is 20.7 degrees or
++        smaller, the triangulation algorithm is theoretically guaranteed to
++        terminate (assuming infinite precision arithmetic - Triangle may
++        fail to terminate if you run out of precision).  In practice, the
++        algorithm often succeeds for minimum angles up to 33.8 degrees.
++        For highly refined meshes, however, it may be necessary to reduce
++        the minimum angle to well below 20 to avoid problems associated
++        with insufficient floating-point precision.  The specified angle
++        may include a decimal point.
++    -a  Imposes a maximum triangle area.  If a number follows the `a', no
++        triangle will be generated whose area is larger than that number.
++        If no number is specified, an .area file (if -r is used) or .poly
++        file (if -r is not used) specifies a number of maximum area
++        constraints.  An .area file contains a separate area constraint for
++        each triangle, and is useful for refining a finite element mesh
++        based on a posteriori error estimates.  A .poly file can optionally
++        contain an area constraint for each segment-bounded region, thereby
++        enforcing triangle densities in a first triangulation.  You can
++        impose both a fixed area constraint and a varying area constraint
++        by invoking the -a switch twice, once with and once without a
++        number following.  Each area specified may include a decimal point.
++    -A  Assigns an additional attribute to each triangle that identifies
++        what segment-bounded region each triangle belongs to.  Attributes
++        are assigned to regions by the .poly file.  If a region is not
++        explicitly marked by the .poly file, triangles in that region are
++        assigned an attribute of zero.  The -A switch has an effect only
++        when the -p switch is used and the -r switch is not.
++    -c  Creates segments on the convex hull of the triangulation.  If you
++        are triangulating a point set, this switch causes a .poly file to
++        be written, containing all edges in the convex hull.  (By default,
++        a .poly file is written only if a .poly file is read.)  If you are
++        triangulating a PSLG, this switch specifies that the interior of
++        the convex hull of the PSLG should be triangulated.  If you do not
++        use this switch when triangulating a PSLG, it is assumed that you
++        have identified the region to be triangulated by surrounding it
++        with segments of the input PSLG.  Beware:  if you are not careful,
++        this switch can cause the introduction of an extremely thin angle
++        between a PSLG segment and a convex hull segment, which can cause
++        overrefinement or failure if Triangle runs out of precision.  If
++        you are refining a mesh, the -c switch works differently; it
++        generates the set of boundary edges of the mesh, rather than the
++        convex hull.
++    -e  Outputs (to an .edge file) a list of edges of the triangulation.
++    -v  Outputs the Voronoi diagram associated with the triangulation.
++        Does not attempt to detect degeneracies.
++    -n  Outputs (to a .neigh file) a list of triangles neighboring each
++        triangle.
++    -g  Outputs the mesh to an Object File Format (.off) file, suitable for
++        viewing with the Geometry Center's Geomview package.
++    -B  No boundary markers in the output .node, .poly, and .edge output
++        files.  See the detailed discussion of boundary markers below.
++    -P  No output .poly file.  Saves disk space, but you lose the ability
++        to impose segment constraints on later refinements of the mesh.
++    -N  No output .node file.
++    -E  No output .ele file.
++    -I  No iteration numbers.  Suppresses the output of .node and .poly
++        files, so your input files won't be overwritten.  (If your input is
++        a .poly file only, a .node file will be written.)  Cannot be used
++        with the -r switch, because that would overwrite your input .ele
++        file.  Shouldn't be used with the -s, -q, or -a switch if you are
++        using a .node file for input, because no .node file will be
++        written, so there will be no record of any added points.
++    -O  No holes.  Ignores the holes in the .poly file.
++    -X  No exact arithmetic.  Normally, Triangle uses exact floating-point
++        arithmetic for certain tests if it thinks the inexact tests are not
++        accurate enough.  Exact arithmetic ensures the robustness of the
++        triangulation algorithms, despite floating-point roundoff error.
++        Disabling exact arithmetic with the -X switch will cause a small
++        improvement in speed and create the possibility (albeit small) that
++        Triangle will fail to produce a valid mesh.  Not recommended.
++    -z  Numbers all items starting from zero (rather than one).  Note that
++        this switch is normally overrided by the value used to number the
++        first point of the input .node or .poly file.  However, this switch
++        is useful when calling Triangle from another program.
++    -o2 Generates second-order subparametric elements with six nodes each.
++    -Y  No new points on the boundary.  This switch is useful when the mesh
++        boundary must be preserved so that it conforms to some adjacent
++        mesh.  Be forewarned that you will probably sacrifice some of the
++        quality of the mesh; Triangle will try, but the resulting mesh may
++        contain triangles of poor aspect ratio.  Works well if all the
++        boundary points are closely spaced.  Specify this switch twice
++        (`-YY') to prevent all segment splitting, including internal
++        boundaries.
++    -S  Specifies the maximum number of Steiner points (points that are not
++        in the input, but are added to meet the constraints of minimum
++        angle and maximum area).  The default is to allow an unlimited
++        number.  If you specify this switch with no number after it,
++        the limit is set to zero.  Triangle always adds points at segment
++        intersections, even if it needs to use more points than the limit
++        you set.  When Triangle inserts segments by splitting (-s), it
++        always adds enough points to ensure that all the segments appear in
++        the triangulation, again ignoring the limit.  Be forewarned that
++        the -S switch may result in a conforming triangulation that is not
++        truly Delaunay, because Triangle may be forced to stop adding
++        points when the mesh is in a state where a segment is non-Delaunay
++        and needs to be split.  If so, Triangle will print a warning.
++    -i  Uses an incremental rather than divide-and-conquer algorithm to
++        form a Delaunay triangulation.  Try it if the divide-and-conquer
++        algorithm fails.
++    -F  Uses Steven Fortune's sweepline algorithm to form a Delaunay
++        triangulation.  Warning:  does not use exact arithmetic for all
++        calculations.  An exact result is not guaranteed.
++    -l  Uses only vertical cuts in the divide-and-conquer algorithm.  By
++        default, Triangle uses alternating vertical and horizontal cuts,
++        which usually improve the speed except with point sets that are
++        small or short and wide.  This switch is primarily of theoretical
++        interest.
++    -s  Specifies that segments should be forced into the triangulation by
++        recursively splitting them at their midpoints, rather than by
++        generating a constrained Delaunay triangulation.  Segment splitting
++        is true to Ruppert's original algorithm, but can create needlessly
++        small triangles near external small features.
++    -C  Check the consistency of the final mesh.  Uses exact arithmetic for
++        checking, even if the -X switch is used.  Useful if you suspect
++        Triangle is buggy.
++    -Q  Quiet: Suppresses all explanation of what Triangle is doing, unless
++        an error occurs.
++    -V  Verbose: Gives detailed information about what Triangle is doing.
++        Add more `V's for increasing amount of detail.  `-V' gives
++        information on algorithmic progress and more detailed statistics.
++        `-VV' gives point-by-point details, and will print so much that
++        Triangle will run much more slowly.  `-VVV' gives information only
++        a debugger could love.
++    -h  Help:  Displays these instructions.
++
++Definitions:
++
++  A Delaunay triangulation of a point set is a triangulation whose vertices
++  are the point set, having the property that no point in the point set
++  falls in the interior of the circumcircle (circle that passes through all
++  three vertices) of any triangle in the triangulation.
++
++  A Voronoi diagram of a point set is a subdivision of the plane into
++  polygonal regions (some of which may be infinite), where each region is
++  the set of points in the plane that are closer to some input point than
++  to any other input point.  (The Voronoi diagram is the geometric dual of
++  the Delaunay triangulation.)
++
++  A Planar Straight Line Graph (PSLG) is a collection of points and
++  segments.  Segments are simply edges, whose endpoints are points in the
++  PSLG.  The file format for PSLGs (.poly files) is described below.
++
++  A constrained Delaunay triangulation of a PSLG is similar to a Delaunay
++  triangulation, but each PSLG segment is present as a single edge in the
++  triangulation.  (A constrained Delaunay triangulation is not truly a
++  Delaunay triangulation.)
++
++  A conforming Delaunay triangulation of a PSLG is a true Delaunay
++  triangulation in which each PSLG segment may have been subdivided into
++  several edges by the insertion of additional points.  These inserted
++  points are necessary to allow the segments to exist in the mesh while
++  maintaining the Delaunay property.
++
++File Formats:
++
++  All files may contain comments prefixed by the character '#'.  Points,
++  triangles, edges, holes, and maximum area constraints must be numbered
++  consecutively, starting from either 1 or 0.  Whichever you choose, all
++  input files must be consistent; if the nodes are numbered from 1, so must
++  be all other objects.  Triangle automatically detects your choice while
++  reading the .node (or .poly) file.  (When calling Triangle from another
++  program, use the -z switch if you wish to number objects from zero.)
++  Examples of these file formats are given below.
++
++  .node files:
++    First line:  <# of points> <dimension (must be 2)> <# of attributes>
++                                           <# of boundary markers (0 or 1)>
++    Remaining lines:  <point #> <x> <y> [attributes] [boundary marker]
++
++    The attributes, which are typically floating-point values of physical
++    quantities (such as mass or conductivity) associated with the nodes of
++    a finite element mesh, are copied unchanged to the output mesh.  If -s,
++    -q, or -a is selected, each new Steiner point added to the mesh will
++    have attributes assigned to it by linear interpolation.
++
++    If the fourth entry of the first line is `1', the last column of the
++    remainder of the file is assumed to contain boundary markers.  Boundary
++    markers are used to identify boundary points and points resting on PSLG
++    segments; a complete description appears in a section below.  The .node
++    file produced by Triangle will contain boundary markers in the last
++    column unless they are suppressed by the -B switch.
++
++  .ele files:
++    First line:  <# of triangles> <points per triangle> <# of attributes>
++    Remaining lines:  <triangle #> <point> <point> <point> ... [attributes]
++
++    Points are indices into the corresponding .node file.  The first three
++    points are the corners, and are listed in counterclockwise order around
++    each triangle.  (The remaining points, if any, depend on the type of
++    finite element used.)  The attributes are just like those of .node
++    files.  Because there is no simple mapping from input to output
++    triangles, an attempt is made to interpolate attributes, which may
++    result in a good deal of diffusion of attributes among nearby triangles
++    as the triangulation is refined.  Diffusion does not occur across
++    segments, so attributes used to identify segment-bounded regions remain
++    intact.  In output .ele files, all triangles have three points each
++    unless the -o2 switch is used, in which case they have six, and the
++    fourth, fifth, and sixth points lie on the midpoints of the edges
++    opposite the first, second, and third corners.
++
++  .poly files:
++    First line:  <# of points> <dimension (must be 2)> <# of attributes>
++                                           <# of boundary markers (0 or 1)>
++    Following lines:  <point #> <x> <y> [attributes] [boundary marker]
++    One line:  <# of segments> <# of boundary markers (0 or 1)>
++    Following lines:  <segment #> <endpoint> <endpoint> [boundary marker]
++    One line:  <# of holes>
++    Following lines:  <hole #> <x> <y>
++    Optional line:  <# of regional attributes and/or area constraints>
++    Optional following lines:  <constraint #> <x> <y> <attrib> <max area>
++
++    A .poly file represents a PSLG, as well as some additional information.
++    The first section lists all the points, and is identical to the format
++    of .node files.  <# of points> may be set to zero to indicate that the
++    points are listed in a separate .node file; .poly files produced by
++    Triangle always have this format.  This has the advantage that a point
++    set may easily be triangulated with or without segments.  (The same
++    effect can be achieved, albeit using more disk space, by making a copy
++    of the .poly file with the extension .node; all sections of the file
++    but the first are ignored.)
++
++    The second section lists the segments.  Segments are edges whose
++    presence in the triangulation is enforced.  Each segment is specified
++    by listing the indices of its two endpoints.  This means that you must
++    include its endpoints in the point list.  If -s, -q, and -a are not
++    selected, Triangle will produce a constrained Delaunay triangulation,
++    in which each segment appears as a single edge in the triangulation.
++    If -q or -a is selected, Triangle will produce a conforming Delaunay
++    triangulation, in which segments may be subdivided into smaller edges.
++    Each segment, like each point, may have a boundary marker.
++
++    The third section lists holes (and concavities, if -c is selected) in
++    the triangulation.  Holes are specified by identifying a point inside
++    each hole.  After the triangulation is formed, Triangle creates holes
++    by eating triangles, spreading out from each hole point until its
++    progress is blocked by PSLG segments; you must be careful to enclose
++    each hole in segments, or your whole triangulation may be eaten away.
++    If the two triangles abutting a segment are eaten, the segment itself
++    is also eaten.  Do not place a hole directly on a segment; if you do,
++    Triangle will choose one side of the segment arbitrarily.
++
++    The optional fourth section lists regional attributes (to be assigned
++    to all triangles in a region) and regional constraints on the maximum
++    triangle area.  Triangle will read this section only if the -A switch
++    is used or the -a switch is used without a number following it, and the
++    -r switch is not used.  Regional attributes and area constraints are
++    propagated in the same manner as holes; you specify a point for each
++    attribute and/or constraint, and the attribute and/or constraint will
++    affect the whole region (bounded by segments) containing the point.  If
++    two values are written on a line after the x and y coordinate, the
++    former is assumed to be a regional attribute (but will only be applied
++    if the -A switch is selected), and the latter is assumed to be a
++    regional area constraint (but will only be applied if the -a switch is
++    selected).  You may also specify just one value after the coordinates,
++    which can serve as both an attribute and an area constraint, depending
++    on the choice of switches.  If you are using the -A and -a switches
++    simultaneously and wish to assign an attribute to some region without
++    imposing an area constraint, use a negative maximum area.
++
++    When a triangulation is created from a .poly file, you must either
++    enclose the entire region to be triangulated in PSLG segments, or
++    use the -c switch, which encloses the convex hull of the input point
++    set.  If you do not use the -c switch, Triangle will eat all triangles
++    on the outer boundary that are not protected by segments; if you are
++    not careful, your whole triangulation may be eaten away.  If you do
++    use the -c switch, you can still produce concavities by appropriate
++    placement of holes just inside the convex hull.
++
++    An ideal PSLG has no intersecting segments, nor any points that lie
++    upon segments (except, of course, the endpoints of each segment.)  You
++    aren't required to make your .poly files ideal, but you should be aware
++    of what can go wrong.  Segment intersections are relatively safe -
++    Triangle will calculate the intersection points for you and add them to
++    the triangulation - as long as your machine's floating-point precision
++    doesn't become a problem.  You are tempting the fates if you have three
++    segments that cross at the same location, and expect Triangle to figure
++    out where the intersection point is.  Thanks to floating-point roundoff
++    error, Triangle will probably decide that the three segments intersect
++    at three different points, and you will find a minuscule triangle in
++    your output - unless Triangle tries to refine the tiny triangle, uses
++    up the last bit of machine precision, and fails to terminate at all.
++    You're better off putting the intersection point in the input files,
++    and manually breaking up each segment into two.  Similarly, if you
++    place a point at the middle of a segment, and hope that Triangle will
++    break up the segment at that point, you might get lucky.  On the other
++    hand, Triangle might decide that the point doesn't lie precisely on the
++    line, and you'll have a needle-sharp triangle in your output - or a lot
++    of tiny triangles if you're generating a quality mesh.
++
++    When Triangle reads a .poly file, it also writes a .poly file, which
++    includes all edges that are part of input segments.  If the -c switch
++    is used, the output .poly file will also include all of the edges on
++    the convex hull.  Hence, the output .poly file is useful for finding
++    edges associated with input segments and setting boundary conditions in
++    finite element simulations.  More importantly, you will need it if you
++    plan to refine the output mesh, and don't want segments to be missing
++    in later triangulations.
++
++  .area files:
++    First line:  <# of triangles>
++    Following lines:  <triangle #> <maximum area>
++
++    An .area file associates with each triangle a maximum area that is used
++    for mesh refinement.  As with other file formats, every triangle must
++    be represented, and they must be numbered consecutively.  A triangle
++    may be left unconstrained by assigning it a negative maximum area.
++
++  .edge files:
++    First line:  <# of edges> <# of boundary markers (0 or 1)>
++    Following lines:  <edge #> <endpoint> <endpoint> [boundary marker]
++
++    Endpoints are indices into the corresponding .node file.  Triangle can
++    produce .edge files (use the -e switch), but cannot read them.  The
++    optional column of boundary markers is suppressed by the -B switch.
++
++    In Voronoi diagrams, one also finds a special kind of edge that is an
++    infinite ray with only one endpoint.  For these edges, a different
++    format is used:
++
++        <edge #> <endpoint> -1 <direction x> <direction y>
++
++    The `direction' is a floating-point vector that indicates the direction
++    of the infinite ray.
++
++  .neigh files:
++    First line:  <# of triangles> <# of neighbors per triangle (always 3)>
++    Following lines:  <triangle #> <neighbor> <neighbor> <neighbor>
++
++    Neighbors are indices into the corresponding .ele file.  An index of -1
++    indicates a mesh boundary, and therefore no neighbor.  Triangle can
++    produce .neigh files (use the -n switch), but cannot read them.
++
++    The first neighbor of triangle i is opposite the first corner of
++    triangle i, and so on.
++
++Boundary Markers:
++
++  Boundary markers are tags used mainly to identify which output points and
++  edges are associated with which PSLG segment, and to identify which
++  points and edges occur on a boundary of the triangulation.  A common use
++  is to determine where boundary conditions should be applied to a finite
++  element mesh.  You can prevent boundary markers from being written into
++  files produced by Triangle by using the -B switch.
++
++  The boundary marker associated with each segment in an output .poly file
++  or edge in an output .edge file is chosen as follows:
++    - If an output edge is part or all of a PSLG segment with a nonzero
++      boundary marker, then the edge is assigned the same marker.
++    - Otherwise, if the edge occurs on a boundary of the triangulation
++      (including boundaries of holes), then the edge is assigned the marker
++      one (1).
++    - Otherwise, the edge is assigned the marker zero (0).
++  The boundary marker associated with each point in an output .node file is
++  chosen as follows:
++    - If a point is assigned a nonzero boundary marker in the input file,
++      then it is assigned the same marker in the output .node file.
++    - Otherwise, if the point lies on a PSLG segment (including the
++      segment's endpoints) with a nonzero boundary marker, then the point
++      is assigned the same marker.  If the point lies on several such
++      segments, one of the markers is chosen arbitrarily.
++    - Otherwise, if the point occurs on a boundary of the triangulation,
++      then the point is assigned the marker one (1).
++    - Otherwise, the point is assigned the marker zero (0).
++
++  If you want Triangle to determine for you which points and edges are on
++  the boundary, assign them the boundary marker zero (or use no markers at
++  all) in your input files.  Alternatively, you can mark some of them and
++  leave others marked zero, allowing Triangle to label them.
++
++Triangulation Iteration Numbers:
++
++  Because Triangle can read and refine its own triangulations, input
++  and output files have iteration numbers.  For instance, Triangle might
++  read the files mesh.3.node, mesh.3.ele, and mesh.3.poly, refine the
++  triangulation, and output the files mesh.4.node, mesh.4.ele, and
++  mesh.4.poly.  Files with no iteration number are treated as if
++  their iteration number is zero; hence, Triangle might read the file
++  points.node, triangulate it, and produce the files points.1.node and
++  points.1.ele.
++
++  Iteration numbers allow you to create a sequence of successively finer
++  meshes suitable for multigrid methods.  They also allow you to produce a
++  sequence of meshes using error estimate-driven mesh refinement.
++
++  If you're not using refinement or quality meshing, and you don't like
++  iteration numbers, use the -I switch to disable them.  This switch will
++  also disable output of .node and .poly files to prevent your input files
++  from being overwritten.  (If the input is a .poly file that contains its
++  own points, a .node file will be written.)
++
++Examples of How to Use Triangle:
++
++  `triangle dots' will read points from dots.node, and write their Delaunay
++  triangulation to dots.1.node and dots.1.ele.  (dots.1.node will be
++  identical to dots.node.)  `triangle -I dots' writes the triangulation to
++  dots.ele instead.  (No additional .node file is needed, so none is
++  written.)
++
++  `triangle -pe object.1' will read a PSLG from object.1.poly (and possibly
++  object.1.node, if the points are omitted from object.1.poly) and write
++  their constrained Delaunay triangulation to object.2.node and
++  object.2.ele.  The segments will be copied to object.2.poly, and all
++  edges will be written to object.2.edge.
++
++  `triangle -pq31.5a.1 object' will read a PSLG from object.poly (and
++  possibly object.node), generate a mesh whose angles are all greater than
++  31.5 degrees and whose triangles all have area smaller than 0.1, and
++  write the mesh to object.1.node and object.1.ele.  Each segment may have
++  been broken up into multiple edges; the resulting constrained edges are
++  written to object.1.poly.
++
++  Here is a sample file `box.poly' describing a square with a square hole:
++
++    # A box with eight points in 2D, no attributes, one boundary marker.
++    8 2 0 1
++    # Outer box has these vertices:
++     1   0 0   0
++     2   0 3   0
++     3   3 0   0
++     4   3 3   33     # A special marker for this point.
++    # Inner square has these vertices:
++     5   1 1   0
++     6   1 2   0
++     7   2 1   0
++     8   2 2   0
++    # Five segments with boundary markers.
++    5 1
++     1   1 2   5      # Left side of outer box.
++     2   5 7   0      # Segments 2 through 5 enclose the hole.
++     3   7 8   0
++     4   8 6   10
++     5   6 5   0
++    # One hole in the middle of the inner square.
++    1
++     1   1.5 1.5
++
++  Note that some segments are missing from the outer square, so one must
++  use the `-c' switch.  After `triangle -pqc box.poly', here is the output
++  file `box.1.node', with twelve points.  The last four points were added
++  to meet the angle constraint.  Points 1, 2, and 9 have markers from
++  segment 1.  Points 6 and 8 have markers from segment 4.  All the other
++  points but 4 have been marked to indicate that they lie on a boundary.
++
++    12  2  0  1
++       1    0   0      5
++       2    0   3      5
++       3    3   0      1
++       4    3   3     33
++       5    1   1      1
++       6    1   2     10
++       7    2   1      1
++       8    2   2     10
++       9    0   1.5    5
++      10    1.5   0    1
++      11    3   1.5    1
++      12    1.5   3    1
++    # Generated by triangle -pqc box.poly
++
++  Here is the output file `box.1.ele', with twelve triangles.
++
++    12  3  0
++       1     5   6   9
++       2    10   3   7
++       3     6   8  12
++       4     9   1   5
++       5     6   2   9
++       6     7   3  11
++       7    11   4   8
++       8     7   5  10
++       9    12   2   6
++      10     8   7  11
++      11     5   1  10
++      12     8   4  12
++    # Generated by triangle -pqc box.poly
++
++  Here is the output file `box.1.poly'.  Note that segments have been added
++  to represent the convex hull, and some segments have been split by newly
++  added points.  Note also that <# of points> is set to zero to indicate
++  that the points should be read from the .node file.
++
++    0  2  0  1
++    12  1
++       1     1   9     5
++       2     5   7     1
++       3     8   7     1
++       4     6   8    10
++       5     5   6     1
++       6     3  10     1
++       7     4  11     1
++       8     2  12     1
++       9     9   2     5
++      10    10   1     1
++      11    11   3     1
++      12    12   4     1
++    1
++       1   1.5 1.5
++    # Generated by triangle -pqc box.poly
++
++Refinement and Area Constraints:
++
++  The -r switch causes a mesh (.node and .ele files) to be read and
++  refined.  If the -p switch is also used, a .poly file is read and used to
++  specify edges that are constrained and cannot be eliminated (although
++  they can be divided into smaller edges) by the refinement process.
++
++  When you refine a mesh, you generally want to impose tighter quality
++  constraints.  One way to accomplish this is to use -q with a larger
++  angle, or -a followed by a smaller area than you used to generate the
++  mesh you are refining.  Another way to do this is to create an .area
++  file, which specifies a maximum area for each triangle, and use the -a
++  switch (without a number following).  Each triangle's area constraint is
++  applied to that triangle.  Area constraints tend to diffuse as the mesh
++  is refined, so if there are large variations in area constraint between
++  adjacent triangles, you may not get the results you want.
++
++  If you are refining a mesh composed of linear (three-node) elements, the
++  output mesh will contain all the nodes present in the input mesh, in the
++  same order, with new nodes added at the end of the .node file.  However,
++  there is no guarantee that each output element is contained in a single
++  input element.  Often, output elements will overlap two input elements,
++  and input edges are not present in the output mesh.  Hence, a sequence of
++  refined meshes will form a hierarchy of nodes, but not a hierarchy of
++  elements.  If you a refining a mesh of higher-order elements, the
++  hierarchical property applies only to the nodes at the corners of an
++  element; other nodes may not be present in the refined mesh.
++
++  It is important to understand that maximum area constraints in .poly
++  files are handled differently from those in .area files.  A maximum area
++  in a .poly file applies to the whole (segment-bounded) region in which a
++  point falls, whereas a maximum area in an .area file applies to only one
++  triangle.  Area constraints in .poly files are used only when a mesh is
++  first generated, whereas area constraints in .area files are used only to
++  refine an existing mesh, and are typically based on a posteriori error
++  estimates resulting from a finite element simulation on that mesh.
++
++  `triangle -rq25 object.1' will read object.1.node and object.1.ele, then
++  refine the triangulation to enforce a 25 degree minimum angle, and then
++  write the refined triangulation to object.2.node and object.2.ele.
++
++  `triangle -rpaa6.2 z.3' will read z.3.node, z.3.ele, z.3.poly, and
++  z.3.area.  After reconstructing the mesh and its segments, Triangle will
++  refine the mesh so that no triangle has area greater than 6.2, and
++  furthermore the triangles satisfy the maximum area constraints in
++  z.3.area.  The output is written to z.4.node, z.4.ele, and z.4.poly.
++
++  The sequence `triangle -qa1 x', `triangle -rqa.3 x.1', `triangle -rqa.1
++  x.2' creates a sequence of successively finer meshes x.1, x.2, and x.3,
++  suitable for multigrid.
++
++Convex Hulls and Mesh Boundaries:
++
++  If the input is a point set (rather than a PSLG), Triangle produces its
++  convex hull as a by-product in the output .poly file if you use the -c
++  switch.  There are faster algorithms for finding a two-dimensional convex
++  hull than triangulation, of course, but this one comes for free.  If the
++  input is an unconstrained mesh (you are using the -r switch but not the
++  -p switch), Triangle produces a list of its boundary edges (including
++  hole boundaries) as a by-product if you use the -c switch.
++
++Voronoi Diagrams:
++
++  The -v switch produces a Voronoi diagram, in files suffixed .v.node and
++  .v.edge.  For example, `triangle -v points' will read points.node,
++  produce its Delaunay triangulation in points.1.node and points.1.ele,
++  and produce its Voronoi diagram in points.1.v.node and points.1.v.edge.
++  The .v.node file contains a list of all Voronoi vertices, and the .v.edge
++  file contains a list of all Voronoi edges, some of which may be infinite
++  rays.  (The choice of filenames makes it easy to run the set of Voronoi
++  vertices through Triangle, if so desired.)
++
++  This implementation does not use exact arithmetic to compute the Voronoi
++  vertices, and does not check whether neighboring vertices are identical.
++  Be forewarned that if the Delaunay triangulation is degenerate or
++  near-degenerate, the Voronoi diagram may have duplicate points, crossing
++  edges, or infinite rays whose direction vector is zero.  Also, if you
++  generate a constrained (as opposed to conforming) Delaunay triangulation,
++  or if the triangulation has holes, the corresponding Voronoi diagram is
++  likely to have crossing edges and unlikely to make sense.
++
++Mesh Topology:
++
++  You may wish to know which triangles are adjacent to a certain Delaunay
++  edge in an .edge file, which Voronoi regions are adjacent to a certain
++  Voronoi edge in a .v.edge file, or which Voronoi regions are adjacent to
++  each other.  All of this information can be found by cross-referencing
++  output files with the recollection that the Delaunay triangulation and
++  the Voronoi diagrams are planar duals.
++
++  Specifically, edge i of an .edge file is the dual of Voronoi edge i of
++  the corresponding .v.edge file, and is rotated 90 degrees counterclock-
++  wise from the Voronoi edge.  Triangle j of an .ele file is the dual of
++  vertex j of the corresponding .v.node file; and Voronoi region k is the
++  dual of point k of the corresponding .node file.
++
++  Hence, to find the triangles adjacent to a Delaunay edge, look at the
++  vertices of the corresponding Voronoi edge; their dual triangles are on
++  the left and right of the Delaunay edge, respectively.  To find the
++  Voronoi regions adjacent to a Voronoi edge, look at the endpoints of the
++  corresponding Delaunay edge; their dual regions are on the right and left
++  of the Voronoi edge, respectively.  To find which Voronoi regions are
++  adjacent to each other, just read the list of Delaunay edges.
++
++Statistics:
++
++  After generating a mesh, Triangle prints a count of the number of points,
++  triangles, edges, boundary edges, and segments in the output mesh.  If
++  you've forgotten the statistics for an existing mesh, the -rNEP switches
++  (or -rpNEP if you've got a .poly file for the existing mesh) will
++  regenerate these statistics without writing any output.
++
++  The -V switch produces extended statistics, including a rough estimate
++  of memory use and a histogram of triangle aspect ratios and angles in the
++  mesh.
++
++Exact Arithmetic:
++
++  Triangle uses adaptive exact arithmetic to perform what computational
++  geometers call the `orientation' and `incircle' tests.  If the floating-
++  point arithmetic of your machine conforms to the IEEE 754 standard (as
++  most workstations do), and does not use extended precision internal
++  registers, then your output is guaranteed to be an absolutely true
++  Delaunay or conforming Delaunay triangulation, roundoff error
++  notwithstanding.  The word `adaptive' implies that these arithmetic
++  routines compute the result only to the precision necessary to guarantee
++  correctness, so they are usually nearly as fast as their approximate
++  counterparts.  The exact tests can be disabled with the -X switch.  On
++  most inputs, this switch will reduce the computation time by about eight
++  percent - it's not worth the risk.  There are rare difficult inputs
++  (having many collinear and cocircular points), however, for which the
++  difference could be a factor of two.  These are precisely the inputs most
++  likely to cause errors if you use the -X switch.
++
++  Unfortunately, these routines don't solve every numerical problem.  Exact
++  arithmetic is not used to compute the positions of points, because the
++  bit complexity of point coordinates would grow without bound.  Hence,
++  segment intersections aren't computed exactly; in very unusual cases,
++  roundoff error in computing an intersection point might actually lead to
++  an inverted triangle and an invalid triangulation.  (This is one reason
++  to compute your own intersection points in your .poly files.)  Similarly,
++  exact arithmetic is not used to compute the vertices of the Voronoi
++  diagram.
++
++  Underflow and overflow can also cause difficulties; the exact arithmetic
++  routines do not ameliorate out-of-bounds exponents, which can arise
++  during the orientation and incircle tests.  As a rule of thumb, you
++  should ensure that your input values are within a range such that their
++  third powers can be taken without underflow or overflow.  Underflow can
++  silently prevent the tests from being performed exactly, while overflow
++  will typically cause a floating exception.
++
++Calling Triangle from Another Program:
++
++  Read the file triangle.h for details.
++
++Troubleshooting:
++
++  Please read this section before mailing me bugs.
++
++  `My output mesh has no triangles!'
++
++    If you're using a PSLG, you've probably failed to specify a proper set
++    of bounding segments, or forgotten to use the -c switch.  Or you may
++    have placed a hole badly.  To test these possibilities, try again with
++    the -c and -O switches.  Alternatively, all your input points may be
++    collinear, in which case you can hardly expect to triangulate them.
++
++  `Triangle doesn't terminate, or just crashes.'
++
++    Bad things can happen when triangles get so small that the distance
++    between their vertices isn't much larger than the precision of your
++    machine's arithmetic.  If you've compiled Triangle for single-precision
++    arithmetic, you might do better by recompiling it for double-precision.
++    Then again, you might just have to settle for more lenient constraints
++    on the minimum angle and the maximum area than you had planned.
++
++    You can minimize precision problems by ensuring that the origin lies
++    inside your point set, or even inside the densest part of your
++    mesh.  On the other hand, if you're triangulating an object whose x
++    coordinates all fall between 6247133 and 6247134, you're not leaving
++    much floating-point precision for Triangle to work with.
++
++    Precision problems can occur covertly if the input PSLG contains two
++    segments that meet (or intersect) at a very small angle, or if such an
++    angle is introduced by the -c switch, which may occur if a point lies
++    ever-so-slightly inside the convex hull, and is connected by a PSLG
++    segment to a point on the convex hull.  If you don't realize that a
++    small angle is being formed, you might never discover why Triangle is
++    crashing.  To check for this possibility, use the -S switch (with an
++    appropriate limit on the number of Steiner points, found by trial-and-
++    error) to stop Triangle early, and view the output .poly file with
++    Show Me (described below).  Look carefully for small angles between
++    segments; zoom in closely, as such segments might look like a single
++    segment from a distance.
++
++    If some of the input values are too large, Triangle may suffer a
++    floating exception due to overflow when attempting to perform an
++    orientation or incircle test.  (Read the section on exact arithmetic
++    above.)  Again, I recommend compiling Triangle for double (rather
++    than single) precision arithmetic.
++
++  `The numbering of the output points doesn't match the input points.'
++
++    You may have eaten some of your input points with a hole, or by placing
++    them outside the area enclosed by segments.
++
++  `Triangle executes without incident, but when I look at the resulting
++  mesh, it has overlapping triangles or other geometric inconsistencies.'
++
++    If you select the -X switch, Triangle's divide-and-conquer Delaunay
++    triangulation algorithm occasionally makes mistakes due to floating-
++    point roundoff error.  Although these errors are rare, don't use the -X
++    switch.  If you still have problems, please report the bug.
++
++  Strange things can happen if you've taken liberties with your PSLG.  Do
++  you have a point lying in the middle of a segment?  Triangle sometimes
++  copes poorly with that sort of thing.  Do you want to lay out a collinear
++  row of evenly spaced, segment-connected points?  Have you simply defined
++  one long segment connecting the leftmost point to the rightmost point,
++  and a bunch of points lying along it?  This method occasionally works,
++  especially with horizontal and vertical lines, but often it doesn't, and
++  you'll have to connect each adjacent pair of points with a separate
++  segment.  If you don't like it, tough.
++
++  Furthermore, if you have segments that intersect other than at their
++  endpoints, try not to let the intersections fall extremely close to PSLG
++  points or each other.
++
++  If you have problems refining a triangulation not produced by Triangle:
++  Are you sure the triangulation is geometrically valid?  Is it formatted
++  correctly for Triangle?  Are the triangles all listed so the first three
++  points are their corners in counterclockwise order?
++
++Show Me:
++
++  Triangle comes with a separate program named `Show Me', whose primary
++  purpose is to draw meshes on your screen or in PostScript.  Its secondary
++  purpose is to check the validity of your input files, and do so more
++  thoroughly than Triangle does.  Show Me requires that you have the X
++  Windows system.  If you didn't receive Show Me with Triangle, complain to
++  whomever you obtained Triangle from, then send me mail.
++
++Triangle on the Web:
++
++  To see an illustrated, updated version of these instructions, check out
++
++    http://www.cs.cmu.edu/~quake/triangle.html
++
++A Brief Plea:
++
++  If you use Triangle, and especially if you use it to accomplish real
++  work, I would like very much to hear from you.  A short letter or email
++  (to jrs@cs.cmu.edu) describing how you use Triangle will mean a lot to
++  me.  The more people I know are using this program, the more easily I can
++  justify spending time on improvements and on the three-dimensional
++  successor to Triangle, which in turn will benefit you.  Also, I can put
++  you on a list to receive email whenever a new version of Triangle is
++  available.
++
++  If you use a mesh generated by Triangle in a publication, please include
++  an acknowledgment as well.
++
++Research credit:
++
++  Of course, I can take credit for only a fraction of the ideas that made
++  this mesh generator possible.  Triangle owes its existence to the efforts
++  of many fine computational geometers and other researchers, including
++  Marshall Bern, L. Paul Chew, Boris Delaunay, Rex A. Dwyer, David
++  Eppstein, Steven Fortune, Leonidas J. Guibas, Donald E. Knuth, C. L.
++  Lawson, Der-Tsai Lee, Ernst P. Mucke, Douglas M. Priest, Jim Ruppert,
++  Isaac Saias, Bruce J. Schachter, Micha Sharir, Jorge Stolfi, Christopher
++  J. Van Wyk, David F. Watson, and Binhai Zhu.  See the comments at the
++  beginning of the source code for references.
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b9be696c35ff1d12a762fbcb0d482c62282fb02f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,289 @@@
++/*****************************************************************************/
++/*                                                                           */
++/*  (triangle.h)                                                             */
++/*                                                                           */
++/*  Include file for programs that call Triangle.                            */
++/*                                                                           */
++/*  Accompanies Triangle Version 1.3                                         */
++/*  July 19, 1996                                                            */
++/*                                                                           */
++/*  Copyright 1996                                                           */
++/*  Jonathan Richard Shewchuk                                                */
++/*  School of Computer Science                                               */
++/*  Carnegie Mellon University                                               */
++/*  5000 Forbes Avenue                                                       */
++/*  Pittsburgh, Pennsylvania  15213-3891                                     */
++/*  jrs@cs.cmu.edu                                                           */
++/*                                                                           */
++/*****************************************************************************/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  How to call Triangle from another program                                */
++/*                                                                           */
++/*                                                                           */
++/*  If you haven't read Triangle's instructions (run "triangle -h" to read   */
++/*  them), you won't understand what follows.                                */
++/*                                                                           */
++/*  Triangle must be compiled into an object file (triangle.o) with the      */
++/*  TRILIBRARY symbol defined (preferably by using the -DTRILIBRARY compiler */
++/*  switch).  The makefile included with Triangle will do this for you if    */
++/*  you run "make trilibrary".  The resulting object file can be called via  */
++/*  the procedure triangulate().                                             */
++/*                                                                           */
++/*  If the size of the object file is important to you, you may wish to      */
++/*  generate a reduced version of triangle.o.  The REDUCED symbol gets rid   */
++/*  of all features that are primarily of research interest.  Specifically,  */
++/*  the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches.  */
++/*  The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond  */
++/*  constrained Delaunay triangulation.  Specifically, the -DCDT_ONLY switch */
++/*  eliminates Triangle's -r, -q, -a, -S, and -s switches.                   */
++/*                                                                           */
++/*  IMPORTANT:  These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be    */
++/*  made in the makefile or in triangle.c itself.  Putting these definitions */
++/*  in this file will not create the desired effect.                         */
++/*                                                                           */
++/*                                                                           */
++/*  The calling convention for triangulate() follows.                        */
++/*                                                                           */
++/*      void triangulate(triswitches, in, out, vorout)                       */
++/*      char *triswitches;                                                   */
++/*      struct triangulateio *in;                                            */
++/*      struct triangulateio *out;                                           */
++/*      struct triangulateio *vorout;                                        */
++/*                                                                           */
++/*  `triswitches' is a string containing the command line switches you wish  */
++/*  to invoke.  No initial dash is required.  Some suggestions:              */
++/*                                                                           */
++/*  - You'll probably find it convenient to use the `z' switch so that       */
++/*    points (and other items) are numbered from zero.  This simplifies      */
++/*    indexing, because the first item of any type always starts at index    */
++/*    [0] of the corresponding array, whether that item's number is zero or  */
++/*    one.                                                                   */
++/*  - You'll probably want to use the `Q' (quiet) switch in your final code, */
++/*    but you can take advantage of Triangle's printed output (including the */
++/*    `V' switch) while debugging.                                           */
++/*  - If you are not using the `q' or `a' switches, then the output points   */
++/*    will be identical to the input points, except possibly for the         */
++/*    boundary markers.  If you don't need the boundary markers, you should  */
++/*    use the `N' (no nodes output) switch to save memory.  (If you do need  */
++/*    boundary markers, but need to save memory, a good nasty trick is to    */
++/*    set out->pointlist equal to in->pointlist before calling triangulate(),*/
++/*    so that Triangle overwrites the input points with identical copies.)   */
++/*  - The `I' (no iteration numbers) and `g' (.off file output) switches     */
++/*    have no effect when Triangle is compiled with TRILIBRARY defined.      */
++/*                                                                           */
++/*  `in', `out', and `vorout' are descriptions of the input, the output,     */
++/*  and the Voronoi output.  If the `v' (Voronoi output) switch is not used, */
++/*  `vorout' may be NULL.  `in' and `out' may never be NULL.                 */
++/*                                                                           */
++/*  Certain fields of the input and output structures must be initialized,   */
++/*  as described below.                                                      */
++/*                                                                           */
++/*****************************************************************************/
++
++/*****************************************************************************/
++/*                                                                           */
++/*  The `triangulateio' structure.                                           */
++/*                                                                           */
++/*  Used to pass data into and out of the triangulate() procedure.           */
++/*                                                                           */
++/*                                                                           */
++/*  Arrays are used to store points, triangles, markers, and so forth.  In   */
++/*  all cases, the first item in any array is stored starting at index [0].  */
++/*  However, that item is item number `1' unless the `z' switch is used, in  */
++/*  which case it is item number `0'.  Hence, you may find it easier to      */
++/*  index points (and triangles in the neighbor list) if you use the `z'     */
++/*  switch.  Unless, of course, you're calling Triangle from a Fortran       */
++/*  program.                                                                 */
++/*                                                                           */
++/*  Description of fields (except the `numberof' fields, which are obvious): */
++/*                                                                           */
++/*  `pointlist':  An array of point coordinates.  The first point's x        */
++/*    coordinate is at index [0] and its y coordinate at index [1], followed */
++/*    by the coordinates of the remaining points.  Each point occupies two   */
++/*    REALs.                                                                 */
++/*  `pointattributelist':  An array of point attributes.  Each point's       */
++/*    attributes occupy `numberofpointattributes' REALs.                     */
++/*  `pointmarkerlist':  An array of point markers; one int per point.        */
++/*                                                                           */
++/*  `trianglelist':  An array of triangle corners.  The first triangle's     */
++/*    first corner is at index [0], followed by its other two corners in     */
++/*    counterclockwise order, followed by any other nodes if the triangle    */
++/*    represents a nonlinear element.  Each triangle occupies                */
++/*    `numberofcorners' ints.                                                */
++/*  `triangleattributelist':  An array of triangle attributes.  Each         */
++/*    triangle's attributes occupy `numberoftriangleattributes' REALs.       */
++/*  `trianglearealist':  An array of triangle area constraints; one REAL per */
++/*    triangle.  Input only.                                                 */
++/*  `neighborlist':  An array of triangle neighbors; three ints per          */
++/*    triangle.  Output only.                                                */
++/*                                                                           */
++/*  `segmentlist':  An array of segment endpoints.  The first segment's      */
++/*    endpoints are at indices [0] and [1], followed by the remaining        */
++/*    segments.  Two ints per segment.                                       */
++/*  `segmentmarkerlist':  An array of segment markers; one int per segment.  */
++/*                                                                           */
++/*  `holelist':  An array of holes.  The first hole's x and y coordinates    */
++/*    are at indices [0] and [1], followed by the remaining holes.  Two      */
++/*    REALs per hole.  Input only, although the pointer is copied to the     */
++/*    output structure for your convenience.                                 */
++/*                                                                           */
++/*  `regionlist':  An array of regional attributes and area constraints.     */
++/*    The first constraint's x and y coordinates are at indices [0] and [1], */
++/*    followed by the regional attribute and index [2], followed by the      */
++/*    maximum area at index [3], followed by the remaining area constraints. */
++/*    Four REALs per area constraint.  Note that each regional attribute is  */
++/*    used only if you select the `A' switch, and each area constraint is    */
++/*    used only if you select the `a' switch (with no number following), but */
++/*    omitting one of these switches does not change the memory layout.      */
++/*    Input only, although the pointer is copied to the output structure for */
++/*    your convenience.                                                      */
++/*                                                                           */
++/*  `edgelist':  An array of edge endpoints.  The first edge's endpoints are */
++/*    at indices [0] and [1], followed by the remaining edges.  Two ints per */
++/*    edge.  Output only.                                                    */
++/*  `edgemarkerlist':  An array of edge markers; one int per edge.  Output   */
++/*    only.                                                                  */
++/*  `normlist':  An array of normal vectors, used for infinite rays in       */
++/*    Voronoi diagrams.  The first normal vector's x and y magnitudes are    */
++/*    at indices [0] and [1], followed by the remaining vectors.  For each   */
++/*    finite edge in a Voronoi diagram, the normal vector written is the     */
++/*    zero vector.  Two REALs per edge.  Output only.                        */
++/*                                                                           */
++/*                                                                           */
++/*  Any input fields that Triangle will examine must be initialized.         */
++/*  Furthermore, for each output array that Triangle will write to, you      */
++/*  must either provide space by setting the appropriate pointer to point    */
++/*  to the space you want the data written to, or you must initialize the    */
++/*  pointer to NULL, which tells Triangle to allocate space for the results. */
++/*  The latter option is preferable, because Triangle always knows exactly   */
++/*  how much space to allocate.  The former option is provided mainly for    */
++/*  people who need to call Triangle from Fortran code, though it also makes */
++/*  possible some nasty space-saving tricks, like writing the output to the  */
++/*  same arrays as the input.                                                */
++/*                                                                           */
++/*  Triangle will not free() any input or output arrays, including those it  */
++/*  allocates itself; that's up to you.                                      */
++/*                                                                           */
++/*  Here's a guide to help you decide which fields you must initialize       */
++/*  before you call triangulate().                                           */
++/*                                                                           */
++/*  `in':                                                                    */
++/*                                                                           */
++/*    - `pointlist' must always point to a list of points; `numberofpoints'  */
++/*      and `numberofpointattributes' must be properly set.                  */
++/*      `pointmarkerlist' must either be set to NULL (in which case all      */
++/*      markers default to zero), or must point to a list of markers.  If    */
++/*      `numberofpointattributes' is not zero, `pointattributelist' must     */
++/*      point to a list of point attributes.                                 */
++/*    - If the `r' switch is used, `trianglelist' must point to a list of    */
++/*      triangles, and `numberoftriangles', `numberofcorners', and           */
++/*      `numberoftriangleattributes' must be properly set.  If               */
++/*      `numberoftriangleattributes' is not zero, `triangleattributelist'    */
++/*      must point to a list of triangle attributes.  If the `a' switch is   */
++/*      used (with no number following), `trianglearealist' must point to a  */
++/*      list of triangle area constraints.  `neighborlist' may be ignored.   */
++/*    - If the `p' switch is used, `segmentlist' must point to a list of     */
++/*      segments, `numberofsegments' must be properly set, and               */
++/*      `segmentmarkerlist' must either be set to NULL (in which case all    */
++/*      markers default to zero), or must point to a list of markers.        */
++/*    - If the `p' switch is used without the `r' switch, then               */
++/*      `numberofholes' and `numberofregions' must be properly set.  If      */
++/*      `numberofholes' is not zero, `holelist' must point to a list of      */
++/*      holes.  If `numberofregions' is not zero, `regionlist' must point to */
++/*      a list of region constraints.                                        */
++/*    - If the `p' switch is used, `holelist', `numberofholes',              */
++/*      `regionlist', and `numberofregions' is copied to `out'.  (You can    */
++/*      nonetheless get away with not initializing them if the `r' switch is */
++/*      used.)                                                               */
++/*    - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */
++/*      ignored.                                                             */
++/*                                                                           */
++/*  `out':                                                                   */
++/*                                                                           */
++/*    - `pointlist' must be initialized (NULL or pointing to memory) unless  */
++/*      the `N' switch is used.  `pointmarkerlist' must be initialized       */
++/*      unless the `N' or `B' switch is used.  If `N' is not used and        */
++/*      `in->numberofpointattributes' is not zero, `pointattributelist' must */
++/*      be initialized.                                                      */
++/*    - `trianglelist' must be initialized unless the `E' switch is used.    */
++/*      `neighborlist' must be initialized if the `n' switch is used.  If    */
++/*      the `E' switch is not used and (`in->numberofelementattributes' is   */
++/*      not zero or the `A' switch is used), `elementattributelist' must be  */
++/*      initialized.  `trianglearealist' may be ignored.                     */
++/*    - `segmentlist' must be initialized if the `p' or `c' switch is used,  */
++/*      and the `P' switch is not used.  `segmentmarkerlist' must also be    */
++/*      initialized under these circumstances unless the `B' switch is used. */
++/*    - `edgelist' must be initialized if the `e' switch is used.            */
++/*      `edgemarkerlist' must be initialized if the `e' switch is used and   */
++/*      the `B' switch is not.                                               */
++/*    - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/
++/*                                                                           */
++/*  `vorout' (only needed if `v' switch is used):                            */
++/*                                                                           */
++/*    - `pointlist' must be initialized.  If `in->numberofpointattributes'   */
++/*      is not zero, `pointattributelist' must be initialized.               */
++/*      `pointmarkerlist' may be ignored.                                    */
++/*    - `edgelist' and `normlist' must both be initialized.                  */
++/*      `edgemarkerlist' may be ignored.                                     */
++/*    - Everything else may be ignored.                                      */
++/*                                                                           */
++/*  After a call to triangulate(), the valid fields of `out' and `vorout'    */
++/*  will depend, in an obvious way, on the choice of switches used.  Note    */
++/*  that when the `p' switch is used, the pointers `holelist' and            */
++/*  `regionlist' are copied from `in' to `out', but no new space is          */
++/*  allocated; be careful that you don't free() the same array twice.  On    */
++/*  the other hand, Triangle will never copy the `pointlist' pointer (or any */
++/*  others); new space is allocated for `out->pointlist', or if the `N'      */
++/*  switch is used, `out->pointlist' remains uninitialized.                  */
++/*                                                                           */
++/*  All of the meaningful `numberof' fields will be properly set; for        */
++/*  instance, `numberofedges' will represent the number of edges in the      */
++/*  triangulation whether or not the edges were written.  If segments are    */
++/*  not used, `numberofsegments' will indicate the number of boundary edges. */
++/*                                                                           */
++/*****************************************************************************/
++
++/* CLO: 3/21/99 - this could be done as a compile flag, but I always want
++this defined and I don't want to sprinkle extra stuff throughout the 
++Makefile system if I don't have to. */
++#define ANSI_DECLARATORS 1
++
++struct triangulateio {
++  REAL *pointlist;                                               /* In / out */
++  REAL *pointattributelist;                                      /* In / out */
++  int *pointmarkerlist;                                          /* In / out */
++  int numberofpoints;                                            /* In / out */
++  int numberofpointattributes;                                   /* In / out */
++
++  int *trianglelist;                                             /* In / out */
++  REAL *triangleattributelist;                                   /* In / out */
++  REAL *trianglearealist;                                         /* In only */
++  int *neighborlist;                                             /* Out only */
++  int numberoftriangles;                                         /* In / out */
++  int numberofcorners;                                           /* In / out */
++  int numberoftriangleattributes;                                /* In / out */
++
++  int *segmentlist;                                              /* In / out */
++  int *segmentmarkerlist;                                        /* In / out */
++  int numberofsegments;                                          /* In / out */
++
++  REAL *holelist;                        /* In / pointer to array copied out */
++  int numberofholes;                                      /* In / copied out */
++
++  REAL *regionlist;                      /* In / pointer to array copied out */
++  int numberofregions;                                    /* In / copied out */
++
++  int *edgelist;                                                 /* Out only */
++  int *edgemarkerlist;            /* Not used with Voronoi diagram; out only */
++  REAL *normlist;                /* Used only with Voronoi diagram; out only */
++  int numberofedges;                                             /* Out only */
++};
++
++#ifdef ANSI_DECLARATORS
++void triangulate(char *, struct triangulateio *, struct triangulateio *,
++                 struct triangulateio *);
++#else /* not ANSI_DECLARATORS */
++void triangulate();
++#endif /* not ANSI_DECLARATORS */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6beccdc81193d09f7b77e3ea06785323a5200350
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,279 @@@
++/*****************************************************************************/
++/*                                                                           */
++/*  (tricall.c)                                                              */
++/*                                                                           */
++/*  Example program that demonstrates how to call Triangle.                  */
++/*                                                                           */
++/*  Accompanies Triangle Version 1.3                                         */
++/*  July 19, 1996                                                            */
++/*                                                                           */
++/*  This file is placed in the public domain (but the file that it calls     */
++/*  is still copyrighted!) by                                                */
++/*  Jonathan Richard Shewchuk                                                */
++/*  School of Computer Science                                               */
++/*  Carnegie Mellon University                                               */
++/*  5000 Forbes Avenue                                                       */
++/*  Pittsburgh, Pennsylvania  15213-3891                                     */
++/*  jrs@cs.cmu.edu                                                           */
++/*                                                                           */
++/*****************************************************************************/
++
++/* If SINGLE is defined when triangle.o is compiled, it should also be       */
++/*   defined here.  If not, it should not be defined here.                   */
++
++/* #define SINGLE */
++
++#ifdef SINGLE
++#define REAL float
++#else /* not SINGLE */
++#define REAL double
++#endif /* not SINGLE */
++
++#include <stdio.h>
++#include "triangle.h"
++
++#ifndef _STDLIB_H_
++extern void *malloc();
++extern void free();
++#endif /* _STDLIB_H_ */
++
++/*****************************************************************************/
++/*                                                                           */
++/*  report()   Print the input or output.                                    */
++/*                                                                           */
++/*****************************************************************************/
++
++void report(io, markers, reporttriangles, reportneighbors, reportsegments,
++            reportedges, reportnorms)
++struct triangulateio *io;
++int markers;
++int reporttriangles;
++int reportneighbors;
++int reportsegments;
++int reportedges;
++int reportnorms;
++{
++  int i, j;
++
++  for (i = 0; i < io->numberofpoints; i++) {
++    printf("Point %4d:", i);
++    for (j = 0; j < 2; j++) {
++      printf("  %.6g", io->pointlist[i * 2 + j]);
++    }
++    if (io->numberofpointattributes > 0) {
++      printf("   attributes");
++    }
++    for (j = 0; j < io->numberofpointattributes; j++) {
++      printf("  %.6g",
++             io->pointattributelist[i * io->numberofpointattributes + j]);
++    }
++    if (markers) {
++      printf("   marker %d\n", io->pointmarkerlist[i]);
++    } else {
++      printf("\n");
++    }
++  }
++  printf("\n");
++
++  if (reporttriangles || reportneighbors) {
++    for (i = 0; i < io->numberoftriangles; i++) {
++      if (reporttriangles) {
++        printf("Triangle %4d points:", i);
++        for (j = 0; j < io->numberofcorners; j++) {
++          printf("  %4d", io->trianglelist[i * io->numberofcorners + j]);
++        }
++        if (io->numberoftriangleattributes > 0) {
++          printf("   attributes");
++        }
++        for (j = 0; j < io->numberoftriangleattributes; j++) {
++          printf("  %.6g", io->triangleattributelist[i *
++                                         io->numberoftriangleattributes + j]);
++        }
++        printf("\n");
++      }
++      if (reportneighbors) {
++        printf("Triangle %4d neighbors:", i);
++        for (j = 0; j < 3; j++) {
++          printf("  %4d", io->neighborlist[i * 3 + j]);
++        }
++        printf("\n");
++      }
++    }
++    printf("\n");
++  }
++
++  if (reportsegments) {
++    for (i = 0; i < io->numberofsegments; i++) {
++      printf("Segment %4d points:", i);
++      for (j = 0; j < 2; j++) {
++        printf("  %4d", io->segmentlist[i * 2 + j]);
++      }
++      if (markers) {
++        printf("   marker %d\n", io->segmentmarkerlist[i]);
++      } else {
++        printf("\n");
++      }
++    }
++    printf("\n");
++  }
++
++  if (reportedges) {
++    for (i = 0; i < io->numberofedges; i++) {
++      printf("Edge %4d points:", i);
++      for (j = 0; j < 2; j++) {
++        printf("  %4d", io->edgelist[i * 2 + j]);
++      }
++      if (reportnorms && (io->edgelist[i * 2 + 1] == -1)) {
++        for (j = 0; j < 2; j++) {
++          printf("  %.6g", io->normlist[i * 2 + j]);
++        }
++      }
++      if (markers) {
++        printf("   marker %d\n", io->edgemarkerlist[i]);
++      } else {
++        printf("\n");
++      }
++    }
++    printf("\n");
++  }
++}
++
++/*****************************************************************************/
++/*                                                                           */
++/*  main()   Create and refine a mesh.                                       */
++/*                                                                           */
++/*****************************************************************************/
++
++int main()
++{
++  struct triangulateio in, mid, out, vorout;
++
++  /* Define input points. */
++
++  in.numberofpoints = 4;
++  in.numberofpointattributes = 1;
++  in.pointlist = (REAL *) malloc(in.numberofpoints * 2 * sizeof(REAL));
++  in.pointlist[0] = 0.0;
++  in.pointlist[1] = 0.0;
++  in.pointlist[2] = 1.0;
++  in.pointlist[3] = 0.0;
++  in.pointlist[4] = 1.0;
++  in.pointlist[5] = 10.0;
++  in.pointlist[6] = 0.0;
++  in.pointlist[7] = 10.0;
++  in.pointattributelist = (REAL *) malloc(in.numberofpoints *
++                                          in.numberofpointattributes *
++                                          sizeof(REAL));
++  in.pointattributelist[0] = 0.0;
++  in.pointattributelist[1] = 1.0;
++  in.pointattributelist[2] = 11.0;
++  in.pointattributelist[3] = 10.0;
++  in.pointmarkerlist = (int *) malloc(in.numberofpoints * sizeof(int));
++  in.pointmarkerlist[0] = 0;
++  in.pointmarkerlist[1] = 2;
++  in.pointmarkerlist[2] = 0;
++  in.pointmarkerlist[3] = 0;
++
++  in.numberofsegments = 0;
++  in.numberofholes = 0;
++  in.numberofregions = 1;
++  in.regionlist = (REAL *) malloc(in.numberofregions * 4 * sizeof(REAL));
++  in.regionlist[0] = 0.5;
++  in.regionlist[1] = 5.0;
++  in.regionlist[2] = 7.0;            /* Regional attribute (for whole mesh). */
++  in.regionlist[3] = 0.1;          /* Area constraint that will not be used. */
++
++  printf("Input point set:\n\n");
++  report(&in, 1, 0, 0, 0, 0, 0);
++
++  /* Make necessary initializations so that Triangle can return a */
++  /*   triangulation in `mid' and a voronoi diagram in `vorout'.  */
++
++  mid.pointlist = (REAL *) NULL;            /* Not needed if -N switch used. */
++  /* Not needed if -N switch used or number of point attributes is zero: */
++  mid.pointattributelist = (REAL *) NULL;
++  mid.pointmarkerlist = (int *) NULL; /* Not needed if -N or -B switch used. */
++  mid.trianglelist = (int *) NULL;          /* Not needed if -E switch used. */
++  /* Not needed if -E switch used or number of triangle attributes is zero: */
++  mid.triangleattributelist = (REAL *) NULL;
++  mid.neighborlist = (int *) NULL;         /* Needed only if -n switch used. */
++  /* Needed only if segments are output (-p or -c) and -P not used: */
++  mid.segmentlist = (int *) NULL;
++  /* Needed only if segments are output (-p or -c) and -P and -B not used: */
++  mid.segmentmarkerlist = (int *) NULL;
++  mid.edgelist = (int *) NULL;             /* Needed only if -e switch used. */
++  mid.edgemarkerlist = (int *) NULL;   /* Needed if -e used and -B not used. */
++
++  vorout.pointlist = (REAL *) NULL;        /* Needed only if -v switch used. */
++  /* Needed only if -v switch used and number of attributes is not zero: */
++  vorout.pointattributelist = (REAL *) NULL;
++  vorout.edgelist = (int *) NULL;          /* Needed only if -v switch used. */
++  vorout.normlist = (REAL *) NULL;         /* Needed only if -v switch used. */
++
++  /* Triangulate the points.  Switches are chosen to read and write a  */
++  /*   PSLG (p), preserve the convex hull (c), number everything from  */
++  /*   zero (z), assign a regional attribute to each element (A), and  */
++  /*   produce an edge list (e), a Voronoi diagram (v), and a triangle */
++  /*   neighbor list (n).                                              */
++
++  triangulate("pczAevn", &in, &mid, &vorout);
++
++  printf("Initial triangulation:\n\n");
++  report(&mid, 1, 1, 1, 1, 1, 0);
++  printf("Initial Voronoi diagram:\n\n");
++  report(&vorout, 0, 0, 0, 0, 1, 1);
++
++  /* Attach area constraints to the triangles in preparation for */
++  /*   refining the triangulation.                               */
++
++  /* Needed only if -r and -a switches used: */
++  mid.trianglearealist = (REAL *) malloc(mid.numberoftriangles * sizeof(REAL));
++  mid.trianglearealist[0] = 3.0;
++  mid.trianglearealist[1] = 1.0;
++
++  /* Make necessary initializations so that Triangle can return a */
++  /*   triangulation in `out'.                                    */
++
++  out.pointlist = (REAL *) NULL;            /* Not needed if -N switch used. */
++  /* Not needed if -N switch used or number of attributes is zero: */
++  out.pointattributelist = (REAL *) NULL;
++  out.trianglelist = (int *) NULL;          /* Not needed if -E switch used. */
++  /* Not needed if -E switch used or number of triangle attributes is zero: */
++  out.triangleattributelist = (REAL *) NULL;
++
++  /* Refine the triangulation according to the attached */
++  /*   triangle area constraints.                       */
++
++  triangulate("prazBP", &mid, &out, (struct triangulateio *) NULL);
++
++  printf("Refined triangulation:\n\n");
++  report(&out, 0, 1, 0, 0, 0, 0);
++
++  /* Free all allocated arrays, including those allocated by Triangle. */
++
++  free(in.pointlist);
++  free(in.pointattributelist);
++  free(in.pointmarkerlist);
++  free(in.regionlist);
++  free(mid.pointlist);
++  free(mid.pointattributelist);
++  free(mid.pointmarkerlist);
++  free(mid.trianglelist);
++  free(mid.triangleattributelist);
++  free(mid.trianglearealist);
++  free(mid.neighborlist);
++  free(mid.segmentlist);
++  free(mid.segmentmarkerlist);
++  free(mid.edgelist);
++  free(mid.edgemarkerlist);
++  free(vorout.pointlist);
++  free(vorout.pointattributelist);
++  free(vorout.edgelist);
++  free(vorout.normlist);
++  free(out.pointlist);
++  free(out.pointattributelist);
++  free(out.trianglelist);
++  free(out.triangleattributelist);
++
++  return 0;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..34c320f91e6e520ad424e36017f69faac973a838
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,14 @@@
++noinst_LIBRARIES = libTriangulate.a
++
++libTriangulate_a_SOURCES = \
++      triangle.cxx triangle.hxx \
++      trieles.cxx trieles.hxx \
++      trinodes.cxx trinodes.hxx \
++      tripoly.cxx tripoly.hxx \
++      trisegs.cxx trisegs.hxx
++
++INCLUDES += \
++      -I$(top_builddir) \
++      -I$(top_builddir)/Lib \
++      -I$(top_builddir)/Tools/Lib \
++      -I$(top_builddir)/Tools/Construct
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..38b8bf1ac3f37e309c2bf15e479c36c0db860bb8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,476 @@@
++// triangle.cxx -- "Triangle" interface class
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include "triangle.hxx"
++#include "tripoly.hxx"
++
++// Constructor
++FGTriangle::FGTriangle( void ) {
++}
++
++
++// Destructor
++FGTriangle::~FGTriangle( void ) {
++}
++
++
++// populate this class based on the specified gpc_polys list
++int 
++FGTriangle::build( const point_list& corner_list,
++                 const point_list& fit_list, 
++                 const FGgpcPolyList& gpc_polys )
++{
++    FGTriPoly poly;
++    int index;
++
++    in_nodes.clear();
++    trisegs.clear();
++
++    // Point3D junkp;
++    // int junkc = 0;
++    // char junkn[256];
++    // FILE *junkfp;
++
++    // traverse the dem corner and fit lists and gpc_polys building a
++    // unified node list and converting the polygons so that they
++    // reference the node list by index (starting at zero) rather than
++    // listing the points explicitely
++
++    // first the corners since these are important
++    const_point_list_iterator f_current, f_last;
++    f_current = corner_list.begin();
++    f_last = corner_list.end();
++    for ( ; f_current != f_last; ++f_current ) {
++      index = in_nodes.unique_add( *f_current );
++    }
++
++    // next process the polygons
++    gpc_polygon *gpc_poly;
++    const_gpcpoly_iterator current, last;
++
++    // process polygons in priority order
++    cout << "prepairing node list and polygons" << endl;
++
++    for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
++      polylist[i].clear();
++
++      // cout << "area type = " << i << endl;
++      current = gpc_polys.polys[i].begin();
++      last = gpc_polys.polys[i].end();
++      for ( ; current != last; ++current ) {
++          gpc_poly = *current;
++          cout << "processing a polygon, contours = " 
++               << gpc_poly->num_contours << endl;
++
++          if (gpc_poly->num_contours <= 0 ) {
++              cout << "FATAL ERROR! no contours in this polygon" << endl;
++              exit(-1);
++          }
++
++          if (gpc_poly->num_contours > 1 ) {
++              cout << "FATAL ERROR! no multi-contour support" << endl;
++              sleep(2);
++              // exit(-1);
++          }
++
++          for ( int j = 0; j < gpc_poly->num_contours; j++ ) {
++              cout << " processing contour, nodes = " 
++                   << gpc_poly->contour[j].num_vertices << endl;
++
++              poly.erase();
++
++              // sprintf(junkn, "g.%d", junkc++);
++              // junkfp = fopen(junkn, "w");
++
++              for ( int k = 0; k < gpc_poly->contour[j].num_vertices; k++ ) {
++                  Point3D p( gpc_poly->contour[j].vertex[k].x,
++                             gpc_poly->contour[j].vertex[k].y,
++                             0 );
++                  index = in_nodes.unique_add( p );
++                  // junkp = in_nodes.get_node( index );
++                  // fprintf(junkfp, "%.4f %.4f\n", junkp.x(), junkp.y());
++                  poly.add_node(index);
++                  // cout << index << endl;
++              }
++              // fprintf(junkfp, "%.4f %.4f\n", 
++              //    gpc_poly->contour[j].vertex[0].x, 
++              //    gpc_poly->contour[j].vertex[0].y);
++              // fclose(junkfp);
++
++              poly.calc_point_inside( in_nodes );
++
++              polylist[i].push_back(poly);
++          }
++      }
++    }
++
++    // last, do the rest of the height nodes
++    f_current = fit_list.begin();
++    f_last = fit_list.end();
++    for ( ; f_current != f_last; ++f_current ) {
++      index = in_nodes.course_add( *f_current );
++    }
++
++    for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
++      if ( polylist[i].size() ) {
++          cout << get_area_name((AreaType)i) << " = " 
++               << polylist[i].size() << endl;
++      }
++    }
++
++    // traverse the polygon lists and build the segment (edge) list
++    // that is used by the "Triangle" lib.
++
++    int i1, i2;
++    point_list node_list = in_nodes.get_node_list();
++    for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
++      // cout << "area type = " << i << endl;
++      tripoly_list_iterator tp_current, tp_last;
++      tp_current = polylist[i].begin();
++      tp_last = polylist[i].end();
++
++      // process each polygon in list
++      for ( ; tp_current != tp_last; ++tp_current ) {
++          poly = *tp_current;
++
++          for ( int j = 0; j < (int)(poly.size()) - 1; ++j ) {
++              i1 = poly.get_pt_index( j );
++              i2 = poly.get_pt_index( j + 1 );
++              // calc_line_params(i1, i2, &m, &b);
++              trisegs.unique_divide_and_add( node_list, FGTriSeg(i1, i2) );
++          }
++          i1 = poly.get_pt_index( 0 );
++          i2 = poly.get_pt_index( poly.size() - 1 );
++          // calc_line_params(i1, i2, &m, &b);
++          trisegs.unique_divide_and_add( node_list, FGTriSeg(i1, i2) );
++      }
++    }
++
++    return 0;
++}
++
++
++static void write_out_data(struct triangulateio *out) {
++    FILE *node = fopen("tile.node", "w");
++    fprintf(node, "%d 2 %d 0\n", 
++          out->numberofpoints, out->numberofpointattributes);
++    for (int i = 0; i < out->numberofpoints; i++) {
++      fprintf(node, "%d %.6f %.6f %.2f\n", 
++              i, out->pointlist[2*i], out->pointlist[2*i + 1], 0.0);
++    }
++    fclose(node);
++
++    FILE *ele = fopen("tile.ele", "w");
++    fprintf(ele, "%d 3 0\n", out->numberoftriangles);
++    for (int i = 0; i < out->numberoftriangles; i++) {
++        fprintf(ele, "%d ", i);
++        for (int j = 0; j < out->numberofcorners; j++) {
++          fprintf(ele, "%d ", out->trianglelist[i * out->numberofcorners + j]);
++        }
++        for (int j = 0; j < out->numberoftriangleattributes; j++) {
++          fprintf(ele, "%.6f ", 
++                  out->triangleattributelist[i 
++                                            * out->numberoftriangleattributes
++                                            + j]
++                  );
++        }
++      fprintf(ele, "\n");
++    }
++    fclose(ele);
++
++    FILE *fp = fopen("tile.poly", "w");
++    fprintf(fp, "0 2 1 0\n");
++    fprintf(fp, "%d 0\n", out->numberofsegments);
++    for (int i = 0; i < out->numberofsegments; ++i) {
++      fprintf(fp, "%d %d %d\n", 
++              i, out->segmentlist[2*i], out->segmentlist[2*i + 1]);
++    }
++    fprintf(fp, "%d\n", out->numberofholes);
++    for (int i = 0; i < out->numberofholes; i++) {
++      fprintf(fp, "%d %.6f %.6f\n", 
++              i, out->holelist[2*i], out->holelist[2*i + 1]);
++    }
++    fprintf(fp, "%d\n", out->numberofregions);
++    for (int i = 0; i < out->numberofregions; i++) {
++      fprintf(fp, "%d %.6f %.6f %.6f\n", 
++              i, out->regionlist[4*i], out->regionlist[4*i + 1],
++              out->regionlist[4*i + 2]);
++    }
++    fclose(fp);
++}
++
++
++// triangulate each of the polygon areas
++int FGTriangle::run_triangulate() {
++    FGTriPoly poly;
++    Point3D p;
++    struct triangulateio in, out, vorout;
++    int counter;
++
++    // point list
++    point_list node_list = in_nodes.get_node_list();
++    in.numberofpoints = node_list.size();
++    in.pointlist = (REAL *) malloc(in.numberofpoints * 2 * sizeof(REAL));
++
++    point_list_iterator tn_current, tn_last;
++    tn_current = node_list.begin();
++    tn_last = node_list.end();
++    counter = 0;
++    for ( ; tn_current != tn_last; ++tn_current ) {
++      in.pointlist[counter++] = tn_current->x();
++      in.pointlist[counter++] = tn_current->y();
++    }
++
++    in.numberofpointattributes = 1;
++    in.pointattributelist = (REAL *) malloc(in.numberofpoints *
++                                          in.numberofpointattributes *
++                                          sizeof(REAL));
++    for ( int i = 0; i < in.numberofpoints * in.numberofpointattributes; i++) {
++      in.pointattributelist[i] = 0.0;
++    }
++
++    in.pointmarkerlist = (int *) malloc(in.numberofpoints * sizeof(int));
++    for ( int i = 0; i < in.numberofpoints; i++) {
++      in.pointmarkerlist[i] = 0;
++    }
++
++    // triangle list
++    in.numberoftriangles = 0;
++
++    // segment list
++    triseg_list seg_list = trisegs.get_seg_list();
++    in.numberofsegments = seg_list.size();
++    in.segmentlist = (int *) malloc(in.numberofsegments * 2 * sizeof(int));
++    in.segmentmarkerlist = (int *) NULL;
++
++    triseg_list_iterator s_current, s_last;
++    s_current = seg_list.begin();
++    s_last = seg_list.end();
++    counter = 0;
++    for ( ; s_current != s_last; ++s_current ) {
++      in.segmentlist[counter++] = s_current->get_n1();
++      in.segmentlist[counter++] = s_current->get_n2();
++    }
++
++    // hole list (make holes for airport ignore areas)
++    in.numberofholes = polylist[(int)AirportIgnoreArea].size();
++    in.holelist = (REAL *) malloc(in.numberofholes * 2 * sizeof(REAL));
++
++    tripoly_list_iterator h_current, h_last;
++    h_current = polylist[(int)AirportIgnoreArea].begin();
++    h_last = polylist[(int)AirportIgnoreArea].end();
++    counter = 0;
++    for ( ; h_current != h_last; ++h_current ) {
++      poly = *h_current;
++      p = poly.get_point_inside();
++      in.holelist[counter++] = p.x();
++      in.holelist[counter++] = p.y();
++    }
++
++    // region list
++    in.numberofregions = 0;
++    for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
++      in.numberofregions += polylist[i].size();
++    }
++
++    in.regionlist = (REAL *) malloc(in.numberofregions * 4 * sizeof(REAL));
++    counter = 0;
++    for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
++      tripoly_list_iterator h_current, h_last;
++      h_current = polylist[(int)i].begin();
++      h_last = polylist[(int)i].end();
++      for ( ; h_current != h_last; ++h_current ) {
++          poly = *h_current;
++          p = poly.get_point_inside();
++          in.regionlist[counter++] = p.x();  // x coord
++          in.regionlist[counter++] = p.y();  // y coord
++          in.regionlist[counter++] = i;      // region attribute
++          in.regionlist[counter++] = -1.0;   // area constraint (unused)
++      }
++    }
++
++    // prep the output structures
++    out.pointlist = (REAL *) NULL;        // Not needed if -N switch used.
++    // Not needed if -N switch used or number of point attributes is zero:
++    out.pointattributelist = (REAL *) NULL;
++    out.pointmarkerlist = (int *) NULL;   // Not needed if -N or -B switch used.
++    out.trianglelist = (int *) NULL;      // Not needed if -E switch used.
++    // Not needed if -E switch used or number of triangle attributes is zero:
++    out.triangleattributelist = (REAL *) NULL;
++    out.neighborlist = (int *) NULL;      // Needed only if -n switch used.
++    // Needed only if segments are output (-p or -c) and -P not used:
++    out.segmentlist = (int *) NULL;
++    // Needed only if segments are output (-p or -c) and -P and -B not used:
++    out.segmentmarkerlist = (int *) NULL;
++    out.edgelist = (int *) NULL;          // Needed only if -e switch used.
++    out.edgemarkerlist = (int *) NULL;    // Needed if -e used and -B not used.
++  
++    vorout.pointlist = (REAL *) NULL;     // Needed only if -v switch used.
++    // Needed only if -v switch used and number of attributes is not zero:
++    vorout.pointattributelist = (REAL *) NULL;
++    vorout.edgelist = (int *) NULL;       // Needed only if -v switch used.
++    vorout.normlist = (REAL *) NULL;      // Needed only if -v switch used.
++    
++    // TEMPORARY
++    // write_out_data(&in);
++
++    // Triangulate the points.  Switches are chosen to read and write
++    // a PSLG (p), preserve the convex hull (c), number everything
++    // from zero (z), assign a regional attribute to each element (A),
++    // and produce an edge list (e), and a triangle neighbor list (n).
++
++    string tri_options = "pczq10Aen";
++    // string tri_options = "pzAen";
++    // string tri_options = "pczq15S400Aen";
++    cout << "Triangulation with options = " << tri_options << endl;
++
++    triangulate(tri_options.c_str(), &in, &out, &vorout);
++
++    // TEMPORARY
++    write_out_data(&out);
++
++    // now copy the results back into the corresponding FGTriangle
++    // structures
++
++    // nodes
++    out_nodes.clear();
++    for ( int i = 0; i < out.numberofpoints; i++ ) {
++      Point3D p( out.pointlist[2*i], out.pointlist[2*i + 1], 0.0 );
++      // cout << "point = " << p << endl;
++      out_nodes.simple_add( p );
++    }
++
++    // triangles
++    elelist.clear();
++    int n1, n2, n3;
++    double attribute;
++    for ( int i = 0; i < out.numberoftriangles; i++ ) {
++      n1 = out.trianglelist[i * 3];
++      n2 = out.trianglelist[i * 3 + 1];
++      n3 = out.trianglelist[i * 3 + 2];
++      if ( out.numberoftriangleattributes > 0 ) {
++          attribute = out.triangleattributelist[i];
++      } else {
++          attribute = 0.0;
++      }
++      // cout << "triangle = " << n1 << " " << n2 << " " << n3 << endl;
++
++      elelist.push_back( FGTriEle( n1, n2, n3, attribute ) );
++    }
++
++    // free mem allocated to the "Triangle" structures
++    free(in.pointlist);
++    free(in.pointattributelist);
++    free(in.pointmarkerlist);
++    free(in.regionlist);
++    free(out.pointlist);
++    free(out.pointattributelist);
++    free(out.pointmarkerlist);
++    free(out.trianglelist);
++    free(out.triangleattributelist);
++    // free(out.trianglearealist);
++    free(out.neighborlist);
++    free(out.segmentlist);
++    free(out.segmentmarkerlist);
++    free(out.edgelist);
++    free(out.edgemarkerlist);
++    free(vorout.pointlist);
++    free(vorout.pointattributelist);
++    free(vorout.edgelist);
++    free(vorout.normlist);
++
++    return 0;
++}
++
++
++// $Log$
++// Revision 1.16  1999/04/05 02:17:11  curt
++// Dynamically update "error" until the resulting tile data scales within
++// a lower and upper bounds.
++//
++// Revision 1.15  1999/04/03 05:22:58  curt
++// Found a bug in dividing and adding unique verticle segments which could
++// cause the triangulator to end up in an infinite loop.  Basically the code
++// was correct, but the verticle line test was a bit to selective.
++//
++// Revision 1.14  1999/03/31 23:47:09  curt
++// Debugging output tweaks.
++//
++// Revision 1.13  1999/03/29 13:11:07  curt
++// Shuffled stl type names a bit.
++// Began adding support for tri-fanning (or maybe other arrangments too.)
++//
++// Revision 1.12  1999/03/27 05:30:12  curt
++// Handle corner nodes separately from the rest of the fitted nodes.
++// Add fitted nodes in after corners and polygon nodes since the fitted nodes
++//   are less important.  Subsequent nodes will "snap" to previous nodes if
++//   they are "close enough."
++// Need to manually divide segments to prevent "T" intersetions which can
++//   confound the triangulator.  Hey, I got to use a recursive method!
++// Pass along correct triangle attributes to output file generator.
++// Do fine grained node snapping for corners and polygons, but course grain
++//   node snapping for fitted terrain nodes.
++//
++// Revision 1.11  1999/03/23 22:02:51  curt
++// Refinements in naming and organization.
++//
++// Revision 1.10  1999/03/22 23:49:02  curt
++// Modifications to facilitate conversion to output format.
++//
++// Revision 1.9  1999/03/21 15:48:02  curt
++// Removed Dem2node from the Tools fold.
++// Tweaked the triangulator options to add quality mesh refinement.
++//
++// Revision 1.8  1999/03/21 14:02:06  curt
++// Added a mechanism to dump out the triangle structures for viewing.
++// Fixed a couple bugs in first pass at triangulation.
++// - needed to explicitely initialize the polygon accumulator in triangle.cxx
++//   before each polygon rather than depending on the default behavior.
++// - Fixed a problem with region attribute propagation where I wasn't generating
++//   the hole points correctly.
++//
++// Revision 1.7  1999/03/20 20:32:55  curt
++// First mostly successful tile triangulation works.  There's plenty of tweaking
++// to do, but we are marching in the right direction.
++//
++// Revision 1.6  1999/03/20 13:22:11  curt
++// Added trisegs.[ch]xx tripoly.[ch]xx.
++//
++// Revision 1.5  1999/03/20 02:21:52  curt
++// Continue shaping the code towards triangulation bliss.  Added code to
++// calculate some point guaranteed to be inside a polygon.
++//
++// Revision 1.4  1999/03/19 22:29:04  curt
++// Working on preparationsn for triangulation.
++//
++// Revision 1.3  1999/03/19 00:27:10  curt
++// Continued work on triangulation preparation.
++//
++// Revision 1.2  1999/03/18 04:31:11  curt
++// Let's not pass copies of huge structures on the stack ... ye might see a
++// segfault ... :-)
++//
++// Revision 1.1  1999/03/17 23:51:59  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..676f5056ce16f3c7cb299d91a375c94e3dbe69d5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,141 @@@
++// triangle.hxx -- "Triangle" interface class
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef _TRIANGLE_HXX
++#define _TRIANGLE_HXX
++
++
++#ifndef __cplusplus                                                          
++# error This library requires C++
++#endif                                   
++
++
++#include <Include/compiler.h>
++
++#include <Array/array.hxx>
++#include <Clipper/clipper.hxx>
++#include <Math/point3d.hxx>
++#include <Polygon/names.hxx>
++
++#define REAL double
++extern "C" {
++#include <Triangle/triangle.h>
++}
++
++#include "trieles.hxx"
++#include "trinodes.hxx"
++#include "tripoly.hxx"
++#include "trisegs.hxx"
++
++
++class FGTriangle {
++
++private:
++
++    // list of nodes
++    FGTriNodes in_nodes;
++    FGTriNodes out_nodes;
++
++    // list of segments
++    FGTriSegments trisegs;
++
++    // polygon list
++    tripoly_list polylist[FG_MAX_AREA_TYPES];
++    
++    // triangle list
++    triele_list elelist;
++
++public:
++
++    // Constructor and destructor
++    FGTriangle( void );
++    ~FGTriangle( void );
++
++    // add nodes from the dem fit
++    int add_nodes();
++
++    // populate this class based on the specified gpc_polys list
++    int build( const point_list& corner_list, 
++             const point_list& fit_list,
++             const FGgpcPolyList& gpc_polys );
++
++    // front end triangulator for polygon list
++    int run_triangulate();
++
++    inline FGTriNodes get_out_nodes() const { return out_nodes; }
++    inline size_t get_out_nodes_size() const { return out_nodes.size(); }
++    inline triele_list get_elelist() const { return elelist; }
++};
++
++
++#endif // _TRIANGLE_HXX
++
++
++// $Log$
++// Revision 1.11  1999/04/05 02:17:12  curt
++// Dynamically update "error" until the resulting tile data scales within
++// a lower and upper bounds.
++//
++// Revision 1.10  1999/03/29 13:11:08  curt
++// Shuffled stl type names a bit.
++// Began adding support for tri-fanning (or maybe other arrangments too.)
++//
++// Revision 1.9  1999/03/27 05:30:13  curt
++// Handle corner nodes separately from the rest of the fitted nodes.
++// Add fitted nodes in after corners and polygon nodes since the fitted nodes
++//   are less important.  Subsequent nodes will "snap" to previous nodes if
++//   they are "close enough."
++// Need to manually divide segments to prevent "T" intersetions which can
++//   confound the triangulator.  Hey, I got to use a recursive method!
++// Pass along correct triangle attributes to output file generator.
++// Do fine grained node snapping for corners and polygons, but course grain
++//   node snapping for fitted terrain nodes.
++//
++// Revision 1.8  1999/03/23 22:02:52  curt
++// Refinements in naming and organization.
++//
++// Revision 1.7  1999/03/22 23:49:03  curt
++// Modifications to facilitate conversion to output format.
++//
++// Revision 1.6  1999/03/20 20:32:56  curt
++// First mostly successful tile triangulation works.  There's plenty of tweaking
++// to do, but we are marching in the right direction.
++//
++// Revision 1.5  1999/03/20 02:21:53  curt
++// Continue shaping the code towards triangulation bliss.  Added code to
++// calculate some point guaranteed to be inside a polygon.
++//
++// Revision 1.4  1999/03/19 22:29:05  curt
++// Working on preparationsn for triangulation.
++//
++// Revision 1.3  1999/03/19 00:27:11  curt
++// Continued work on triangulation preparation.
++//
++// Revision 1.2  1999/03/18 04:31:12  curt
++// Let's not pass copies of huge structures on the stack ... ye might see a
++// segfault ... :-)
++//
++// Revision 1.1  1999/03/17 23:51:59  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..406a19a9142450ac4abfaa4c120b85e92f867bb0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,31 @@@
++// trieles.cxx -- "Triangle" element management class
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include "trieles.hxx"
++
++
++// $Log$
++// Revision 1.1  1999/03/22 23:58:57  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2d22c7db5ee62b8baab7bed0a9cf773fe9e6c501
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,94 @@@
++// trieles.hxx -- "Triangle" element management class
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef _TRIELES_HXX
++#define _TRIELES_HXX
++
++
++#ifndef __cplusplus                                                          
++# error This library requires C++
++#endif                                   
++
++
++#include <Include/compiler.h>
++
++#include <vector>
++
++FG_USING_STD(vector);
++
++
++// a segment is two integer pointers into the node list
++class FGTriEle {
++    int n1, n2, n3;
++
++    double attribute;
++
++public:
++
++    // Constructor and destructor
++    inline FGTriEle( void ) { };
++    inline FGTriEle( int i1, int i2, int i3, double a ) {
++      n1 = i1; n2 = i2; n3 = i3; attribute = a;
++    }
++
++    inline ~FGTriEle( void ) { };
++
++    inline int get_n1() const { return n1; }
++    inline void set_n1( int i ) { n1 = i; }
++    inline int get_n2() const { return n2; }
++    inline void set_n2( int i ) { n2 = i; }
++    inline int get_n3() const { return n3; }
++    inline void set_n3( int i ) { n3 = i; }
++
++    inline double get_attribute() const { return attribute; }
++    inline void set_attribute( double a ) { attribute = a; }
++};
++
++
++typedef vector < FGTriEle > triele_list;
++typedef triele_list::iterator triele_list_iterator;
++typedef triele_list::const_iterator const_triele_list_iterator;
++
++
++#endif // _TRIELES_HXX
++
++
++// $Log$
++// Revision 1.3  1999/03/27 05:30:14  curt
++// Handle corner nodes separately from the rest of the fitted nodes.
++// Add fitted nodes in after corners and polygon nodes since the fitted nodes
++//   are less important.  Subsequent nodes will "snap" to previous nodes if
++//   they are "close enough."
++// Need to manually divide segments to prevent "T" intersetions which can
++//   confound the triangulator.  Hey, I got to use a recursive method!
++// Pass along correct triangle attributes to output file generator.
++// Do fine grained node snapping for corners and polygons, but course grain
++//   node snapping for fitted terrain nodes.
++//
++// Revision 1.2  1999/03/23 22:02:53  curt
++// Refinements in naming and organization.
++//
++// Revision 1.1  1999/03/22 23:58:57  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..50e7df7ee8febac106936d303bf607f1dd5c2da5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,130 @@@
++// trinodes.cxx -- "Triangle" nodes management class
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include "trinodes.hxx"
++
++
++// Constructor 
++FGTriNodes::FGTriNodes( void ) {
++}
++
++
++// Destructor
++FGTriNodes::~FGTriNodes( void ) {
++}
++
++
++// Add a point to the point list if it doesn't already exist.  Returns
++// the index (starting at zero) of the point in the list.
++int FGTriNodes::unique_add( const Point3D& p ) {
++    point_list_iterator current, last;
++    int counter = 0;
++
++    // cout << p.x() << "," << p.y() << endl;
++
++    // see if point already exists
++    current = node_list.begin();
++    last = node_list.end();
++    for ( ; current != last; ++current ) {
++      if ( close_enough(p, *current) ) {
++          // cout << "found an existing match!" << endl;
++          return counter;
++      }
++      
++      ++counter;
++    }
++
++    // add to list
++    node_list.push_back( p );
++
++    return counter;
++}
++
++
++// Add the point with no uniqueness checking
++int FGTriNodes::simple_add( const Point3D& p ) {
++    node_list.push_back( p );
++
++    return node_list.size() - 1;
++}
++
++
++// Add a point to the point list if it doesn't already exist.  Returns
++// the index (starting at zero) of the point in the list.  Use a
++// course proximity check
++int FGTriNodes::course_add( const Point3D& p ) {
++    point_list_iterator current, last;
++    int counter = 0;
++
++    // cout << p.x() << "," << p.y() << endl;
++
++    // see if point already exists
++    current = node_list.begin();
++    last = node_list.end();
++    for ( ; current != last; ++current ) {
++      if ( course_close_enough(p, *current) ) {
++          // cout << "found an existing match!" << endl;
++          return counter;
++      }
++      
++      ++counter;
++    }
++
++    // add to list
++    node_list.push_back( p );
++
++    return counter;
++}
++
++
++// $Log$
++// Revision 1.6  1999/03/27 05:30:15  curt
++// Handle corner nodes separately from the rest of the fitted nodes.
++// Add fitted nodes in after corners and polygon nodes since the fitted nodes
++//   are less important.  Subsequent nodes will "snap" to previous nodes if
++//   they are "close enough."
++// Need to manually divide segments to prevent "T" intersetions which can
++//   confound the triangulator.  Hey, I got to use a recursive method!
++// Pass along correct triangle attributes to output file generator.
++// Do fine grained node snapping for corners and polygons, but course grain
++//   node snapping for fitted terrain nodes.
++//
++// Revision 1.5  1999/03/23 22:02:54  curt
++// Refinements in naming and organization.
++//
++// Revision 1.4  1999/03/22 23:49:04  curt
++// Modifications to facilitate conversion to output format.
++//
++// Revision 1.3  1999/03/20 02:21:54  curt
++// Continue shaping the code towards triangulation bliss.  Added code to
++// calculate some point guaranteed to be inside a polygon.
++//
++// Revision 1.2  1999/03/19 00:27:12  curt
++// Continued work on triangulation preparation.
++//
++// Revision 1.1  1999/03/17 23:52:00  curt
++// Initial revision.
++//
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f7c5fdd5584e379653a97b3a0af3ea813b4a30d9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,155 @@@
++// trinodes.hxx -- "Triangle" nodes management class
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef _TRINODES_HXX
++#define _TRINODES_HXX
++
++
++#ifndef __cplusplus                                                          
++# error This library requires C++
++#endif                                   
++
++
++#include <Include/compiler.h>
++
++#include <Math/point3d.hxx>
++
++#include <Main/construct_types.hxx>
++
++
++#define FG_PROXIMITY_EPSILON 0.000001
++#define FG_COURSE_EPSILON 0.0003
++
++
++class FGTriNodes {
++
++private:
++
++    point_list node_list;
++
++    // return true of the two points are "close enough" as defined by
++    // FG_PROXIMITY_EPSILON
++    bool close_enough( const Point3D& p, const Point3D& p );
++
++    // return true of the two points are "close enough" as defined by
++    // FG_COURSE_EPSILON
++    bool course_close_enough( const Point3D& p1, const Point3D& p2 );
++
++public:
++
++    // Constructor and destructor
++    FGTriNodes( void );
++    ~FGTriNodes( void );
++
++    // delete all the data out of node_list
++    inline void clear() { node_list.clear(); }
++
++    // Add a point to the point list if it doesn't already exist.
++    // Returns the index (starting at zero) of the point in the list.
++    int unique_add( const Point3D& p );
++
++    // Add the point with no uniqueness checking
++    int simple_add( const Point3D& p );
++
++    // Add a point to the point list if it doesn't already exist.
++    // Returns the index (starting at zero) of the point in the list.
++    // Use a course proximity check
++    int course_add( const Point3D& p );
++
++    // return the master node list
++    inline point_list get_node_list() const { return node_list; }
++
++    // return the ith point
++    inline Point3D get_node( int i ) const { return node_list[i]; }
++
++    // return the size of the node list
++    inline size_t size() const { return node_list.size(); }
++};
++
++
++// return true of the two points are "close enough" as defined by
++// FG_PROXIMITY_EPSILON
++inline bool FGTriNodes::close_enough( const Point3D& p1, const Point3D& p2 ) {
++    if ( ( fabs(p1.x() - p2.x()) < FG_PROXIMITY_EPSILON ) &&
++       ( fabs(p1.y() - p2.y()) < FG_PROXIMITY_EPSILON ) ) {
++      return true;
++    } else {
++      return false;
++    }
++}
++
++
++// return true of the two points are "close enough" as defined by
++// FG_COURSE_EPSILON
++inline bool FGTriNodes::course_close_enough( const Point3D& p1, 
++                                           const Point3D& p2 )
++{
++    if ( ( fabs(p1.x() - p2.x()) < FG_COURSE_EPSILON ) &&
++       ( fabs(p1.y() - p2.y()) < FG_COURSE_EPSILON ) ) {
++      return true;
++    } else {
++      return false;
++    }
++}
++
++
++#endif // _TRINODES_HXX
++
++
++// $Log$
++// Revision 1.8  1999/04/05 02:17:13  curt
++// Dynamically update "error" until the resulting tile data scales within
++// a lower and upper bounds.
++//
++// Revision 1.7  1999/03/29 13:11:10  curt
++// Shuffled stl type names a bit.
++// Began adding support for tri-fanning (or maybe other arrangments too.)
++//
++// Revision 1.6  1999/03/27 05:30:16  curt
++// Handle corner nodes separately from the rest of the fitted nodes.
++// Add fitted nodes in after corners and polygon nodes since the fitted nodes
++//   are less important.  Subsequent nodes will "snap" to previous nodes if
++//   they are "close enough."
++// Need to manually divide segments to prevent "T" intersetions which can
++//   confound the triangulator.  Hey, I got to use a recursive method!
++// Pass along correct triangle attributes to output file generator.
++// Do fine grained node snapping for corners and polygons, but course grain
++//   node snapping for fitted terrain nodes.
++//
++// Revision 1.5  1999/03/23 22:02:55  curt
++// Refinements in naming and organization.
++//
++// Revision 1.4  1999/03/22 23:49:05  curt
++// Modifications to facilitate conversion to output format.
++//
++// Revision 1.3  1999/03/20 02:21:55  curt
++// Continue shaping the code towards triangulation bliss.  Added code to
++// calculate some point guaranteed to be inside a polygon.
++//
++// Revision 1.2  1999/03/19 22:29:06  curt
++// Working on preparationsn for triangulation.
++//
++// Revision 1.1  1999/03/17 23:52:00  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d01bb8b40f24c5e17064da787558ac3a67af4493
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,189 @@@
++// tripoly.cxx -- "Triangle" polygon management class
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include <Include/fg_constants.h>
++#include <Math/point3d.hxx>
++
++#include "tripoly.hxx"
++
++
++// Constructor 
++FGTriPoly::FGTriPoly( void ) {
++}
++
++
++// Destructor
++FGTriPoly::~FGTriPoly( void ) {
++}
++
++
++// Given a line segment specified by two endpoints p1 and p2, return
++// the slope of the line.
++static double slope( const Point3D& p0, const Point3D& p1 ) {
++    if ( fabs(p0.x() - p1.x()) > FG_EPSILON ) {
++      return (p0.y() - p1.y()) / (p0.x() - p1.x());
++    } else {
++      return 1.0e+999; // really big number
++    }
++}
++
++
++// Given a line segment specified by two endpoints p1 and p2, return
++// the y value of a point on the line that intersects with the
++// verticle line through x.  Return true if an intersection is found,
++// false otherwise.
++static bool intersects( const Point3D& p0, const Point3D& p1, double x, 
++                       Point3D *result ) {
++    // equation of a line through (x0,y0) and (x1,y1):
++    // 
++    //     y = y1 + (x - x1) * (y0 - y1) / (x0 - x1)
++
++    double y;
++
++    if ( fabs(p0.x() - p1.x()) > FG_EPSILON ) {
++      y = p1.y() + (x - p1.x()) * (p0.y() - p1.y()) / (p0.x() - p1.x());
++    } else {
++      return false;
++    }
++    result->setx(x);
++    result->sety(y);
++
++    if ( p0.y() <= p1.y() ) {
++      if ( (p0.y() <= y) && (y <= p1.y()) ) {
++          return true;
++      }
++    } else {
++      if ( (p0.y() >= y) && (y >= p1.y()) ) {
++          return true;
++      }
++    }
++
++    return false;
++}
++
++
++// calculate an "arbitrary" point inside this polygon for assigning
++// attribute areas
++void FGTriPoly::calc_point_inside( const FGTriNodes& trinodes ) {
++    Point3D tmp, min, ln, p1, p2, p3, m, result;
++
++    // 1. find point, min, with smallest y
++
++    // min.y() starts greater than the biggest possible lat (degrees)
++    min.sety( 100.0 );
++    // int min_index;
++    int min_node_index = 0;
++
++    int_list_iterator current, last;
++    current = poly.begin();
++    last = poly.end();
++
++    int counter = 0;
++    for ( ; current != last; ++current ) {
++      tmp = trinodes.get_node( *current );
++      if ( tmp.y() < min.y() ) {
++          min = tmp;
++          // min_index = *current;
++          min_node_index = counter;
++
++          // cout << "min index = " << *current 
++          //      << " value = " << min_y << endl;
++      } else {
++          // cout << "  index = " << *current << endl;
++      }
++      ++counter;
++    }
++    cout << "min node index = " << min_node_index << endl;
++    cout << "min index = " << poly[min_node_index] 
++       << " value = " << trinodes.get_node( poly[min_node_index] ) 
++       << " == " << min << endl;
++
++    // 2. take midpoint, m, of min with neighbor having lowest
++    // fabs(slope)
++
++    if ( min_node_index == 0 ) {
++      p1 = trinodes.get_node( poly[1] );
++      p2 = trinodes.get_node( poly[poly.size() - 1] );
++    } else if ( min_node_index == (int)(poly.size()) - 1 ) {
++      p1 = trinodes.get_node( poly[0] );
++      p2 = trinodes.get_node( poly[poly.size() - 1] );
++    } else {
++      p1 = trinodes.get_node( poly[min_node_index - 1] );
++      p2 = trinodes.get_node( poly[min_node_index + 1] );
++    }
++    double s1 = fabs( slope(min, p1) );
++    double s2 = fabs( slope(min, p2) );
++    if ( s1 < s2  ) {
++      ln = p1;
++    } else {
++      ln = p2;
++    }
++
++    m.setx( (min.x() + ln.x()) / 2.0 );
++    m.sety( (min.y() + ln.y()) / 2.0 );
++    cout << "low mid point = " << m << endl;
++
++    // 3. intersect vertical line through m and all other segments.
++    // save point, p3, with smallest y > m.y
++
++    p3.sety(100);
++    for ( int i = 0; i < (int)(poly.size()) - 1; ++i ) {
++      p1 = trinodes.get_node( poly[i] );
++      p2 = trinodes.get_node( poly[i+1] );
++
++      if ( intersects(p1, p2, m.x(), &result) ) {
++          // cout << "intersection = " << result << endl;
++          if ( ( result.y() < p3.y() ) &&
++               ( fabs(result.y() - m.y()) > FG_EPSILON ) ) {
++              p3 = result;
++          }
++      }
++    }
++    p1 = trinodes.get_node( poly[0] );
++    p2 = trinodes.get_node( poly[poly.size() - 1] );
++    if ( intersects(p1, p2, m.x(), &result) ) {
++      // cout << "intersection = " << result << endl;
++      if ( ( result.y() < p3.y() ) &&
++           ( fabs(result.y() - m.y()) > FG_EPSILON ) ) {
++          p3 = result;
++      }
++    }
++    cout << "low intersection of other segment = " << p3 << endl;
++
++    // 4. take midpoint of p2 && m as an arbitrary point inside polygon
++
++    inside.setx( (m.x() + p3.x()) / 2.0 );
++    inside.sety( (m.y() + p3.y()) / 2.0 );
++    cout << "inside point = " << inside << endl;
++}
++
++
++// $Log$
++// Revision 1.2  1999/03/29 13:11:11  curt
++// Shuffled stl type names a bit.
++// Began adding support for tri-fanning (or maybe other arrangments too.)
++//
++// Revision 1.1  1999/03/20 13:21:36  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0e156dbae32f5f23bd1dee95d24a1b979461c424
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,106 @@@
++// tripoly.hxx -- "Triangle" polygon management class
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef _TRIPOLY_HXX
++#define _TRIPOLY_HXX
++
++
++#ifndef __cplusplus                                                          
++# error This library requires C++
++#endif                                   
++
++
++#include <Include/compiler.h>
++
++#include <vector>
++
++#include <Main/construct_types.hxx>
++
++#include "trinodes.hxx"
++
++FG_USING_STD(vector);
++
++
++class FGTriPoly {
++
++private:
++
++    int_list poly;
++    Point3D inside;
++
++public:
++
++    // Constructor and destructor
++    FGTriPoly( void );
++    ~FGTriPoly( void );
++
++    // Add the specified node (index) to the polygon
++    inline void add_node( int index ) { poly.push_back( index ); }
++
++    // return size
++    inline int size() const { return poly.size(); }
++
++    // return the ith polygon point index
++    inline int get_pt_index( int i ) const { return poly[i]; }
++
++    // calculate an "arbitrary" point inside this polygon for
++    // assigning attribute areas
++    void calc_point_inside( const FGTriNodes& trinodes );
++    inline Point3D get_point_inside() const { return inside; }
++
++    inline void erase() { poly.erase( poly.begin(), poly.end() ); }
++};
++
++
++typedef vector < FGTriPoly > tripoly_list;
++typedef tripoly_list::iterator tripoly_list_iterator;
++typedef tripoly_list::const_iterator const_tripoly_list_iterator;
++
++
++#endif // _TRIPOLY_HXX
++
++
++// $Log$
++// Revision 1.5  1999/03/29 13:11:12  curt
++// Shuffled stl type names a bit.
++// Began adding support for tri-fanning (or maybe other arrangments too.)
++//
++// Revision 1.4  1999/03/23 22:02:56  curt
++// Refinements in naming and organization.
++//
++// Revision 1.3  1999/03/21 14:02:07  curt
++// Added a mechanism to dump out the triangle structures for viewing.
++// Fixed a couple bugs in first pass at triangulation.
++// - needed to explicitely initialize the polygon accumulator in triangle.cxx
++//   before each polygon rather than depending on the default behavior.
++// - Fixed a problem with region attribute propagation where I wasn't generating
++//   the hole points correctly.
++//
++// Revision 1.2  1999/03/20 20:32:58  curt
++// First mostly successful tile triangulation works.  There's plenty of tweaking
++// to do, but we are marching in the right direction.
++//
++// Revision 1.1  1999/03/20 13:21:36  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d05c6ccf190ec7dc2f8bc90dda6eb23b15a00f47
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,211 @@@
++// trisegs.cxx -- "Triangle" segment management class
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#include <Include/fg_constants.h>
++#include <Math/point3d.hxx>
++
++#include "trinodes.hxx"
++#include "trisegs.hxx"
++
++
++// Constructor 
++FGTriSegments::FGTriSegments( void ) {
++}
++
++
++// Destructor
++FGTriSegments::~FGTriSegments( void ) {
++}
++
++
++// Add a segment to the segment list if it doesn't already exist.
++// Returns the index (starting at zero) of the segment in the list.
++int FGTriSegments::unique_add( const FGTriSeg& s )
++{
++    triseg_list_iterator current, last;
++    int counter = 0;
++
++    // cout << s.get_n1() << "," << s.get_n2() << endl;
++
++    // check if segment already exists
++    current = seg_list.begin();
++    last = seg_list.end();
++    for ( ; current != last; ++current ) {
++      if ( s == *current ) {
++          // cout << "found an existing segment match" << endl;
++          return counter;
++      }
++      
++      ++counter;
++    }
++
++    // add to list
++    seg_list.push_back( s );
++
++    return counter;
++}
++
++
++// Divide segment if there are other points on it, return the divided
++// list of segments
++void FGTriSegments::unique_divide_and_add( const point_list& nodes, 
++                                         const FGTriSeg& s )
++{
++    Point3D p0 = nodes[ s.get_n1() ];
++    Point3D p1 = nodes[ s.get_n2() ];
++
++    bool found_extra = false;
++    int extra_index = 0;
++    int counter;
++    double m, b, y_err, x_err;
++    const_point_list_iterator current, last;
++
++    // bool temp = false;
++    // if ( s == FGTriSeg( 170, 206 ) ) {
++    //   cout << "this is it!" << endl;
++    //   temp = true;
++    // }
++
++    if ( fabs(p0.x() - p1.x()) > 3 * FG_EPSILON ) {
++      // use y = mx + b
++
++      // sort these in a sensable order
++      if ( p0.x() > p1.x() ) {
++          Point3D tmp = p0;
++          p0 = p1;
++          p1 = tmp;
++      }
++
++      m = (p0.y() - p1.y()) / (p0.x() - p1.x());
++      b = p1.y() - m * p1.x();
++
++      // if ( temp ) {
++      //   cout << "m = " << m << " b = " << b << endl;
++      // }
++
++      current = nodes.begin();
++      last = nodes.end();
++      counter = 0;
++      for ( ; current != last; ++current ) {
++          if ( (current->x() > (p0.x() + FG_EPSILON)) 
++               && (current->x() < (p1.x() - FG_EPSILON)) ) {
++
++              // if ( temp ) {
++              //   cout << counter << endl;
++              // }
++
++              y_err = fabs(current->y() - (m * current->x() + b));
++
++              if ( y_err < 10 * FG_EPSILON ) {
++                  cout << "FOUND EXTRA SEGMENT NODE (Y)" << endl;
++                  cout << p0 << " < " << *current << " < "
++                       << p1 << endl;
++                  found_extra = true;
++                  extra_index = counter;
++                  break;
++              }
++          }
++          ++counter;
++      }
++    } else {
++      // use x = constant
++
++      // cout << "FOUND VERTICLE SEGMENT" << endl;
++
++      // sort these in a sensable order
++      if ( p0.y() > p1.y() ) {
++          Point3D tmp = p0;
++          p0 = p1;
++          p1 = tmp;
++      }
++
++      // cout << " p0 = " << p0 << " p1 = " << p1 << endl;
++
++      current = nodes.begin();
++      last = nodes.end();
++      counter = 0;
++      for ( ; current != last; ++current ) {
++          // cout << counter << endl;
++          if ( (current->y() > (p0.y() + FG_EPSILON))
++               && (current->y() < (p1.y() - FG_EPSILON)) ) {
++              x_err = fabs(current->x() - p0.x());
++              // cout << "  found a potential point, x err = " 
++              //      << x_err << endl;
++              if ( x_err < 10*FG_EPSILON ) {
++                  cout << "FOUND EXTRA SEGMENT NODE (X)" << endl;
++                  cout << p0 << " < " << *current << " < "
++                       << p1 << endl;
++                  found_extra = true;
++                  extra_index = counter;
++                  break;
++              }
++          }
++          ++counter;
++      }
++    }
++
++    if ( found_extra ) {
++      // recurse with two sub segments
++      cout << "dividing " << s.get_n1() << " " << extra_index 
++           << " " << s.get_n2() << endl;
++      unique_divide_and_add( nodes, FGTriSeg( s.get_n1(), extra_index ) );
++      unique_divide_and_add( nodes, FGTriSeg( extra_index, s.get_n2() ) );
++    } else {
++      // this segment does not need to be divided, lets add it
++      unique_add( s );
++    }
++}
++
++
++// $Log$
++// Revision 1.6  1999/04/03 05:22:59  curt
++// Found a bug in dividing and adding unique verticle segments which could
++// cause the triangulator to end up in an infinite loop.  Basically the code
++// was correct, but the verticle line test was a bit to selective.
++//
++// Revision 1.5  1999/03/29 13:11:13  curt
++// Shuffled stl type names a bit.
++// Began adding support for tri-fanning (or maybe other arrangments too.)
++//
++// Revision 1.4  1999/03/27 05:30:17  curt
++// Handle corner nodes separately from the rest of the fitted nodes.
++// Add fitted nodes in after corners and polygon nodes since the fitted nodes
++//   are less important.  Subsequent nodes will "snap" to previous nodes if
++//   they are "close enough."
++// Need to manually divide segments to prevent "T" intersetions which can
++//   confound the triangulator.  Hey, I got to use a recursive method!
++// Pass along correct triangle attributes to output file generator.
++// Do fine grained node snapping for corners and polygons, but course grain
++//   node snapping for fitted terrain nodes.
++//
++// Revision 1.3  1999/03/23 22:02:57  curt
++// Refinements in naming and organization.
++//
++// Revision 1.2  1999/03/20 20:32:59  curt
++// First mostly successful tile triangulation works.  There's plenty of tweaking
++// to do, but we are marching in the right direction.
++//
++// Revision 1.1  1999/03/20 13:21:36  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2766bcf156de0131d72c1378e4a5b522a34149d4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,142 @@@
++// trisegs.hxx -- "Triangle" segment management class
++//
++// Written by Curtis Olson, started March 1999.
++//
++// Copyright (C) 1999  Curtis L. Olson  - curt@flightgear.org
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 2 of the
++// License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful, but
++// WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License
++// along with this program; if not, write to the Free Software
++// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++//
++// $Id$
++// (Log is kept at end of this file)
++
++
++#ifndef _TRISEGS_HXX
++#define _TRISEGS_HXX
++
++
++#ifndef __cplusplus                                                          
++# error This library requires C++
++#endif                                   
++
++
++#include <Include/compiler.h>
++
++#include <vector>
++
++#include "trinodes.hxx"
++
++FG_USING_STD(vector);
++
++
++// a segment is two integer pointers into the node list
++class FGTriSeg {
++    int n1, n2;
++
++public:
++
++    // Constructor and destructor
++    inline FGTriSeg( void ) { };
++    inline FGTriSeg( int i1, int i2 ) { 
++      n1 = i1;
++      n2 = i2;
++    }
++
++    inline ~FGTriSeg( void ) { };
++
++    inline int get_n1() const { return n1; }
++    inline void set_n1( int i ) { n1 = i; }
++    inline int get_n2() const { return n2; }
++    inline void set_n2( int i ) { n2 = i; }
++
++    friend bool operator == (const FGTriSeg& a, const FGTriSeg& b);
++
++};
++
++inline bool operator == (const FGTriSeg& a, const FGTriSeg& b)
++{
++    return ((a.n1 == b.n1) && (a.n2 == b.n2)) 
++      || ((a.n1 == b.n2) && (a.n2 == b.n1));
++}
++
++
++typedef vector < FGTriSeg > triseg_list;
++typedef triseg_list::iterator triseg_list_iterator;
++typedef triseg_list::const_iterator const_triseg_list_iterator;
++
++
++class FGTriSegments {
++
++private:
++
++    triseg_list seg_list;
++
++    // Divide segment if there are other points on it, return the
++    // divided list of segments
++    triseg_list divide_segment( const point_list& nodes, 
++                              const FGTriSeg& s );
++
++public:
++
++    // Constructor and destructor
++    FGTriSegments( void );
++    ~FGTriSegments( void );
++
++    // delete all the data out of seg_list
++    inline void clear() { seg_list.clear(); }
++
++    // Add a segment to the segment list if it doesn't already exist.
++    // Returns the index (starting at zero) of the segment in the
++    // list.
++    int unique_add( const FGTriSeg& s );
++
++    // Add a segment to the segment list if it doesn't already exist.
++    // Returns the index (starting at zero) of the segment in the list.
++    void unique_divide_and_add( const point_list& node_list, 
++                              const FGTriSeg& s );
++
++    // return the master node list
++    inline triseg_list get_seg_list() const { return seg_list; }
++
++    // return the ith segment
++    inline FGTriSeg get_seg( int i ) const { return seg_list[i]; }
++};
++
++
++#endif // _TRISEGS_HXX
++
++
++// $Log$
++// Revision 1.4  1999/04/05 02:17:14  curt
++// Dynamically update "error" until the resulting tile data scales within
++// a lower and upper bounds.
++//
++// Revision 1.3  1999/03/27 05:30:18  curt
++// Handle corner nodes separately from the rest of the fitted nodes.
++// Add fitted nodes in after corners and polygon nodes since the fitted nodes
++//   are less important.  Subsequent nodes will "snap" to previous nodes if
++//   they are "close enough."
++// Need to manually divide segments to prevent "T" intersetions which can
++//   confound the triangulator.  Hey, I got to use a recursive method!
++// Pass along correct triangle attributes to output file generator.
++// Do fine grained node snapping for corners and polygons, but course grain
++//   node snapping for fitted terrain nodes.
++//
++// Revision 1.2  1999/03/20 20:33:00  curt
++// First mostly successful tile triangulation works.  There's plenty of tweaking
++// to do, but we are marching in the right direction.
++//
++// Revision 1.1  1999/03/20 13:21:36  curt
++// Initial revision.
++//
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5c3f005b0fe8a5631efed5b2e3721a91b8298deb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++SUBDIRS = \
++      Makedir