--- /dev/null
--- /dev/null
++#---------------------------------------------------------------------------
++# 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.
++#
++
--- /dev/null
--- /dev/null
++// 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.
++//
++//
--- /dev/null
--- /dev/null
++// 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.
++//
++//
--- /dev/null
--- /dev/null
++// 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
++//
--- /dev/null
--- /dev/null
++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
++
--- /dev/null
--- /dev/null
++// 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.)
++//
--- /dev/null
--- /dev/null
++// 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.)
++//
--- /dev/null
--- /dev/null
++#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 );
++}
--- /dev/null
--- /dev/null
++#---------------------------------------------------------------------------
++# 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.
++#
++
--- /dev/null
--- /dev/null
++// 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.
++//
++
--- /dev/null
--- /dev/null
++// 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.
++//
++
--- /dev/null
--- /dev/null
++# 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 '#'
--- /dev/null
--- /dev/null
++# 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".
--- /dev/null
--- /dev/null
++# 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:
--- /dev/null
--- /dev/null
++# 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.
--- /dev/null
--- /dev/null
++# 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
--- /dev/null
--- /dev/null
++# 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.
--- /dev/null
--- /dev/null
++# 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"
--- /dev/null
--- /dev/null
++# 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".
--- /dev/null
--- /dev/null
++# 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".
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++SUBDIRS = \
++ Array \
++ Clipper \
++ Combine \
++ GenOutput \
++ Triangulate \
++ Main
--- /dev/null
--- /dev/null
++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
++
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++#---------------------------------------------------------------------------
++# 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.
++#
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
++//
--- /dev/null
--- /dev/null
++#---------------------------------------------------------------------------
++# 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.
++#
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++#!/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.
++#
--- /dev/null
--- /dev/null
++#---------------------------------------------------------------------------
++# 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.
++#
--- /dev/null
--- /dev/null
++/* 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.
++ *
++ */
--- /dev/null
--- /dev/null
++/* 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.
++ *
++ */
--- /dev/null
--- /dev/null
++/* 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.
++ *
++ */
--- /dev/null
--- /dev/null
++#---------------------------------------------------------------------------
++# 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.
++#
--- /dev/null
--- /dev/null
++// 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.
++//
++
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++#---------------------------------------------------------------------------
++# 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.
++#
--- /dev/null
--- /dev/null
++// 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.
++//
++
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
++
--- /dev/null
--- /dev/null
++#---------------------------------------------------------------------------
++# 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.
++#
++
--- /dev/null
--- /dev/null
++// 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.
++//
++//
--- /dev/null
--- /dev/null
++// 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.
++//
++//
--- /dev/null
--- /dev/null
++// 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.
++//
++//
--- /dev/null
--- /dev/null
++// 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.
++//
++//
--- /dev/null
--- /dev/null
++// 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.
++//
++//
--- /dev/null
--- /dev/null
++// 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.
++//
++//
--- /dev/null
--- /dev/null
++// 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.
++//
++//
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++// 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], ¢er, &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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++SUBDIRS = \
++ DEM \
++ Polygon \
++ Triangle
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++// 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.
++//
++
++
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++
++#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
++
--- /dev/null
--- /dev/null
++noinst_LIBRARIES = libPolygon.a
++
++libPolygon_a_SOURCES = \
++ index.cxx index.hxx \
++ names.cxx names.hxx
++
++INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++SUBDIRS = \
++ DemChop \
++ DemInfo \
++ DemRaw2ascii \
++ GenAirports \
++ ShapeFile
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++#---------------------------------------------------------------------------
++# 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.
++#
--- /dev/null
--- /dev/null
++// 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.
++//
++
--- /dev/null
--- /dev/null
++// 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.
++//
++
--- /dev/null
--- /dev/null
++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)
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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;
++
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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",¢er[0],¢er[1],¢er[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();
++
++}
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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;
++ }
++ }
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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 ();
++
++
++
++
++
++
++
++
++
++
++
++
--- /dev/null
--- /dev/null
++
++#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 */
++};
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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;
++
--- /dev/null
--- /dev/null
++/*
++ * 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);
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++ }
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
++
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++
++}
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
--- /dev/null
--- /dev/null
++int change_in_stripEx = 0;
++int change_in_strip = 0;
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++ }
++ }
++ }
++ }
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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;
++}
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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};
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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));
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++
++}
++
++
++
++
++
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++ }
++ }
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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 */
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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 );
++}
++
--- /dev/null
--- /dev/null
++
++/********************************************************************/
++/* 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
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++
++ }
++}
++
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++
++ }
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++}
++
++
++
--- /dev/null
--- /dev/null
++
++struct vert_struct {
++ VRDATA x, y, z; /* point coordinates */
++};
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
++
++
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
++
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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]);
++}
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
--- /dev/null
--- /dev/null
++
++/********************************************************************/
++/* 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();
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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;
++ }
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
--- /dev/null
--- /dev/null
++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)
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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;
++}
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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 );
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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",¢er[0],¢er[1],¢er[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);
++}
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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;
++ }
++ }
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++
++
++
++
++
++
++
++
++
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++ }
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++
++
++
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++}
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++ }
++ }
++ }
++ }
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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;
++}
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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};
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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));
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++
++}
++
++
++
++
++
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++ }
++ }
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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 );
++}
++
--- /dev/null
--- /dev/null
++
++/********************************************************************/
++/* 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
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++
++ }
++}
++
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++
++ }
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++}
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
++
++
++
++
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
++
++
++
++
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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]);
++}
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
--- /dev/null
--- /dev/null
++
++/********************************************************************/
++/* 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();
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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();
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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;
++ }
++}
++
++
--- /dev/null
--- /dev/null
++/********************************************************************/
++/* 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);
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++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.
--- /dev/null
--- /dev/null
++--------------------------------------------------------------------------
++| 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.
--- /dev/null
--- /dev/null
++#!/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.
++#
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++#---------------------------------------------------------------------------
++# 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.
++#
++
--- /dev/null
--- /dev/null
++// 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.
++//
++
--- /dev/null
--- /dev/null
++/* 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.
++ *
++ */
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++# 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
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++/*****************************************************************************/
++/* */
++/* ,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 = ¢er[i * dim];
++ point2 = ¢er[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 = ¢er[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 = ¢er[i * dim];
++ point2 = ¢er[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 = ¢er[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);
++ }
++}
--- /dev/null
--- /dev/null
++/*****************************************************************************/
++/* */
++/* 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, ®ionlist[4 * i]) >
++ 0.0) {
++ /* Find a triangle that contains the region point. */
++ intersect = locate(®ionlist[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,
++ ®ionarray, ®ions);
++#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 */
++}
--- /dev/null
--- /dev/null
++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.
++
--- /dev/null
--- /dev/null
++/*****************************************************************************/
++/* */
++/* (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 */
--- /dev/null
--- /dev/null
++/*****************************************************************************/
++/* */
++/* (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;
++}
--- /dev/null
--- /dev/null
++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
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
++
++
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++// 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.
++//
--- /dev/null
--- /dev/null
++SUBDIRS = \
++ Makedir