1
0
Fork 0

Merge FG_Tools as subdirectory

This commit is contained in:
Tim Moore 2009-09-14 13:43:55 +02:00
commit c54ce2dd85
190 changed files with 52483 additions and 0 deletions

62
Tools/Areas/Makefile.am Normal file
View file

@ -0,0 +1,62 @@
#---------------------------------------------------------------------------
# Makefile
#
# Written by Curtis Olson, started January 1998.
#
# Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id$
# (Log is kept at end of this file)
#---------------------------------------------------------------------------
bin_PROGRAMS = areas
areas_SOURCES = area.cxx area.hxx main.cxx
areas_LDADD = \
$(top_builddir)/Lib/Bucket/libBucket.a \
$(base_LIBS)
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
#---------------------------------------------------------------------------
# $Log$
# Revision 1.3 1998/11/04 23:01:43 curt
# Changes to the automake/autoconf system to reduce the number of libraries
# that are unnecessarily linked into the various executables.
#
# Revision 1.2 1998/07/30 23:49:18 curt
# Removed libtool support.
#
# Revision 1.1 1998/07/20 12:54:53 curt
# Whoops, need to commit Makefile.am, not Makefile.
#
# Revision 1.2 1998/04/14 02:25:59 curt
# Code reorganizations. Added a Lib/ directory for more general libraries.
#
# Revision 1.1 1998/04/08 22:54:57 curt
# Adopted Gnu automake/autoconf system.
#
# Revision 1.2 1998/01/21 02:55:46 curt
# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
#
# Revision 1.1 1998/01/15 02:45:25 curt
# Initial revision.
#

161
Tools/Areas/area.cxx Normal file
View file

@ -0,0 +1,161 @@
// area.c -- routines to assist with inserting "areas" into FG terrain
//
// Written by Curtis Olson, started March 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#include <math.h>
#include <stdio.h>
#include <Include/fg_constants.h>
#include "area.hxx"
// calc new x, y for a rotation
double rot_x(double x, double y, double theta) {
return ( x * cos(theta) + y * sin(theta) );
}
// calc new x, y for a rotation
double rot_y(double x, double y, double theta) {
return ( -x * sin(theta) + y * cos(theta) );
}
// calc new lon/lat given starting lon/lat, and offset radial, and
// distance. NOTE: distance is specified in meters (and converted
// internally to radians)
point2d calc_lon_lat( point2d orig, point2d offset ) {
point2d result;
offset.dist *= METER_TO_NM * NM_TO_RAD;
result.lat = asin( sin(orig.lat) * cos(offset.dist) +
cos(orig.lat) * sin(offset.dist) * cos(offset.theta) );
if ( cos(result.lat) < FG_EPSILON ) {
result.lon = orig.lon; // endpoint a pole
} else {
result.lon =
fmod(orig.lon - asin( sin(offset.theta) * sin(offset.dist) /
cos(result.lat) ) + FG_PI, FG_2PI) - FG_PI;
}
return(result);
}
point2d cart_to_polar_2d(point2d in) {
point2d result;
result.dist = sqrt( in.x * in.x + in.y * in.y );
result.theta = atan2(in.y, in.x);
return(result);
}
void batch_cart_to_polar_2d(point2d *in, point2d *out, int size) {
int i;
for ( i = 0; i < size; i++ ) {
out[i] = cart_to_polar_2d( in[i] );
}
}
// given a set of 2d coordinates relative to a center point, and the
// lon, lat of that center point, as well as a potential orientation
// angle, generate the corresponding lon and lat of the original 2d
// verticies.
void make_area(point2d orig, point2d *cart, point2d *result,
int size, double angle ) {
point2d rad[size];
int i;
// convert to polar coordinates
batch_cart_to_polar_2d(cart, rad, size);
for ( i = 0; i < size; i++ ) {
printf("(%.2f, %.2f)\n", rad[i].dist, rad[i].theta);
}
printf("\n");
// rotate by specified angle
for ( i = 0; i < size; i++ ) {
rad[i].theta += angle;
while ( rad[i].theta > FG_2PI ) {
rad[i].theta -= FG_2PI;
}
printf("(%.2f, %.2f)\n", rad[i].dist, rad[i].theta);
}
printf("\n");
for ( i = 0; i < size; i++ ) {
result[i] = calc_lon_lat(orig, rad[i]);
printf("(%.8f, %.8f)\n", result[i].lon, result[i].lat);
}
printf("\n");
}
// generate an area for a runway
void gen_runway_area( double lon, double lat, double heading,
double length, double width,
point2d *result, int *count)
{
point2d cart[4];
point2d orig;
double l, w;
int i;
orig.lon = lon;
orig.lat = lat;
l = (length / 2.0) + (length * 0.1);
w = (width / 2.0) + (width * 0.1);
// generate untransformed runway area vertices
cart[0].x = l; cart[0].y = w;
cart[1].x = l; cart[1].y = -w;
cart[2].x = -l; cart[2].y = -w;
cart[3].x = -l; cart[3].y = w;
for ( i = 0; i < 4; i++ ) {
printf("(%.2f, %.2f)\n", cart[i].x, cart[i].y);
}
printf("\n");
make_area(orig, cart, result, 4, heading);
for ( i = 0; i < 4; i++ ) {
printf("(%.8f, %.8f)\n", result[i].lon, result[i].lat);
}
printf("\n");
*count = 4;
}
// $Log$
// Revision 1.1 1998/07/20 12:54:05 curt
// Initial revision.
//
//

57
Tools/Areas/area.hxx Normal file
View file

@ -0,0 +1,57 @@
// area.h -- routines to assist with inserting "areas" into FG terrain
//
// Written by Curtis Olson, started February 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#ifndef _AREA_H
#define _AREA_H
typedef struct {
union {
double x;
double dist;
double lon;
};
union {
double y;
double theta;
double lat;
};
} point2d;
// generate an area for a runway
void gen_runway_area( double lon, double lat, double heading,
double length, double width,
point2d *result, int *count );
#endif // _AREA_H
// $Log$
// Revision 1.1 1998/07/20 12:54:05 curt
// Initial revision.
//
//

130
Tools/Areas/main.cxx Normal file
View file

@ -0,0 +1,130 @@
// main.c -- main loop
//
// Written by Curtis Olson, started March 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <stdio.h>
#include <string.h>
#include "area.hxx"
#include <Bucket/bucketutils.h>
#include <Include/fg_constants.h>
int main( int argc, char **argv ) {
fgBUCKET b;
point2d nodes[4];
FILE *fd;
char base[256], path[256], command[256], file[256], exfile[256];
double lon, lat, elevation, heading;
double length, width;
long int index;
int i, count;
if ( argc != 2 ) {
printf("Usage %s <work dir>\n", argv[0]);
exit(0);
}
// P13 (Globe, AZ)
// lon = -110.6642442;
// lat = 33.3528903;
// heading = 102.0 * DEG_TO_RAD;
// length = 1769;
// width = 23;
// KANE
lon = -93.2113889;
lat = 45.145;
elevation = 912 * FEET_TO_METER;
heading = 270.0 * DEG_TO_RAD;
length = 1220;
width = 23;
gen_runway_area( lon * DEG_TO_RAD, lat * DEG_TO_RAD,
heading, length, width, nodes, &count );
fgBucketFind(lon, lat, &b);
printf( "Bucket = lon,lat = %d,%d x,y index = %d,%d\n",
b.lon, b.lat, b.x, b.y);
index = fgBucketGenIndex(&b);
fgBucketGenBasePath(&b, base);
sprintf(path, "%s/Scenery/%s", argv[1], base);
sprintf(command, "mkdir -p %s\n", path);
system(command);
sprintf(exfile, "%s/%ld.node.ex", path, index);
sprintf(file, "%s/%ld.poly", path, index);
printf( "extra node file = %s\n", exfile);
printf( "poly file = %s\n", file);
// output extra nodes
if ( (fd = fopen(exfile, "w")) == NULL ) {
printf("Cannot open file: %s\n", exfile);
exit(-1);
}
fprintf(fd, "%d 2 0 0\n", count);
for ( i = 0; i < count; i++ ) {
fprintf( fd, "%d %.2f %.2f %.2f\n", i + 1,
nodes[i].lon * RAD_TO_ARCSEC, nodes[i].lat * RAD_TO_ARCSEC,
elevation);
}
fclose(fd);
// output poly
if ( (fd = fopen(file, "w")) == NULL ) {
printf("Cannot open file: %s\n", file);
exit(-1);
}
// output empty node list
fprintf(fd, "0 2 0 0\n");
// output segments
fprintf(fd, "%d 0\n", count);
for ( i = 0; i < count - 1; i++ ) {
fprintf( fd, "%d %d %d\n", i + 1, i + 1, i + 2 );
}
fprintf( fd, "%d %d %d\n", count, count, 1 );
// output hole center
fprintf( fd, "1\n");
fprintf( fd, "1 %.2f %.2f\n", lon * 3600.0, lat * 3600);
fclose(fd);
}
// $Log: main.c,v
//

25
Tools/Array/Makefile.am Normal file
View file

@ -0,0 +1,25 @@
noinst_LIBRARIES = libArray.a
libArray_a_SOURCES = array.cxx array.hxx
bin_PROGRAMS = testarray
testarray_SOURCES = testarray.cxx
testarray_LDADD = \
$(top_builddir)/Tools/Construct/Array/libArray.a \
$(top_builddir)/Lib/Bucket/libBucket.a \
$(top_builddir)/Lib/Math/libMath.a \
$(top_builddir)/Lib/Misc/libMisc.a \
$(top_builddir)/Lib/zlib/libz.a
INCLUDES += \
-I$(top_builddir) \
-I$(top_builddir)/Lib \
-I$(top_builddir)/Tools/Construct
# We can't build this with "-O2" (optimization) since this causes a seg fault
# I haven't found a way to strip this out of the CXXFLAGS, so I'm just
# setting it to "-g"
# CXXFLAGS = -g

607
Tools/Array/array.cxx Normal file
View file

@ -0,0 +1,607 @@
// array.cxx -- Array management class
//
// Written by Curtis Olson, started March 1998.
//
// Copyright (C) 1998 - 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <Include/compiler.h>
// #include <ctype.h> // isspace()
// #include <stdlib.h> // atoi()
// #include <math.h> // rint()
// #include <stdio.h>
// #include <string.h>
// #ifdef HAVE_SYS_STAT_H
// # include <sys/stat.h> // stat()
// #endif
// #ifdef FG_HAVE_STD_INCLUDES
// # include <cerrno>
// #else
// # include <errno.h>
// #endif
// #ifdef HAVE_UNISTD_H
// # include <unistd.h> // stat()
// #endif
#include STL_STRING
#include <Include/fg_constants.h>
#include <Misc/fgstream.hxx>
#include <Misc/strutils.hxx>
#include <Math/leastsqs.hxx>
#include "array.hxx"
FG_USING_STD(string);
FGArray::FGArray( void ) {
// cout << "class FGArray CONstructor called." << endl;
in_data = new float[ARRAY_SIZE_1][ARRAY_SIZE_1];
// out_data = new float[ARRAY_SIZE_1][ARRAY_SIZE_1];
}
FGArray::FGArray( const string &file ) {
// cout << "class FGArray CONstructor called." << endl;
in_data = new float[ARRAY_SIZE_1][ARRAY_SIZE_1];
// out_data = new float[ARRAY_SIZE_1][ARRAY_SIZE_1];
FGArray::open(file);
}
// open an Array file
int
FGArray::open( const string& file ) {
// open input file (or read from stdin)
if ( file == "-" ) {
cout << " Opening array data pipe from stdin" << endl;
// fd = stdin;
// fd = gzdopen(STDIN_FILENO, "r");
cout << " Not yet ported ..." << endl;
return 0;
} else {
in = new fg_gzifstream( file );
if ( ! in->is_open() ) {
cout << " Cannot open " << file << endl;
return 0;
}
cout << " Opening array data file: " << file << endl;
}
return 1;
}
// close an Array file
int
FGArray::close() {
// the fg_gzifstream doesn't seem to have a close()
delete in;
return 1;
}
// parse Array file, pass in the bucket so we can make up values when
// the file wasn't found.
int
FGArray::parse( FGBucket& b ) {
if ( in->is_open() ) {
// file open, parse
*in >> originx >> originy;
*in >> cols >> col_step;
*in >> rows >> row_step;
cout << " origin = " << originx << " " << originy << endl;
cout << " cols = " << cols << " rows = " << rows << endl;
cout << " col_step = " << col_step
<< " row_step = " << row_step <<endl;
for ( int i = 0; i < cols; i++ ) {
for ( int j = 0; j < rows; j++ ) {
*in >> in_data[i][j];
}
}
cout << " Done parsing\n";
} else {
// file not open (not found?), fill with zero'd data
originx = ( b.get_center_lon() - 0.5 * b.get_width() ) * 3600.0;
originy = ( b.get_center_lat() - 0.5 * b.get_height() ) * 3600.0;
double max_x = ( b.get_center_lon() + 0.5 * b.get_width() ) * 3600.0;
double max_y = ( b.get_center_lat() + 0.5 * b.get_height() ) * 3600.0;
cols = 3;
col_step = (max_x - originx) / (cols - 1);
rows = 3;
row_step = (max_y - originy) / (rows - 1);
cout << " origin = " << originx << " " << originy << endl;
cout << " cols = " << cols << " rows = " << rows << endl;
cout << " col_step = " << col_step
<< " row_step = " << row_step <<endl;
for ( int i = 0; i < cols; i++ ) {
for ( int j = 0; j < rows; j++ ) {
in_data[i][j] = 0.0;
}
}
cout << " File not open, so using zero'd data" << endl;
}
return 1;
}
// add a node to the output corner node list
void FGArray::add_corner_node( int i, int j, double val ) {
double x = (originx + i * col_step) / 3600.0;
double y = (originy + j * row_step) / 3600.0;
// cout << "originx = " << originx << " originy = " << originy << endl;
// cout << "corner = " << Point3D(x, y, val) << endl;
corner_list.push_back( Point3D(x, y, val) );
}
// add a node to the output fitted node list
void FGArray::add_fit_node( int i, int j, double val ) {
double x = (originx + i * col_step) / 3600.0;
double y = (originy + j * row_step) / 3600.0;
// cout << Point3D(x, y, val) << endl;
node_list.push_back( Point3D(x, y, val) );
}
// Use least squares to fit a simpler data set to dem data. Return
// the number of fitted nodes
int FGArray::fit( double error ) {
double x[ARRAY_SIZE_1], y[ARRAY_SIZE_1];
double m, b, max_error, error_sq;
double x1, y1;
// double ave_error;
double cury, lasty;
int n, row, start, end;
int colmin, colmax, rowmin, rowmax;
bool good_fit;
// FILE *dem, *fit, *fit1;
error_sq = error * error;
cout << " Initializing fitted node list" << endl;
corner_list.clear();
node_list.clear();
// determine dimensions
colmin = 0;
colmax = cols;
rowmin = 0;
rowmax = rows;
cout << " Fitting region = " << colmin << "," << rowmin << " to "
<< colmax << "," << rowmax << endl;;
// generate corners list
add_corner_node( colmin, rowmin, in_data[colmin][rowmin] );
add_corner_node( colmin, rowmax-1, in_data[colmin][rowmax] );
add_corner_node( colmax-1, rowmin, in_data[colmax][rowmin] );
add_corner_node( colmax-1, rowmax-1, in_data[colmax][rowmax] );
cout << " Beginning best fit procedure" << endl;
lasty = 0;
for ( row = rowmin; row < rowmax; row++ ) {
// fit = fopen("fit.dat", "w");
// fit1 = fopen("fit1.dat", "w");
start = colmin;
// cout << " fitting row = " << row << endl;
while ( start < colmax - 1 ) {
end = start + 1;
good_fit = true;
x[0] = start * col_step;
y[0] = in_data[start][row];
x[1] = end * col_step;
y[1] = in_data[end][row];
n = 2;
// cout << "Least square of first 2 points" << endl;
least_squares(x, y, n, &m, &b);
end++;
while ( (end < colmax) && good_fit ) {
++n;
// cout << "Least square of first " << n << " points" << endl;
x[n-1] = x1 = end * col_step;
y[n-1] = y1 = in_data[end][row];
least_squares_update(x1, y1, &m, &b);
// ave_error = least_squares_error(x, y, n, m, b);
max_error = least_squares_max_error(x, y, n, m, b);
/*
printf("%d - %d ave error = %.2f max error = %.2f y = %.2f*x + %.2f\n",
start, end, ave_error, max_error, m, b);
f = fopen("gnuplot.dat", "w");
for ( j = 0; j <= end; j++) {
fprintf(f, "%.2f %.2f\n", 0.0 + ( j * col_step ),
in_data[row][j]);
}
for ( j = start; j <= end; j++) {
fprintf(f, "%.2f %.2f\n", 0.0 + ( j * col_step ),
in_data[row][j]);
}
fclose(f);
printf("Please hit return: "); gets(junk);
*/
if ( max_error > error_sq ) {
good_fit = false;
}
end++;
}
if ( !good_fit ) {
// error exceeded the threshold, back up
end -= 2; // back "end" up to the last good enough fit
n--; // back "n" up appropriately too
} else {
// we popped out of the above loop while still within
// the error threshold, so we must be at the end of
// the data set
end--;
}
least_squares(x, y, n, &m, &b);
// ave_error = least_squares_error(x, y, n, m, b);
max_error = least_squares_max_error(x, y, n, m, b);
/*
printf("\n");
printf("%d - %d ave error = %.2f max error = %.2f y = %.2f*x + %.2f\n",
start, end, ave_error, max_error, m, b);
printf("\n");
fprintf(fit1, "%.2f %.2f\n", x[0], m * x[0] + b);
fprintf(fit1, "%.2f %.2f\n", x[end-start], m * x[end-start] + b);
*/
if ( start > colmin ) {
// skip this for the first line segment
cury = m * x[0] + b;
add_fit_node( start, row, (lasty + cury) / 2 );
// fprintf(fit, "%.2f %.2f\n", x[0], (lasty + cury) / 2);
}
lasty = m * x[end-start] + b;
start = end;
}
/*
fclose(fit);
fclose(fit1);
dem = fopen("gnuplot.dat", "w");
for ( j = 0; j < ARRAY_SIZE_1; j++) {
fprintf(dem, "%.2f %.2f\n", 0.0 + ( j * col_step ),
in_data[j][row]);
}
fclose(dem);
*/
// NOTICE, this is for testing only. This instance of
// output_nodes should be removed. It should be called only
// once at the end once all the nodes have been generated.
// newmesh_output_nodes(&nm, "mesh.node");
// printf("Please hit return: "); gets(junk);
}
// outputmesh_output_nodes(fg_root, p);
// return fit nodes + 4 corners
return node_list.size() + 4;
}
// return the current altitude based on grid data. We should rewrite
// this to interpolate exact values, but for now this is good enough
double FGArray::interpolate_altitude( double lon, double lat ) const {
// we expect incoming (lon,lat) to be in arcsec for now
double xlocal, ylocal, dx, dy, zA, zB, elev;
int x1, x2, x3, y1, y2, y3;
float z1, z2, z3;
int xindex, yindex;
/* determine if we are in the lower triangle or the upper triangle
______
| /|
| / |
| / |
|/ |
------
then calculate our end points
*/
xlocal = (lon - originx) / col_step;
ylocal = (lat - originy) / row_step;
xindex = (int)(xlocal);
yindex = (int)(ylocal);
// printf("xindex = %d yindex = %d\n", xindex, yindex);
if ( xindex + 1 == cols ) {
xindex--;
}
if ( yindex + 1 == rows ) {
yindex--;
}
if ( (xindex < 0) || (xindex + 1 >= cols) ||
(yindex < 0) || (yindex + 1 >= rows) ) {
cout << "WARNING: Attempt to interpolate value outside of array!!!"
<< endl;
return 0;
}
dx = xlocal - xindex;
dy = ylocal - yindex;
if ( dx > dy ) {
// lower triangle
// printf(" Lower triangle\n");
x1 = xindex;
y1 = yindex;
z1 = in_data[x1][y1];
x2 = xindex + 1;
y2 = yindex;
z2 = in_data[x2][y2];
x3 = xindex + 1;
y3 = yindex + 1;
z3 = in_data[x3][y3];
// printf(" dx = %.2f dy = %.2f\n", dx, dy);
// printf(" (x1,y1,z1) = (%d,%d,%d)\n", x1, y1, z1);
// printf(" (x2,y2,z2) = (%d,%d,%d)\n", x2, y2, z2);
// printf(" (x3,y3,z3) = (%d,%d,%d)\n", x3, y3, z3);
zA = dx * (z2 - z1) + z1;
zB = dx * (z3 - z1) + z1;
// printf(" zA = %.2f zB = %.2f\n", zA, zB);
if ( dx > FG_EPSILON ) {
elev = dy * (zB - zA) / dx + zA;
} else {
elev = zA;
}
} else {
// upper triangle
// printf(" Upper triangle\n");
x1 = xindex;
y1 = yindex;
z1 = in_data[x1][y1];
x2 = xindex;
y2 = yindex + 1;
z2 = in_data[x2][y2];
x3 = xindex + 1;
y3 = yindex + 1;
z3 = in_data[x3][y3];
// printf(" dx = %.2f dy = %.2f\n", dx, dy);
// printf(" (x1,y1,z1) = (%d,%d,%d)\n", x1, y1, z1);
// printf(" (x2,y2,z2) = (%d,%d,%d)\n", x2, y2, z2);
// printf(" (x3,y3,z3) = (%d,%d,%d)\n", x3, y3, z3);
zA = dy * (z2 - z1) + z1;
zB = dy * (z3 - z1) + z1;
// printf(" zA = %.2f zB = %.2f\n", zA, zB );
// printf(" xB - xA = %.2f\n", col_step * dy / row_step);
if ( dy > FG_EPSILON ) {
elev = dx * (zB - zA) / dy + zA;
} else {
elev = zA;
}
}
return(elev);
}
#if 0
// Write out a node file that can be used by the "triangle" program.
// Check for an optional "index.node.ex" file in case there is a .poly
// file to go along with this node file. Include these nodes first
// since they are referenced by position from the .poly file.
void FGArray::outputmesh_output_nodes( const string& fg_root, FGBucket& p )
{
double exnodes[MAX_EX_NODES][3];
struct stat stat_buf;
string dir, file;
char exfile[256];
#ifdef WIN32
char tmp_path[256];
#endif
string command;
FILE *fd;
int colmin, colmax, rowmin, rowmax;
int i, j, count, excount, result;
// determine dimensions
colmin = p.get_x() * ( (cols - 1) / 8);
colmax = colmin + ( (cols - 1) / 8);
rowmin = p.get_y() * ( (rows - 1) / 8);
rowmax = rowmin + ( (rows - 1) / 8);
cout << " dumping region = " << colmin << "," << rowmin << " to " <<
colmax << "," << rowmax << "\n";
// generate the base directory
string base_path = p.gen_base_path();
cout << " fg_root = " << fg_root << " Base Path = " << base_path << endl;
dir = fg_root + "/Scenery/" + base_path;
cout << " Dir = " << dir << endl;
// stat() directory and create if needed
errno = 0;
result = stat(dir.c_str(), &stat_buf);
if ( result != 0 && errno == ENOENT ) {
cout << " Creating directory\n";
command = "mkdir -p " + dir + "\n";
system( command.c_str() );
} else {
// assume directory exists
}
// get index and generate output file name
file = dir + "/" + p.gen_index_str() + ".node";
// get (optional) extra node file name (in case there is matching
// .poly file.
exfile = file + ".ex";
// load extra nodes if they exist
excount = 0;
if ( (fd = fopen(exfile, "r")) != NULL ) {
int junki;
fscanf(fd, "%d %d %d %d", &excount, &junki, &junki, &junki);
if ( excount > MAX_EX_NODES - 1 ) {
printf("Error, too many 'extra' nodes, increase array size\n");
exit(-1);
} else {
printf(" Expecting %d 'extra' nodes\n", excount);
}
for ( i = 1; i <= excount; i++ ) {
fscanf(fd, "%d %lf %lf %lf\n", &junki,
&exnodes[i][0], &exnodes[i][1], &exnodes[i][2]);
printf("(extra) %d %.2f %.2f %.2f\n",
i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
}
fclose(fd);
}
printf("Creating node file: %s\n", file);
fd = fopen(file, "w");
// first count regular nodes to generate header
count = 0;
for ( j = rowmin; j <= rowmax; j++ ) {
for ( i = colmin; i <= colmax; i++ ) {
if ( out_data[i][j] > -9000.0 ) {
count++;
}
}
// printf(" count = %d\n", count);
}
fprintf(fd, "%d 2 1 0\n", count + excount);
// now write out extra node data
for ( i = 1; i <= excount; i++ ) {
fprintf(fd, "%d %.2f %.2f %.2f\n",
i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
}
// write out actual node data
count = excount + 1;
for ( j = rowmin; j <= rowmax; j++ ) {
for ( i = colmin; i <= colmax; i++ ) {
if ( out_data[i][j] > -9000.0 ) {
fprintf(fd, "%d %.2f %.2f %.2f\n",
count++,
originx + (double)i * col_step,
originy + (double)j * row_step,
out_data[i][j]);
}
}
// printf(" count = %d\n", count);
}
fclose(fd);
}
#endif
FGArray::~FGArray( void ) {
// printf("class FGArray DEstructor called.\n");
delete [] in_data;
// delete [] out_data;
}
// $Log$
// Revision 1.8 1999/04/05 02:15:23 curt
// Make dem fitting more robust in cases when no dem file available.
//
// Revision 1.7 1999/03/27 14:05:10 curt
// More sensible handling of the case where no dem file for this tile exists
// (or has been generated).
//
// Revision 1.6 1999/03/27 05:20:13 curt
// Handle corner nodes separately from the rest of the fitted nodes.
// Fixed some "const" related warnings.
//
// Revision 1.5 1999/03/25 19:03:50 curt
// Minor tweaks related to FGBucket usage.
//
// Revision 1.4 1999/03/20 20:32:51 curt
// First mostly successful tile triangulation works. There's plenty of tweaking
// to do, but we are marching in the right direction.
//
// Revision 1.3 1999/03/17 23:48:17 curt
// Removed forced -g compile flag.
// Fixed a couple compiler warnings.
//
// Revision 1.2 1999/03/13 23:50:26 curt
// Tweaked output formatting a bit.
//
// Revision 1.1 1999/03/13 18:45:02 curt
// Initial revision. (derived from libDEM.a code.)
//

146
Tools/Array/array.hxx Normal file
View file

@ -0,0 +1,146 @@
// array.hxx -- Array management class
//
// Written by Curtis Olson, started March 1998.
//
// Copyright (C) 1998 - 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifndef _ARRAY_HXX
#define _ARRAY_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <Include/compiler.h>
#include <vector>
#include <Bucket/newbucket.hxx>
#include <Math/point3d.hxx>
#include <Misc/fgstream.hxx>
#include <Main/construct_types.hxx>
FG_USING_STD(vector);
#define ARRAY_SIZE 1200
#define ARRAY_SIZE_1 1201
class FGArray {
private:
// file pointer for input
// gzFile fd;
fg_gzifstream *in;
// coordinates (in arc seconds) of south west corner
double originx, originy;
// number of columns and rows
int cols, rows;
// Distance between column and row data points (in arc seconds)
double col_step, row_step;
// pointers to the actual grid data allocated here
float (*in_data)[ARRAY_SIZE_1];
// float (*out_data)[ARRAY_SIZE_1];
// output nodes
point_list corner_list;
point_list node_list;
public:
// Constructor
FGArray( void );
FGArray( const string& file );
// Destructor
~FGArray( void );
// open an Array file (use "-" if input is coming from stdin)
int open ( const string& file );
// close a Array file
int close();
// parse a Array file
int parse( FGBucket& b );
// Use least squares to fit a simpler data set to dem data.
// Return the number of fitted nodes
int fit( double error );
// add a node to the output corner node list
void add_corner_node( int i, int j, double val );
// add a node to the output fitted node list
void add_fit_node( int i, int j, double val );
// return the current altitude based on grid data. We should
// rewrite this to interpolate exact values, but for now this is
// good enough
double interpolate_altitude( double lon, double lat ) const;
// Informational methods
inline double get_originx() const { return originx; }
inline double get_originy() const { return originy; }
inline int get_cols() const { return cols; }
inline int get_rows() const { return rows; }
inline double get_col_step() const { return col_step; }
inline double get_row_step() const { return row_step; }
inline point_list get_corner_node_list() const { return corner_list; }
inline point_list get_fit_node_list() const { return node_list; }
};
#endif // _ARRAY_HXX
// $Log$
// Revision 1.6 1999/04/05 02:15:24 curt
// Make dem fitting more robust in cases when no dem file available.
//
// Revision 1.5 1999/03/29 13:11:02 curt
// Shuffled stl type names a bit.
// Began adding support for tri-fanning (or maybe other arrangments too.)
//
// Revision 1.4 1999/03/27 05:20:14 curt
// Handle corner nodes separately from the rest of the fitted nodes.
// Fixed some "const" related warnings.
//
// Revision 1.3 1999/03/20 20:32:52 curt
// First mostly successful tile triangulation works. There's plenty of tweaking
// to do, but we are marching in the right direction.
//
// Revision 1.2 1999/03/13 23:50:27 curt
// Tweaked output formatting a bit.
//
// Revision 1.1 1999/03/13 18:45:02 curt
// Initial revision. (derived from libDEM.a code.)
//

33
Tools/Array/testarray.cxx Normal file
View file

@ -0,0 +1,33 @@
#include <Bucket/newbucket.hxx>
#include "array.hxx"
main(int argc, char **argv) {
double lon, lat;
if ( argc != 2 ) {
cout << "Usage: " << argv[0] << " work_dir" << endl;
exit(-1);
}
string work_dir = argv[1];
lon = -146.248360; lat = 61.133950; // PAVD (Valdez, AK)
lon = -110.664244; lat = 33.352890; // P13
FGBucket b( lon, lat );
string base = b.gen_base_path();
string path = work_dir + "/Scenery/" + base;
string arrayfile = path + "/" + b.gen_index_str() + ".dem";
cout << "arrayfile = " << arrayfile << endl;
FGArray a(arrayfile);
a.parse( b );
lon *= 3600;
lat *= 3600;
cout << " " << a.interpolate_altitude(lon, lat) << endl;
a.fit( 100 );
}

View file

@ -0,0 +1,62 @@
#---------------------------------------------------------------------------
# Makefile
#
# Written by Curtis Olson, started January 1998.
#
# Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id$
# (Log is kept at end of this file)
#---------------------------------------------------------------------------
bin_PROGRAMS = assemtris
assemtris_SOURCES = assemtris.cxx assemtris.hxx
assemtris_LDADD = \
$(top_builddir)/Lib/Bucket/libBucket.a \
$(base_LIBS)
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
#---------------------------------------------------------------------------
# $Log$
# Revision 1.5 1998/11/04 23:01:45 curt
# Changes to the automake/autoconf system to reduce the number of libraries
# that are unnecessarily linked into the various executables.
#
# Revision 1.4 1998/09/25 19:35:25 curt
# Renamed assemtris.[ch] to assemtris.[ch]xx
#
# Revision 1.3 1998/07/30 23:49:23 curt
# Removed libtool support.
#
# Revision 1.2 1998/04/14 02:25:59 curt
# Code reorganizations. Added a Lib/ directory for more general libraries.
#
# Revision 1.1 1998/04/08 22:54:57 curt
# Adopted Gnu automake/autoconf system.
#
# Revision 1.2 1998/01/21 02:55:46 curt
# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
#
# Revision 1.1 1998/01/15 02:45:25 curt
# Initial revision.
#

View file

@ -0,0 +1,600 @@
// assemtris.cxx -- reassemble the pieces produced by splittris
//
// Written by Curtis Olson, started January 1998.
//
// Copyright (C) 1997 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <math.h>
#include <stdio.h>
#include <stdlib.h> // for atoi()
#include <string.h>
#include <sys/stat.h> // for stat()
#include <unistd.h> // for stat()
#include "assemtris.hxx"
#include <Include/fg_constants.h>
#include <Bucket/bucketutils.h>
// #define OFFSET_LON 0.1
// #define OFFSET_LAT 0.1
#define OFFSET_LON 0.0
#define OFFSET_LAT 0.0
int nodecount = 0;
int excount = 0;
static double nodes[MAX_NODES][3];
static double exnodes[MAX_NODES][3];
fgBUCKET my_index;
fgBUCKET ne_index, nw_index, sw_index, se_index;
fgBUCKET north_index, south_index, east_index, west_index;
// return the file base name ( foo/bar/file.ext = file.ext )
void extract_file(char *in, char *base) {
int len, i;
len = strlen(in);
i = len - 1;
while ( (i >= 0) && (in[i] != '/') ) {
i--;
}
in += (i + 1);
strcpy(base, in);
}
// return the file path name ( foo/bar/file.ext = foo/bar )
void extract_path(char *in, char *base) {
int len, i;
len = strlen(in);
strcpy(base, in);
i = len - 1;
while ( (i >= 0) && (in[i] != '/') ) {
i--;
}
base[i] = '\0';
}
// check to see if specified node is in the extra list
int is_extra_node(double *n) {
int i;
for ( i = 1; i <= excount; i++ ) {
// we only check lon/lat in case the height got fooled with
// along the way
if ( (fabs(n[0] - exnodes[i][0]) < FG_EPSILON) &&
(fabs(n[1] - exnodes[i][1]) < FG_EPSILON) ) {
return(i);
}
}
return(0);
}
// Read all the extra nodes. These typically define inner areas to
// exclude from triangulations. There will be a .poly file that
// refers to these by position number which assumes all the extra
// nodes come first in the generated .node file.
void read_extra_nodes(char *exfile) {
FILE *fd;
int i, junk1, junk2, junk3;
// load extra nodes if they exist
excount = 0;
if ( (fd = fopen(exfile, "r")) != NULL ) {
printf("Found and 'extra' node file = %s\n", exfile);
fscanf(fd, "%d %d %d %d", &excount, &junk1, &junk2, &junk3);
if ( excount > MAX_NODES - 1 ) {
printf("Error, too many 'extra' nodes, increase array size\n");
exit(-1);
} else {
printf(" Expecting %d 'extra' nodes\n", excount);
}
for ( i = 1; i <= excount; i++ ) {
fscanf(fd, "%d %lf %lf %lf\n", &junk1,
&exnodes[i][0], &exnodes[i][1], &exnodes[i][2]);
printf("(extra) %d %.2f %.2f %.2f\n",
i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
}
fclose(fd);
}
}
// check if a file exists
int file_exists(char *file) {
struct stat stat_buf;
int result;
printf("checking %s ... ", file);
result = stat(file, &stat_buf);
if ( result != 0 ) {
// stat failed, no file
printf("not found.\n");
return(0);
} else {
// stat succeeded, file exists
printf("exists.\n");
return(1);
}
}
// check to see if a shared object exists
int shared_object_exists(char *basepath, char *ext, char *file) {
char scene_path[256];
long int index;
if ( strcmp(ext, ".sw") == 0 ) {
fgBucketGenBasePath(&my_index, scene_path);
index = fgBucketGenIndex(&my_index);
sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&west_index, scene_path);
index = fgBucketGenIndex(&west_index);
sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&sw_index, scene_path);
index = fgBucketGenIndex(&sw_index);
sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&south_index, scene_path);
index = fgBucketGenIndex(&south_index);
sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( strcmp(ext, ".se") == 0 ) {
fgBucketGenBasePath(&my_index, scene_path);
index = fgBucketGenIndex(&my_index);
sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&east_index, scene_path);
index = fgBucketGenIndex(&east_index);
sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&se_index, scene_path);
index = fgBucketGenIndex(&se_index);
sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&south_index, scene_path);
index = fgBucketGenIndex(&south_index);
sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( strcmp(ext, ".ne") == 0 ) {
fgBucketGenBasePath(&my_index, scene_path);
index = fgBucketGenIndex(&my_index);
sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&east_index, scene_path);
index = fgBucketGenIndex(&east_index);
sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&ne_index, scene_path);
index = fgBucketGenIndex(&ne_index);
sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&north_index, scene_path);
index = fgBucketGenIndex(&north_index);
sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( strcmp(ext, ".nw") == 0 ) {
fgBucketGenBasePath(&my_index, scene_path);
index = fgBucketGenIndex(&my_index);
sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&west_index, scene_path);
index = fgBucketGenIndex(&west_index);
sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&nw_index, scene_path);
index = fgBucketGenIndex(&nw_index);
sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&north_index, scene_path);
index = fgBucketGenIndex(&north_index);
sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( strcmp(ext, ".south") == 0 ) {
fgBucketGenBasePath(&my_index, scene_path);
index = fgBucketGenIndex(&my_index);
sprintf(file, "%s/%s/%ld.1.south", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&south_index, scene_path);
index = fgBucketGenIndex(&south_index);
sprintf(file, "%s/%s/%ld.1.north", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( strcmp(ext, ".north") == 0 ) {
fgBucketGenBasePath(&my_index, scene_path);
index = fgBucketGenIndex(&my_index);
sprintf(file, "%s/%s/%ld.1.north", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&north_index, scene_path);
index = fgBucketGenIndex(&north_index);
sprintf(file, "%s/%s/%ld.1.south", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( strcmp(ext, ".west") == 0 ) {
fgBucketGenBasePath(&my_index, scene_path);
index = fgBucketGenIndex(&my_index);
sprintf(file, "%s/%s/%ld.1.west", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&west_index, scene_path);
index = fgBucketGenIndex(&west_index);
sprintf(file, "%s/%s/%ld.1.east", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( strcmp(ext, ".east") == 0 ) {
fgBucketGenBasePath(&my_index, scene_path);
index = fgBucketGenIndex(&my_index);
sprintf(file, "%s/%s/%ld.1.east", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&east_index, scene_path);
index = fgBucketGenIndex(&east_index);
sprintf(file, "%s/%s/%ld.1.west", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( strcmp(ext, ".body") == 0 ) {
fgBucketGenBasePath(&my_index, scene_path);
index = fgBucketGenIndex(&my_index);
sprintf(file, "%s/%s/%ld.1.body", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
return(0);
}
// my custom file opening routine ... don't open if a shared edge or
// vertex alread exists
FILE *my_open(char *basename, char *basepath, char *ext) {
FILE *fp;
char filename[256];
// check if a shared object already exists
if ( shared_object_exists(basepath, ext, filename) ) {
// not an actual file open error, but we've already got the
// shared edge, so we don't want to create another one
fp = fopen(filename, "r");
printf("Opening %s\n", filename);
return(fp);
} else {
// open the file
printf("not opening\n");
return(NULL);
}
}
// given a file pointer, read all the gdn (geodetic nodes from it.)
// The specified offset values (in arcsec) are used to overlap the
// edges of the tile slightly to cover gaps induced by floating point
// precision problems. 1 arcsec == about 100 feet so 0.01 arcsec ==
// about 1 foot
void read_nodes(FILE *fp, double offset_lon, double offset_lat) {
double n[3];
char line[256];
int ex_index;
offset_lon = offset_lat = 0.0;
while ( fgets(line, 250, fp) != NULL ) {
if ( strncmp(line, "gdn ", 4) == 0 ) {
sscanf(line, "gdn %lf %lf %lf\n", &n[0], &n[1], &n[2]);
ex_index = is_extra_node(n);
if ( ex_index == 0 ) {
// not an extra node
nodes[nodecount][0] = n[0] + offset_lon;
nodes[nodecount][1] = n[1] + offset_lat;
nodes[nodecount][2] = n[2];
// printf("read_nodes(%d) %.2f %.2f %.2f %s", nodecount,
// nodes[nodecount][0], nodes[nodecount][1],
// nodes[nodecount][2], line);
nodecount++;
} else {
// is an extra node
printf("found extra node %.2f %.2f %.2f\n", n[0], n[1], n[2]);
// preserve the DEM altitude for now
exnodes[ex_index][2] = n[2];
}
}
}
}
// load in nodes from the various split and shared pieces to
// reconstruct a tile
void build_node_list(char *basename, char *basepath) {
char exfile[256];
FILE *ne, *nw, *se, *sw, *north, *south, *east, *west, *body;
// load extra nodes if they exist
strcpy(exfile, basename);
strcat(exfile, ".node.ex");
read_extra_nodes(exfile);
ne = my_open(basename, basepath, ".ne");
read_nodes(ne, OFFSET_LON, OFFSET_LAT);
fclose(ne);
nw = my_open(basename, basepath, ".nw");
read_nodes(nw, -1.0 * OFFSET_LON, OFFSET_LAT);
fclose(nw);
se = my_open(basename, basepath, ".se");
read_nodes(se, OFFSET_LON, -1.0 * OFFSET_LAT);
fclose(se);
sw = my_open(basename, basepath, ".sw");
read_nodes(sw, -1.0 * OFFSET_LON, -1.0 * OFFSET_LAT);
fclose(sw);
north = my_open(basename, basepath, ".north");
read_nodes(north, 0.0, OFFSET_LAT);
fclose(north);
south = my_open(basename, basepath, ".south");
read_nodes(south, 0.0, -1.0 * OFFSET_LAT);
fclose(south);
east = my_open(basename, basepath, ".east");
read_nodes(east, OFFSET_LON, 0.0);
fclose(east);
west = my_open(basename, basepath, ".west");
read_nodes(west, -1.0 * OFFSET_LON, 0.0);
fclose(west);
body = my_open(basename, basepath, ".body");
read_nodes(body, 0.0, 0.0);
fclose(body);
}
// dump in WaveFront .obj format
void dump_nodes(char *basename) {
char file[256];
FILE *fd;
int i;
// generate output file name
strcpy(file, basename);
// len = strlen(file);
// file[len-2] = '\0';
strcat(file, ".node");
// dump vertices
printf("Creating node file: %s\n", file);
printf(" writing vertices in .node format.\n");
fd = fopen(file, "w");
fprintf(fd, "%d 2 1 0\n", excount + nodecount);
// now write out extra node data
for ( i = 1; i <= excount; i++ ) {
fprintf(fd, "%d %.2f %.2f %.2f 0\n",
i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
}
// now write out actual node data
for ( i = 0; i < nodecount; i++ ) {
fprintf(fd, "%d %.2f %.2f %.2f 0\n", excount + i + 1,
nodes[i][0], nodes[i][1], nodes[i][2]);
}
fclose(fd);
}
int main(int argc, char **argv) {
char basename[256], basepath[256], temp[256];
long int tmp_index;
int len;
// derive base name
strcpy(basename, argv[1]);
len = strlen(basename);
// find the base path of the file
extract_path(basename, basepath);
extract_path(basepath, basepath);
extract_path(basepath, basepath);
printf("%s\n", basepath);
// find the index of the current file
extract_file(basename, temp);
// len = strlen(temp);
// if ( len >= 2 ) {
// temp[len-2] = '\0';
// }
tmp_index = atoi(temp);
printf("%ld\n", tmp_index);
fgBucketParseIndex(tmp_index, &my_index);
printf("bucket = %d %d %d %d\n",
my_index.lon, my_index.lat, my_index.x, my_index.y);
// generate the indexes of the neighbors
fgBucketOffset(&my_index, &ne_index, 1, 1);
fgBucketOffset(&my_index, &nw_index, -1, 1);
fgBucketOffset(&my_index, &se_index, 1, -1);
fgBucketOffset(&my_index, &sw_index, -1, -1);
fgBucketOffset(&my_index, &north_index, 0, 1);
fgBucketOffset(&my_index, &south_index, 0, -1);
fgBucketOffset(&my_index, &east_index, 1, 0);
fgBucketOffset(&my_index, &west_index, -1, 0);
// printf("Corner indexes = %ld %ld %ld %ld\n",
// ne_index, nw_index, sw_index, se_index);
// printf("Edge indexes = %ld %ld %ld %ld\n",
// north_index, south_index, east_index, west_index);
// load the input data files
build_node_list(basename, basepath);
// dump in WaveFront .obj format
dump_nodes(basename);
return(0);
}
// $Log$
// Revision 1.3 1998/11/02 18:25:40 curt
// Check for __CYGWIN__ (b20) as well as __CYGWIN32__ (pre b20 compilers)
// Other misc. tweaks.
//
// Revision 1.2 1998/09/25 19:38:01 curt
// Minor tweaks so that this actually compiles.
//
// Revision 1.1 1998/09/25 19:35:29 curt
// Renamed assemtris.[ch] to assemtris.[ch]xx
//
// Revision 1.13 1998/09/21 20:56:30 curt
// Changes to avoid setting airport area nodes back to their original
// elevations if they have been changed.
//
//
// Revision 1.12 1998/09/09 16:24:51 curt
// Fixed a bug in the handling of exclude files which was causing
// a crash by calling fclose() on an invalid file handle.
// Removed overlapping offsets.
//
// Revision 1.11 1998/08/06 12:47:59 curt
// Removed overlap in tiles as a test.
//
// Revision 1.10 1998/07/21 04:34:20 curt
// Mods to handle extra nodes (i.e. preserve cutouts).
//
// Revision 1.9 1998/07/04 00:55:39 curt
// typedef'd struct fgBUCKET.
//
// Revision 1.8 1998/06/01 17:58:19 curt
// Added a slight border overlap to try to minimize pixel wide gaps between
// tiles due to round off error. This is not a perfect solution, but helps.
//
// Revision 1.7 1998/04/14 02:26:00 curt
// Code reorganizations. Added a Lib/ directory for more general libraries.
//
// Revision 1.6 1998/04/08 22:54:58 curt
// Adopted Gnu automake/autoconf system.
//
// Revision 1.5 1998/03/03 16:00:52 curt
// More c++ compile tweaks.
//
// Revision 1.4 1998/01/31 00:41:23 curt
// Made a few changes converting floats to doubles.
//
// Revision 1.3 1998/01/27 18:37:00 curt
// Lots of updates to get back in sync with changes made over in .../Src/
//
// Revision 1.2 1998/01/15 21:33:36 curt
// Assembling triangles and building a new .node file with the proper shared
// vertices now works. Now we just have to use the shared normals and we'll
// be all set.
//
// Revision 1.1 1998/01/15 02:45:26 curt
// Initial revision.
//

View file

@ -0,0 +1,51 @@
// splittris.hxx -- reassemble the pieces produced by splittris
//
// Written by Curtis Olson, started January 1998.
//
// Copyright (C) 1997 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifndef ASSEMTRIS_H
#define ASSEMTRIS_H
#include <stdio.h>
#include <string.h>
#define MAX_NODES 200000
#define MAX_TRIS 400000
#endif // SPLITTRIS_H
// $Log$
// Revision 1.2 1998/09/25 19:38:03 curt
// Minor tweaks so that this actually compiles.
//
// Revision 1.1 1998/09/25 19:35:31 curt
// Renamed assemtris.[ch] to assemtris.[ch]xx
//
// Revision 1.1 1998/01/15 02:45:26 curt
// Initial revision.
//

View file

@ -0,0 +1,13 @@
# The "checkoutlist" file is used to support additional version controlled
# administrative files in $CVSROOT/CVSROOT, such as template files.
#
# The first entry on a line is a filename which will be checked out from
# the corresponding RCS file in the $CVSROOT/CVSROOT directory.
# The remainder of the line is an error message to use if the file cannot
# be checked out.
#
# File format:
#
# [<whitespace>]<filename><whitespace><error message><end-of-line>
#
# comment lines begin with '#'

15
Tools/CVSROOT/commitinfo Normal file
View file

@ -0,0 +1,15 @@
# The "commitinfo" file is used to control pre-commit checks.
# The filter on the right is invoked with the repository and a list
# of files to check. A non-zero exit of the filter program will
# cause the commit to be aborted.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being committed to, relative
# to the $CVSROOT. For the first match that is found, then the remainder
# of the line is the name of the filter to run.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".

22
Tools/CVSROOT/cvswrappers Normal file
View file

@ -0,0 +1,22 @@
# This file describes wrappers and other binary files to CVS.
#
# Wrappers are the concept where directories of files are to be
# treated as a single file. The intended use is to wrap up a wrapper
# into a single tar such that the tar archive can be treated as a
# single binary file in CVS.
#
# To solve the problem effectively, it was also necessary to be able to
# prevent rcsmerge from merging these files.
#
# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
#
# wildcard [option value][option value]...
#
# where option is one of
# -f from cvs filter value: path to filter
# -t to cvs filter value: path to filter
# -m update methodology value: MERGE or COPY
#
# and value is a single-quote delimited value.
#
# For example:

21
Tools/CVSROOT/editinfo Normal file
View file

@ -0,0 +1,21 @@
# The "editinfo" file is used to allow verification of logging
# information. It works best when a template (as specified in the
# rcsinfo file) is provided for the logging procedure. Given a
# template with locations for, a bug-id number, a list of people who
# reviewed the code before it can be checked in, and an external
# process to catalog the differences that were code reviewed, the
# following test can be applied to the code:
#
# Making sure that the entered bug-id number is correct.
# Validating that the code that was reviewed is indeed the code being
# checked in (using the bug-id number or a seperate review
# number to identify this particular code set.).
#
# If any of the above test failed, then the commit would be aborted.
#
# Actions such as mailing a copy of the report to each reviewer are
# better handled by an entry in the loginfo file.
#
# One thing that should be noted is the the ALL keyword is not
# supported. There can be only one entry that matches a given
# repository.

19
Tools/CVSROOT/loginfo Normal file
View file

@ -0,0 +1,19 @@
# The "loginfo" file is used to control where "cvs commit" log information is
# sent. The first entry on a line is a regular expression which is tested
# against the directory that the change is being made to, relative to the
# $CVSROOT. For the first match that is found, the remainder of the line is a
# filter program that should expect log information on its standard input
#
# If the repository name does not match any of the regular expressions in the
# first field of this file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".
#
# The filter program may use one and only one "%s" modifier (ala printf). If
# such a "%s" is specified in the filter program, a brief title is included
# (as one argument, enclosed in single quotes) showing the relative directory
# name and listing the modified file names.
#
# For example:
#DEFAULT (echo ""; who am i; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog

26
Tools/CVSROOT/modules Normal file
View file

@ -0,0 +1,26 @@
# Three different line formats are valid:
# key -a aliases...
# key [options] directory
# key [options] directory files...
#
# Where "options" are composed of:
# -i prog Run "prog" on "cvs commit" from top-level of module.
# -o prog Run "prog" on "cvs checkout" of module.
# -e prog Run "prog" on "cvs export" of module.
# -t prog Run "prog" on "cvs rtag" of module.
# -u prog Run "prog" on "cvs update" of module.
# -d dir Place module in directory "dir" instead of module name.
# -l Top-level directory only -- do not recurse.
#
# NOTE: If you change any of the "Run" options above, you'll have to
# release and re-checkout any working directories of these modules.
#
# And "directory" is a path to a directory relative to $CVSROOT.
#
# The "-a" option specifies an alias. An alias is interpreted as if
# everything on the right of the "-a" had been typed on the command line.
#
# You can encode a module within a module by using the special '&'
# character to interpose another module into the current module. This
# can be useful for creating a module that consists of many directories
# spread out over the entire source repository.

12
Tools/CVSROOT/notify Normal file
View file

@ -0,0 +1,12 @@
# The "notify" file controls where notifications from watches set by
# "cvs watch add" or "cvs edit" are sent. The first entry on a line is
# a regular expression which is tested against the directory that the
# change is being made to, relative to the $CVSROOT. If it matches,
# then the remainder of the line is a filter program that should contain
# one occurrence of %s for the user to notify, and information on its
# standard input.
#
# "ALL" or "DEFAULT" can be used in place of the regular expression.
#
# For example:
#ALL mail %s -s "CVS notification"

13
Tools/CVSROOT/rcsinfo Normal file
View file

@ -0,0 +1,13 @@
# The "rcsinfo" file is used to control templates with which the editor
# is invoked on commit and import.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being made to, relative to the
# $CVSROOT. For the first match that is found, then the remainder of the
# line is the name of the file that contains the template.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".

20
Tools/CVSROOT/taginfo Normal file
View file

@ -0,0 +1,20 @@
# The "taginfo" file is used to control pre-tag checks.
# The filter on the right is invoked with the following arguments:
#
# $1 -- tagname
# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d
# $3 -- repository
# $4-> file revision [file revision ...]
#
# A non-zero exit of the filter program will cause the tag to be aborted.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being committed to, relative
# to the $CVSROOT. For the first match that is found, then the remainder
# of the line is the name of the filter to run.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".

16
Tools/Clipper/Makefile.am Normal file
View file

@ -0,0 +1,16 @@
noinst_LIBRARIES = libClipper.a
libClipper_a_SOURCES = clipper.cxx clipper.hxx
bin_PROGRAMS = testclipper
testclipper_SOURCES = testclipper.cxx
testclipper_LDADD = $(top_builddir)/Tools/Construct/Clipper/libClipper.a \
$(top_builddir)/Tools/Lib/Polygon/libPolygon.a \
$(top_builddir)/Lib/Debug/libDebug.a \
$(top_builddir)/Lib/Misc/libMisc.a \
$(top_builddir)/Lib/zlib/libz.a \
-lgfc -lgpc
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib

304
Tools/Clipper/clipper.cxx Normal file
View file

@ -0,0 +1,304 @@
// clipper.cxx -- top level routines to take a series of arbitrary areas and
// produce a tight fitting puzzle pieces that combine to make a
// tile
//
// Written by Curtis Olson, started February 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <Debug/logstream.hxx>
#include <Include/fg_constants.h>
#include <Misc/fgstream.hxx>
#include <Polygon/names.hxx>
#include "clipper.hxx"
// Constructor
FGClipper::FGClipper( void ) {
}
// Destructor
FGClipper::~FGClipper( void ) {
}
// Initialize Clipper (allocate and/or connect structures)
bool FGClipper::init() {
v_list.num_vertices = 0;
v_list.vertex = new gpc_vertex[FG_MAX_VERTICES];;
return true;
}
// Load a polygon definition file
bool FGClipper::load_polys(const string& path) {
string poly_name;
AreaType poly_type = DefaultArea;
int contours, count, i, j;
double startx, starty, x, y, lastx, lasty;
FG_LOG( FG_CLIPPER, FG_INFO, "Loading " << path << " ..." );
fg_gzifstream in( path );
if ( !in ) {
FG_LOG( FG_CLIPPER, FG_ALERT, "Cannot open file: " << path );
exit(-1);
}
gpc_polygon *poly = new gpc_polygon;
poly->num_contours = 0;
poly->contour = NULL;
in >> skipcomment;
while ( !in.eof() ) {
in >> poly_name;
cout << "poly name = " << poly_name << endl;
poly_type = get_area_type( poly_name );
cout << "poly type (int) = " << (int)poly_type << endl;
in >> contours;
cout << "num contours = " << contours << endl;
for ( i = 0; i < contours; ++i ) {
in >> count;
if ( count < 3 ) {
FG_LOG( FG_CLIPPER, FG_ALERT,
"Polygon with less than 3 data points." );
exit(-1);
}
in >> startx;
in >> starty;
v_list.vertex[0].x = startx;
v_list.vertex[0].y = starty;
FG_LOG( FG_CLIPPER, FG_BULK, "0 = "
<< startx << ", " << starty );
for ( j = 1; j < count - 1; ++j ) {
in >> x;
in >> y;
v_list.vertex[j].x = x;
v_list.vertex[j].y = y;
FG_LOG( FG_CLIPPER, FG_BULK, j << " = " << x << ", " << y );
}
v_list.num_vertices = count - 1;
in >> lastx;
in >> lasty;
if ( (fabs(startx - lastx) < FG_EPSILON)
&& (fabs(starty - lasty) < FG_EPSILON) ) {
// last point same as first, discard
} else {
v_list.vertex[count - 1].x = lastx;
v_list.vertex[count - 1].y = lasty;
++v_list.num_vertices;
FG_LOG( FG_CLIPPER, FG_BULK, count - 1 << " = "
<< lastx << ", " << lasty );
}
gpc_add_contour( poly, &v_list );
}
in >> skipcomment;
}
int area = (int)poly_type;
if ( area < FG_MAX_AREA_TYPES ) {
polys_in.polys[area].push_back(poly);
} else {
FG_LOG( FG_CLIPPER, FG_ALERT, "Polygon type out of range = "
<< (int)poly_type);
exit(-1);
}
// FILE *ofp= fopen("outfile", "w");
// gpc_write_polygon(ofp, &polys.landuse);
return true;
}
// Do actually clipping work
bool FGClipper::clip_all(const point2d& min, const point2d& max) {
gpc_polygon accum, result_union, tmp;
gpc_polygon *result_diff, *remains;
gpcpoly_iterator current, last;
FG_LOG( FG_CLIPPER, FG_INFO, "Running master clipper" );
accum.num_contours = 0;
cout << " (" << min.x << "," << min.y << ") ("
<< max.x << "," << max.y << ")" << endl;
// set up clipping tile
v_list.vertex[0].x = min.x;
v_list.vertex[0].y = min.y;
v_list.vertex[1].x = max.x;
v_list.vertex[1].y = min.y;
v_list.vertex[2].x = max.x;
v_list.vertex[2].y = max.y;
v_list.vertex[3].x = min.x;
v_list.vertex[3].y = max.y;
v_list.num_vertices = 4;
polys_in.safety_base.num_contours = 0;
polys_in.safety_base.contour = NULL;
gpc_add_contour( &polys_in.safety_base, &v_list );
// process polygons in priority order
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
// cout << "num polys of this type = "
// << polys_in.polys[i].size() << endl;
current = polys_in.polys[i].begin();
last = polys_in.polys[i].end();
for ( ; current != last; ++current ) {
FG_LOG( FG_CLIPPER, FG_DEBUG, get_area_name( (AreaType)i )
<< " = " << (*current)->contour->num_vertices );
#ifdef EXTRA_SAFETY_CLIP
// clip to base tile
gpc_polygon_clip(GPC_INT, *current, &polys_in.safety_base, &tmp);
#else
tmp = *current;
#endif
// clip current polygon against previous higher priority
// stuff
result_diff = new gpc_polygon;
result_diff->num_contours = 0;
result_diff->contour = NULL;
if ( accum.num_contours == 0 ) {
*result_diff = tmp;
result_union = tmp;
} else {
// cout << "DIFF: tmp.num_contours = " << tmp.num_contours
// << " accum.num_contours = " << accum.num_contours
// << endl;
// tmp output accum
FILE *ofp= fopen("tmp-debug", "w");
gpc_write_polygon(ofp, &tmp);
fclose(ofp);
ofp= fopen("accum-debug", "w");
gpc_write_polygon(ofp, &accum);
fclose(ofp);
gpc_polygon_clip(GPC_DIFF, &tmp, &accum, result_diff);
gpc_polygon_clip(GPC_UNION, &tmp, &accum, &result_union);
}
/*
cout << "original contours = " << tmp.num_contours << endl;
for ( int j = 0; j < tmp.num_contours; j++ ) {
for (int k = 0;k < tmp.contour[j].num_vertices;k++ ) {
cout << tmp.contour[j].vertex[k].x << ","
<< tmp.contour[j].vertex[k].y << endl;
}
}
cout << "clipped contours = " << result_diff->num_contours << endl;
for ( int j = 0; j < result_diff->num_contours; j++ ) {
for (int k = 0;k < result_diff->contour[j].num_vertices;k++ ) {
cout << result_diff->contour[j].vertex[k].x << ","
<< result_diff->contour[j].vertex[k].y << endl;
}
}
*/
// only add to output list if the clip left us with a polygon
if ( result_diff->num_contours > 0 ) {
polys_clipped.polys[i].push_back(result_diff);
}
accum = result_union;
}
}
// finally, what ever is left over goes to base terrain
// clip to accum against original base tile
remains = new gpc_polygon;
remains->num_contours = 0;
remains->contour = NULL;
gpc_polygon_clip(GPC_DIFF, &polys_in.safety_base, &accum,
remains);
if ( remains->num_contours > 0 ) {
polys_clipped.polys[0].push_back(remains);
}
// tmp output accum
FILE *ofp= fopen("accum", "w");
gpc_write_polygon(ofp, &accum);
fclose(ofp);
// tmp output safety_base
ofp= fopen("remains", "w");
gpc_write_polygon(ofp, remains);
fclose(ofp);
return true;
}
// $Log$
// Revision 1.9 1999/03/31 23:46:38 curt
// Debuggin output tweaks.
//
// Revision 1.8 1999/03/30 23:49:22 curt
// Added some debugging output.
//
// Revision 1.7 1999/03/30 13:41:38 curt
// Working towards better handling of multi-contoured polygons.
//
// Revision 1.6 1999/03/27 05:20:53 curt
// Pass along default area explicitely to triangulator.
//
// Revision 1.5 1999/03/19 22:28:46 curt
// Only add non-null polygons to output list.
//
// Revision 1.4 1999/03/19 00:26:18 curt
// Fixed a clipping bug (polygons specified in wrong order).
// Touched up a few compiler warnings.
//
// Revision 1.3 1999/03/17 23:48:58 curt
// minor renaming and a bit of rearranging.
//
// Revision 1.2 1999/03/13 23:51:33 curt
// Renamed main.cxx to testclipper.cxx
// Converted clipper routines to a class FGClipper.
//
// Revision 1.1 1999/03/01 15:39:39 curt
// Initial revision.
//

129
Tools/Clipper/clipper.hxx Normal file
View file

@ -0,0 +1,129 @@
// clipper.hxx -- top level routines to take a series of arbitrary areas and
// produce a tight fitting puzzle pieces that combine to make a
// tile
//
// Written by Curtis Olson, started February 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifndef _CLIPPER_HXX
#define _CLIPPER_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <Include/compiler.h>
// include Generic Polygon Clipping Library
//
// http://www.cs.man.ac.uk/aig/staff/alan/software/
//
extern "C" {
#include <gpc.h>
}
#include STL_STRING
#include <vector>
FG_USING_STD(string);
FG_USING_STD(vector);
typedef vector < gpc_polygon * > gpcpoly_container;
typedef gpcpoly_container::iterator gpcpoly_iterator;
typedef gpcpoly_container::const_iterator const_gpcpoly_iterator;
#define FG_MAX_AREA_TYPES 20
#define EXTRA_SAFETY_CLIP
#define FG_MAX_VERTICES 100000
class point2d {
public:
double x, y;
};
class FGgpcPolyList {
public:
gpcpoly_container polys[FG_MAX_AREA_TYPES];
gpc_polygon safety_base;
};
class FGClipper {
private:
gpc_vertex_list v_list;
// static gpc_polygon poly;
FGgpcPolyList polys_in, polys_clipped;
public:
// Constructor
FGClipper( void );
// Destructor
~FGClipper( void );
// Initialize Clipper (allocate and/or connect structures)
bool init();
// Load a polygon definition file
bool load_polys(const string& path);
// Do actually clipping work
bool clip_all(const point2d& min, const point2d& max);
// return output poly list
inline FGgpcPolyList get_polys_clipped() const { return polys_clipped; }
};
#endif // _CLIPPER_HXX
// $Log$
// Revision 1.5 1999/03/19 00:26:19 curt
// Fixed a clipping bug (polygons specified in wrong order).
// Touched up a few compiler warnings.
//
// Revision 1.4 1999/03/18 04:31:10 curt
// Let's not pass copies of huge structures on the stack ... ye might see a
// segfault ... :-)
//
// Revision 1.3 1999/03/17 23:48:59 curt
// minor renaming and a bit of rearranging.
//
// Revision 1.2 1999/03/13 23:51:34 curt
// Renamed main.cxx to testclipper.cxx
// Converted clipper routines to a class FGClipper.
//
// Revision 1.1 1999/03/01 15:39:39 curt
// Initial revision.
//

View file

@ -0,0 +1,119 @@
// main.cxx -- sample use of the clipper lib
//
// Written by Curtis Olson, started February 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <Debug/logstream.hxx>
#include <Bucket/newbucket.hxx>
#include "clipper.hxx"
int main( int argc, char **argv ) {
point2d global_min, global_max;
fglog().setLogLevels( FG_ALL, FG_DEBUG );
global_min.x = global_min.y = 200;
global_max.y = global_max.x = -200;
FGClipper clipper;
clipper.init();
if ( argc < 2 ) {
FG_LOG( FG_CLIPPER, FG_ALERT, "Usage: " << argv[0]
<< " file1 file2 ..." );
exit(-1);
}
// process all specified polygon files
for ( int i = 1; i < argc; i++ ) {
string full_path = argv[i];
// determine bucket for this polygon
int pos = full_path.rfind("/");
string file_name = full_path.substr(pos + 1);
cout << "file name = " << file_name << endl;
pos = file_name.find(".");
string base_name = file_name.substr(0, pos);
cout << "base_name = " << base_name << endl;
long int index;
sscanf( base_name.c_str(), "%ld", &index);
FGBucket b(index);
cout << "bucket = " << b << endl;
// calculate bucket dimensions
point2d c, min, max;
c.x = b.get_center_lon();
c.y = b.get_center_lat();
double span = bucket_span(c.y);
if ( (c.y >= -89.0) && (c.y < 89.0) ) {
min.x = c.x - span / 2.0;
max.x = c.x + span / 2.0;
min.y = c.y - FG_HALF_BUCKET_SPAN;
max.y = c.y + FG_HALF_BUCKET_SPAN;
} else if ( c.y < -89.0) {
min.x = -90.0;
max.x = -89.0;
min.y = -180.0;
max.y = 180.0;
} else if ( c.y >= 89.0) {
min.x = 89.0;
max.x = 90.0;
min.y = -180.0;
max.y = 180.0;
} else {
FG_LOG ( FG_GENERAL, FG_ALERT,
"Out of range latitude in clip_and_write_poly() = "
<< c.y );
}
if ( min.x < global_min.x ) global_min.x = min.x;
if ( min.y < global_min.y ) global_min.y = min.y;
if ( max.x > global_max.x ) global_max.x = max.x;
if ( max.y > global_max.y ) global_max.y = max.y;
// finally, load the polygon(s) from this file
clipper.load_polys( full_path );
}
// do the clipping
clipper.clip_all(global_min, global_max);
FG_LOG( FG_CLIPPER, FG_INFO, "finished main" );
return 0;
}
// $Log$
// Revision 1.1 1999/03/13 23:51:36 curt
// Renamed main.cxx to testclipper.cxx
// Converted clipper routines to a class FGClipper.
//
// Revision 1.1 1999/03/01 15:39:39 curt
// Initial revision.
//

View file

@ -0,0 +1,9 @@
noinst_LIBRARIES = libCombine.a
libCombine_a_SOURCES = genfans.cxx genfans.hxx
INCLUDES += \
-I$(top_builddir) \
-I$(top_builddir)/Lib \
-I$(top_builddir)/Tools/Lib \
-I$(top_builddir)/Tools/Construct

266
Tools/Combine/genfans.cxx Normal file
View file

@ -0,0 +1,266 @@
// genfans.cxx -- Combine individual triangles into more optimal fans.
//
// Written by Curtis Olson, started March 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include "genfans.hxx"
// make sure the list is expanded at least to hold "n" and then push
// "i" onto the back of the "n" list.
void FGGenFans::add_and_expand( reverse_list& by_node, int n, int i ) {
int_list empty;
int size = (int)by_node.size();
if ( size > n ) {
// ok
} else {
// cout << "capacity = " << by_node.capacity() << endl;
// cout << "size = " << size << " n = " << n
// << " need to push = " << n - size + 1 << endl;
for ( int i = 0; i < n - size + 1; ++i ) {
by_node.push_back(empty);
}
}
by_node[n].push_back(i);
}
// given an input triangle, shuffle nodes so that "center" is the
// first node, but maintain winding order.
static FGTriEle canonify( const FGTriEle& t, int center ) {
if ( t.get_n1() == center ) {
// already ok
return t;
} else if ( t.get_n2() == center ) {
return FGTriEle( t.get_n2(), t.get_n3(), t.get_n1(), 0.0 );
} else if ( t.get_n3() == center ) {
return FGTriEle( t.get_n3(), t.get_n1(), t.get_n2(), 0.0 );
} else {
cout << "ERROR, index doesn't refer to this triangle!!!" << endl;
exit(-1);
}
}
// returns a list of triangle indices
static int_list make_best_fan( const triele_list& master_tris,
const int center, const int_list& local_tris )
{
int_list best_result;
// try starting with each of local_tris to find the best fan
// arrangement
for ( int start = 0; start < (int)local_tris.size(); ++start ) {
// cout << "trying with first triangle = " << local_tris[start] << endl;
int_list tmp_result;
tmp_result.clear();
FGTriEle current_tri;
FGTriEle test;
current_tri = canonify( master_tris[local_tris[start]], center );
tmp_result.push_back( local_tris[start] );
// follow the ring
int next = -1;
bool matches = true;
while ( (next != start) && matches ) {
// find next triangle in ring
matches = false;
for ( int i = 0; i < (int)local_tris.size(); ++i ) {
test = canonify( master_tris[local_tris[i]], center );
if ( current_tri.get_n3() == test.get_n2() ) {
if ( i != start ) {
// cout << " next triangle = " << local_tris[i] << endl;
current_tri = test;
tmp_result.push_back( local_tris[i] );
matches = true;
next = i;
break;
}
}
}
}
if ( tmp_result.size() == local_tris.size() ) {
// we found a complete usage, no need to go on
// cout << "we found a complete usage, no need to go on" << endl;
best_result = tmp_result;
break;
} else if ( tmp_result.size() > best_result.size() ) {
// we found a better way to fan
// cout << "we found a better fan arrangement" << endl;
best_result = tmp_result;
}
}
return best_result;
}
static bool in_fan(int index, const int_list& fan ) {
const_int_list_iterator current = fan.begin();
const_int_list_iterator last = fan.end();
for ( ; current != last; ++current ) {
if ( index == *current ) {
return true;
}
}
return false;
}
// recursive build fans from triangle list
fan_list FGGenFans::greedy_build( triele_list tris ) {
cout << "starting greedy build of fans" << endl;
fans.clear();
while ( ! tris.empty() ) {
// cout << "building reverse_list" << endl;
reverse_list by_node;
by_node.clear();
// traverse the triangle list and for each node, build a list of
// triangles that attach to it.
for ( int i = 0; i < (int)tris.size(); ++i ) {
int n1 = tris[i].get_n1();
int n2 = tris[i].get_n2();
int n3 = tris[i].get_n3();
add_and_expand( by_node, n1, i );
add_and_expand( by_node, n2, i );
add_and_expand( by_node, n3, i );
}
// find the node in the tris list that attaches to the most
// triangles
// cout << "find most connected node" << endl;
int_list biggest_group;
reverse_list_iterator r_current = by_node.begin();
reverse_list_iterator r_last = by_node.end();
int index = 0;
int counter = 0;
for ( ; r_current != r_last; ++r_current ) {
if ( r_current->size() > biggest_group.size() ) {
biggest_group = *r_current;
index = counter;
}
++counter;
}
// cout << "triangle pool = " << tris.size() << endl;
// cout << "biggest_group = " << biggest_group.size() << endl;
// cout << "center node = " << index << endl;
// make the best fan we can out of this group
// cout << "before make_best_fan()" << endl;
int_list best_fan = make_best_fan( tris, index, biggest_group );
// cout << "after make_best_fan()" << endl;
// generate point form of best_fan
int_list node_list;
node_list.clear();
int_list_iterator i_start = best_fan.begin();
int_list_iterator i_current = i_start;
int_list_iterator i_last = best_fan.end();
for ( ; i_current != i_last; ++i_current ) {
FGTriEle t = canonify( tris[*i_current], index );
if ( i_start == i_current ) {
node_list.push_back( t.get_n1() );
node_list.push_back( t.get_n2() );
}
node_list.push_back( t.get_n3() );
}
// cout << "best list size = " << node_list.size() << endl;
// add this fan to the fan list
fans.push_back( node_list );
// delete the triangles in best_fan out of tris and repeat
triele_list_iterator t_current = tris.begin();
triele_list_iterator t_last = tris.end();
counter = 0;
while ( t_current != t_last ) {
if ( in_fan(counter, best_fan) ) {
// cout << "erasing "
// << t_current->get_n1() << ","
// << t_current->get_n2() << ","
// << t_current->get_n3()
// << " from master tri pool"
// << endl;
tris.erase( t_current );
} else {
++t_current;
}
++counter;
}
}
cout << "end of greedy build of fans" << endl;
cout << "average fan size = " << ave_size() << endl;
return fans;
}
// report average fan size
double FGGenFans::ave_size() {
double sum = 0.0;
fan_list_iterator current = fans.begin();
fan_list_iterator last = fans.end();
for ( ; current != last; ++current ) {
sum += current->size();
}
return sum / (double)fans.size();
}
// $Log$
// Revision 1.6 1999/04/05 02:16:02 curt
// Fixed a compiler warning.
//
// Revision 1.5 1999/03/31 23:46:49 curt
// Debugging output tweaks.
//
// Revision 1.4 1999/03/31 13:26:39 curt
// Debugging output tweeaks.
//
// Revision 1.3 1999/03/31 05:35:04 curt
// Fixed bug in genfans (deleting the wrong triangles from the available pool.)
//
// Revision 1.2 1999/03/30 23:50:15 curt
// Fannifier is clearly bugging ... working on debugging it. I suspect there
// is a problem related to deleting triangles from the triangle pool as they
// are combined into fans.
//
// Revision 1.1 1999/03/29 13:08:35 curt
// Initial revision.
//

85
Tools/Combine/genfans.hxx Normal file
View file

@ -0,0 +1,85 @@
// genfans.hxx -- Combine individual triangles into more optimal fans.
//
// Written by Curtis Olson, started March 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifndef _GENFANS_HXX
#define _GENFANS_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <Include/compiler.h>
#include <vector>
#include <Main/construct_types.hxx>
#include <Triangulate/trieles.hxx>
FG_USING_STD(vector);
typedef vector < int_list > fan_list;
typedef fan_list::iterator fan_list_iterator;
typedef fan_list::const_iterator const_fan_list_iterator;
typedef vector < int_list > reverse_list;
typedef reverse_list::iterator reverse_list_iterator;
typedef reverse_list::const_iterator const_reverse_list_iterator;
class FGGenFans {
private:
fan_list fans;
// make sure the list is expanded at least to hold "n" and then
// push "i" onto the back of the "n" list.
void add_and_expand( reverse_list& by_node, int n, int i );
public:
// Constructor && Destructor
inline FGGenFans() { }
inline ~FGGenFans() { }
// recursive build fans from triangle list
// fan_list greedy_build( triele_list tris );
fan_list greedy_build( triele_list tris );
// report average fan size
double ave_size();
};
#endif // _GENFANS_HXX
// $Log$
// Revision 1.1 1999/03/29 13:08:35 curt
// Initial revision.
//

View file

@ -0,0 +1,7 @@
SUBDIRS = \
Array \
Clipper \
Combine \
GenOutput \
Triangulate \
Main

11
Tools/DEM/Makefile.am Normal file
View file

@ -0,0 +1,11 @@
noinst_LIBRARIES = libDEM.a
libDEM_a_SOURCES = dem.cxx dem.hxx
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
# We can't build this with "-O2" (optimization) since this causes a seg fault
# I haven't found a way to strip this out of the CXXFLAGS, so I'm just
# setting it to "-g"
# CXXFLAGS = -g

977
Tools/DEM/dem.cxx Normal file
View file

@ -0,0 +1,977 @@
// dem.cxx -- DEM management class
//
// Written by Curtis Olson, started March 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <Include/compiler.h>
#include <ctype.h> // isspace()
#include <stdlib.h> // atoi()
#include <math.h> // rint()
#include <stdio.h>
#include <string.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h> // stat()
#endif
#ifdef FG_HAVE_STD_INCLUDES
# include <cerrno>
#else
# include <errno.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h> // stat()
#endif
#include <Misc/fgstream.hxx>
#include <Misc/strutils.hxx>
#include <Include/fg_constants.h>
#include "dem.hxx"
#define MAX_EX_NODES 10000
#if 0
#ifdef WIN32
# ifdef __BORLANDC__
# include <dir.h>
# define MKDIR(a) mkdir(a)
# else
# define MKDIR(a) mkdir(a,S_IRWXU) // I am just guessing at this flag (NHV)
# endif // __BORLANDC__
#endif // WIN32
#endif //0
FGDem::FGDem( void ) {
// cout << "class FGDem CONstructor called." << endl;
dem_data = new float[DEM_SIZE_1][DEM_SIZE_1];
output_data = new float[DEM_SIZE_1][DEM_SIZE_1];
}
FGDem::FGDem( const string &file ) {
// cout << "class FGDem CONstructor called." << endl;
dem_data = new float[DEM_SIZE_1][DEM_SIZE_1];
output_data = new float[DEM_SIZE_1][DEM_SIZE_1];
FGDem::open(file);
}
// open a DEM file
int
FGDem::open ( const string& file ) {
// open input file (or read from stdin)
if ( file == "-" ) {
printf("Loading DEM data file: stdin\n");
// fd = stdin;
// fd = gzdopen(STDIN_FILENO, "r");
printf("Not yet ported ...\n");
return 0;
} else {
in = new fg_gzifstream( file );
if ( !(*in) ) {
cout << "Cannot open " << file << endl;
return 0;
}
cout << "Loading DEM data file: " << file << endl;
}
return 1;
}
// close a DEM file
int
FGDem::close () {
// the fg_gzifstream doesn't seem to have a close()
delete in;
return 1;
}
// return next token from input stream
string
FGDem::next_token() {
string token;
*in >> token;
// cout << " returning " + token + "\n";
return token;
}
// return next integer from input stream
int
FGDem::next_int() {
int result;
*in >> result;
return result;
}
// return next double from input stream
double
FGDem::next_double() {
double result;
*in >> result;
return result;
}
// return next exponential num from input stream
double
FGDem::next_exp() {
string token;
token = next_token();
const char* p = token.c_str();
char buf[64];
char* bp = buf;
for ( ; *p != 0; ++p )
{
if ( *p == 'D' )
*bp++ = 'E';
else
*bp++ = *p;
}
*bp = 0;
return ::atof( buf );
}
// read and parse DEM "A" record
int
FGDem::read_a_record() {
int i, inum;
double dnum;
string name, token;
char c;
// get the name field (144 characters)
for ( i = 0; i < 144; i++ ) {
in->get(c);
name += c;
}
// clean off the trailing whitespace
name = trim(name);
cout << " Quad name field: " << name << endl;
// DEM level code, 3 reflects processing by DMA
inum = next_int();
cout << " DEM level code = " << inum << "\n";
if ( inum > 3 ) {
return 0;
}
// Pattern code, 1 indicates a regular elevation pattern
inum = next_int();
cout << " Pattern code = " << inum << "\n";
// Planimetric reference system code, 0 indicates geographic
// coordinate system.
inum = next_int();
cout << " Planimetric reference code = " << inum << "\n";
// Zone code
inum = next_int();
cout << " Zone code = " << inum << "\n";
// Map projection parameters (ignored)
for ( i = 0; i < 15; i++ ) {
dnum = next_exp();
// printf("%d: %f\n",i,dnum);
}
// Units code, 3 represents arc-seconds as the unit of measure for
// ground planimetric coordinates throughout the file.
inum = next_int();
if ( inum != 3 ) {
cout << " Unknown (X,Y) units code = " << inum << "!\n";
exit(-1);
}
// Units code; 2 represents meters as the unit of measure for
// elevation coordinates throughout the file.
inum = next_int();
if ( inum != 2 ) {
cout << " Unknown (Z) units code = " << inum << "!\n";
exit(-1);
}
// Number (n) of sides in the polygon which defines the coverage of
// the DEM file (usually equal to 4).
inum = next_int();
if ( inum != 4 ) {
cout << " Unknown polygon dimension = " << inum << "!\n";
exit(-1);
}
// Ground coordinates of bounding box in arc-seconds
dem_x1 = originx = next_exp();
dem_y1 = originy = next_exp();
cout << " Origin = (" << originx << "," << originy << ")\n";
dem_x2 = next_exp();
dem_y2 = next_exp();
dem_x3 = next_exp();
dem_y3 = next_exp();
dem_x4 = next_exp();
dem_y4 = next_exp();
// Minimum/maximum elevations in meters
dem_z1 = next_exp();
dem_z2 = next_exp();
cout << " Elevation range " << dem_z1 << " to " << dem_z2 << "\n";
// Counterclockwise angle from the primary axis of ground
// planimetric referenced to the primary axis of the DEM local
// reference system.
token = next_token();
// Accuracy code; 0 indicates that a record of accuracy does not
// exist and that no record type C will follow.
// DEM spacial resolution. Usually (3,3,1) (3,6,1) or (3,9,1)
// depending on latitude
// I will eventually have to do something with this for data at
// higher latitudes */
token = next_token();
cout << " accuracy & spacial resolution string = " << token << endl;
i = token.length();
cout << " length = " << i << "\n";
inum = atoi( token.substr( 0, i - 36 ) );
row_step = atof( token.substr( i - 24, 12 ) );
col_step = atof( token.substr( i - 36, 12 ) );
cout << " Accuracy code = " << inum << "\n";
cout << " column step = " << col_step <<
" row step = " << row_step << "\n";
// dimension of arrays to follow (1)
token = next_token();
// number of profiles
dem_num_profiles = cols = next_int();
cout << " Expecting " << dem_num_profiles << " profiles\n";
return 1;
}
// read and parse DEM "B" record
void
FGDem::read_b_record( ) {
string token;
int i;
// row / column id of this profile
prof_row = next_int();
prof_col = next_int();
// printf("col id = %d row id = %d\n", prof_col, prof_row);
// Number of columns and rows (elevations) in this profile
prof_num_rows = rows = next_int();
prof_num_cols = next_int();
// printf(" profile num rows = %d\n", prof_num_rows);
// Ground planimetric coordinates (arc-seconds) of the first
// elevation in the profile
prof_x1 = next_exp();
prof_y1 = next_exp();
// printf(" Starting at %.2f %.2f\n", prof_x1, prof_y1);
// Elevation of local datum for the profile. Always zero for
// 1-degree DEM, the reference is mean sea level.
token = next_token();
// Minimum and maximum elevations for the profile.
token = next_token();
token = next_token();
// One (usually) dimensional array (prof_num_cols,1) of elevations
for ( i = 0; i < prof_num_rows; i++ ) {
prof_data = next_int();
dem_data[cur_col][i] = (float)prof_data;
}
}
// parse dem file
int
FGDem::parse( ) {
int i;
cur_col = 0;
if ( !read_a_record() ) {
return(0);
}
for ( i = 0; i < dem_num_profiles; i++ ) {
// printf("Ready to read next b record\n");
read_b_record();
cur_col++;
if ( cur_col % 100 == 0 ) {
cout << " loaded " << cur_col << " profiles of data\n";
}
}
cout << " Done parsing\n";
return 1;
}
// write out the area of data covered by the specified bucket. Data
// is written out column by column starting at the lower left hand
// corner.
int
FGDem::write_area( const string& root, FGBucket& b, bool compress ) {
// calculate some boundaries
double min_x = ( b.get_center_lon() - 0.5 * b.get_width() ) * 3600.0;
double max_x = ( b.get_center_lon() + 0.5 * b.get_width() ) * 3600.0;
double min_y = ( b.get_center_lat() - 0.5 * b.get_height() ) * 3600.0;
double max_y = ( b.get_center_lat() + 0.5 * b.get_height() ) * 3600.0;
cout << b << endl;
cout << "width = " << b.get_width() << " height = " << b.get_height()
<< endl;
int start_x = (int)((min_x - originx) / col_step);
int span_x = (int)(b.get_width() * 3600.0 / col_step);
int start_y = (int)((min_y - originy) / row_step);
int span_y = (int)(b.get_height() * 3600.0 / row_step);
cout << "start_x = " << start_x << " span_x = " << span_x << endl;
cout << "start_y = " << start_y << " span_y = " << span_y << endl;
// Do a simple sanity checking. But, please, please be nice to
// this write_area() routine and feed it buckets that coincide
// well with the underlying grid structure and spacing.
if ( ( min_x < originx )
|| ( max_x > originx + cols * col_step )
|| ( min_y < originy )
|| ( max_y > originy + rows * row_step ) ) {
cout << " ERROR: bucket at least partially outside DEM data range!" <<
endl;
return 0;
}
// generate output file name
string base = b.gen_base_path();
string path = root + "/Scenery/" + base;
string command = "mkdir -p " + path;
system( command.c_str() );
string demfile = path + "/" + b.gen_index_str() + ".dem";
cout << "demfile = " << demfile << endl;
// write the file
FILE *fp;
if ( (fp = fopen(demfile.c_str(), "w")) == NULL ) {
cout << "cannot open " << demfile << " for writing!" << endl;
exit(-1);
}
fprintf( fp, "%d %d\n", (int)min_x, (int)min_y );
fprintf( fp, "%d %d %d %d\n", span_x + 1, (int)col_step,
span_y + 1, (int)row_step );
for ( int i = start_x; i <= start_x + span_x; ++i ) {
for ( int j = start_y; j <= start_y + span_y; ++j ) {
fprintf( fp, "%d ", (int)dem_data[i][j] );
}
fprintf( fp, "\n" );
}
fclose(fp);
if ( compress ) {
string command = "gzip --best -f " + demfile;
system( command.c_str() );
}
return 1;
}
#if 0
// return the current altitude based on grid data. We should rewrite
// this to interpolate exact values, but for now this is good enough
double FGDem::interpolate_altitude( double lon, double lat ) {
// we expect incoming (lon,lat) to be in arcsec for now
double xlocal, ylocal, dx, dy, zA, zB, elev;
int x1, x2, x3, y1, y2, y3;
float z1, z2, z3;
int xindex, yindex;
/* determine if we are in the lower triangle or the upper triangle
______
| /|
| / |
| / |
|/ |
------
then calculate our end points
*/
xlocal = (lon - originx) / col_step;
ylocal = (lat - originy) / row_step;
xindex = (int)(xlocal);
yindex = (int)(ylocal);
// printf("xindex = %d yindex = %d\n", xindex, yindex);
if ( xindex + 1 == cols ) {
xindex--;
}
if ( yindex + 1 == rows ) {
yindex--;
}
if ( (xindex < 0) || (xindex + 1 >= cols) ||
(yindex < 0) || (yindex + 1 >= rows) ) {
return(-9999);
}
dx = xlocal - xindex;
dy = ylocal - yindex;
if ( dx > dy ) {
// lower triangle
// printf(" Lower triangle\n");
x1 = xindex;
y1 = yindex;
z1 = dem_data[x1][y1];
x2 = xindex + 1;
y2 = yindex;
z2 = dem_data[x2][y2];
x3 = xindex + 1;
y3 = yindex + 1;
z3 = dem_data[x3][y3];
// printf(" dx = %.2f dy = %.2f\n", dx, dy);
// printf(" (x1,y1,z1) = (%d,%d,%d)\n", x1, y1, z1);
// printf(" (x2,y2,z2) = (%d,%d,%d)\n", x2, y2, z2);
// printf(" (x3,y3,z3) = (%d,%d,%d)\n", x3, y3, z3);
zA = dx * (z2 - z1) + z1;
zB = dx * (z3 - z1) + z1;
// printf(" zA = %.2f zB = %.2f\n", zA, zB);
if ( dx > FG_EPSILON ) {
elev = dy * (zB - zA) / dx + zA;
} else {
elev = zA;
}
} else {
// upper triangle
// printf(" Upper triangle\n");
x1 = xindex;
y1 = yindex;
z1 = dem_data[x1][y1];
x2 = xindex;
y2 = yindex + 1;
z2 = dem_data[x2][y2];
x3 = xindex + 1;
y3 = yindex + 1;
z3 = dem_data[x3][y3];
// printf(" dx = %.2f dy = %.2f\n", dx, dy);
// printf(" (x1,y1,z1) = (%d,%d,%d)\n", x1, y1, z1);
// printf(" (x2,y2,z2) = (%d,%d,%d)\n", x2, y2, z2);
// printf(" (x3,y3,z3) = (%d,%d,%d)\n", x3, y3, z3);
zA = dy * (z2 - z1) + z1;
zB = dy * (z3 - z1) + z1;
// printf(" zA = %.2f zB = %.2f\n", zA, zB );
// printf(" xB - xA = %.2f\n", col_step * dy / row_step);
if ( dy > FG_EPSILON ) {
elev = dx * (zB - zA) / dy + zA;
} else {
elev = zA;
}
}
return(elev);
}
// Use least squares to fit a simpler data set to dem data
void FGDem::fit( double error, FGBucket& p ) {
double x[DEM_SIZE_1], y[DEM_SIZE_1];
double m, b, ave_error, max_error;
double cury, lasty;
int n, row, start, end;
int colmin, colmax, rowmin, rowmax;
bool good_fit;
// FILE *dem, *fit, *fit1;
printf("Initializing output mesh structure\n");
outputmesh_init();
// determine dimensions
colmin = p.get_x() * ( (cols - 1) / 8);
colmax = colmin + ( (cols - 1) / 8);
rowmin = p.get_y() * ( (rows - 1) / 8);
rowmax = rowmin + ( (rows - 1) / 8);
printf("Fitting region = %d,%d to %d,%d\n", colmin, rowmin, colmax, rowmax);
// include the corners explicitly
outputmesh_set_pt(colmin, rowmin, dem_data[colmin][rowmin]);
outputmesh_set_pt(colmin, rowmax, dem_data[colmin][rowmax]);
outputmesh_set_pt(colmax, rowmax, dem_data[colmax][rowmax]);
outputmesh_set_pt(colmax, rowmin, dem_data[colmax][rowmin]);
printf("Beginning best fit procedure\n");
for ( row = rowmin; row <= rowmax; row++ ) {
// fit = fopen("fit.dat", "w");
// fit1 = fopen("fit1.dat", "w");
start = colmin;
// printf(" fitting row = %d\n", row);
while ( start < colmax ) {
end = start + 1;
good_fit = true;
x[(end - start) - 1] = 0.0 + ( start * col_step );
y[(end - start) - 1] = dem_data[start][row];
while ( (end <= colmax) && good_fit ) {
n = (end - start) + 1;
// printf("Least square of first %d points\n", n);
x[end - start] = 0.0 + ( end * col_step );
y[end - start] = dem_data[end][row];
least_squares(x, y, n, &m, &b);
ave_error = least_squares_error(x, y, n, m, b);
max_error = least_squares_max_error(x, y, n, m, b);
/*
printf("%d - %d ave error = %.2f max error = %.2f y = %.2f*x + %.2f\n",
start, end, ave_error, max_error, m, b);
f = fopen("gnuplot.dat", "w");
for ( j = 0; j <= end; j++) {
fprintf(f, "%.2f %.2f\n", 0.0 + ( j * col_step ),
dem_data[row][j]);
}
for ( j = start; j <= end; j++) {
fprintf(f, "%.2f %.2f\n", 0.0 + ( j * col_step ),
dem_data[row][j]);
}
fclose(f);
printf("Please hit return: "); gets(junk);
*/
if ( max_error > error ) {
good_fit = false;
}
end++;
}
if ( !good_fit ) {
// error exceeded the threshold, back up
end -= 2; // back "end" up to the last good enough fit
n--; // back "n" up appropriately too
} else {
// we popped out of the above loop while still within
// the error threshold, so we must be at the end of
// the data set
end--;
}
least_squares(x, y, n, &m, &b);
ave_error = least_squares_error(x, y, n, m, b);
max_error = least_squares_max_error(x, y, n, m, b);
/*
printf("\n");
printf("%d - %d ave error = %.2f max error = %.2f y = %.2f*x + %.2f\n",
start, end, ave_error, max_error, m, b);
printf("\n");
fprintf(fit1, "%.2f %.2f\n", x[0], m * x[0] + b);
fprintf(fit1, "%.2f %.2f\n", x[end-start], m * x[end-start] + b);
*/
if ( start > colmin ) {
// skip this for the first line segment
cury = m * x[0] + b;
outputmesh_set_pt(start, row, (lasty + cury) / 2);
// fprintf(fit, "%.2f %.2f\n", x[0], (lasty + cury) / 2);
}
lasty = m * x[end-start] + b;
start = end;
}
/*
fclose(fit);
fclose(fit1);
dem = fopen("gnuplot.dat", "w");
for ( j = 0; j < DEM_SIZE_1; j++) {
fprintf(dem, "%.2f %.2f\n", 0.0 + ( j * col_step ),
dem_data[j][row]);
}
fclose(dem);
*/
// NOTICE, this is for testing only. This instance of
// output_nodes should be removed. It should be called only
// once at the end once all the nodes have been generated.
// newmesh_output_nodes(&nm, "mesh.node");
// printf("Please hit return: "); gets(junk);
}
// outputmesh_output_nodes(fg_root, p);
}
// Initialize output mesh structure
void FGDem::outputmesh_init( void ) {
int i, j;
for ( j = 0; j < DEM_SIZE_1; j++ ) {
for ( i = 0; i < DEM_SIZE_1; i++ ) {
output_data[i][j] = -9999.0;
}
}
}
// Get the value of a mesh node
double FGDem::outputmesh_get_pt( int i, int j ) {
return ( output_data[i][j] );
}
// Set the value of a mesh node
void FGDem::outputmesh_set_pt( int i, int j, double value ) {
// printf("Setting data[%d][%d] = %.2f\n", i, j, value);
output_data[i][j] = value;
}
// Write out a node file that can be used by the "triangle" program.
// Check for an optional "index.node.ex" file in case there is a .poly
// file to go along with this node file. Include these nodes first
// since they are referenced by position from the .poly file.
void FGDem::outputmesh_output_nodes( const string& fg_root, FGBucket& p )
{
double exnodes[MAX_EX_NODES][3];
struct stat stat_buf;
string dir;
char file[256], exfile[256];
#ifdef WIN32
char tmp_path[256];
#endif
string command;
FILE *fd;
long int index;
int colmin, colmax, rowmin, rowmax;
int i, j, count, excount, result;
// determine dimensions
colmin = p.get_x() * ( (cols - 1) / 8);
colmax = colmin + ( (cols - 1) / 8);
rowmin = p.get_y() * ( (rows - 1) / 8);
rowmax = rowmin + ( (rows - 1) / 8);
cout << " dumping region = " << colmin << "," << rowmin << " to " <<
colmax << "," << rowmax << "\n";
// generate the base directory
string base_path = p.gen_base_path();
cout << "fg_root = " << fg_root << " Base Path = " << base_path << endl;
dir = fg_root + "/Scenery/" + base_path;
cout << "Dir = " << dir << endl;
// stat() directory and create if needed
errno = 0;
result = stat(dir.c_str(), &stat_buf);
if ( result != 0 && errno == ENOENT ) {
cout << "Creating directory\n";
// #ifndef WIN32
command = "mkdir -p " + dir + "\n";
system( command.c_str() );
#if 0
// #else // WIN32
// Cygwin crashes when trying to output to node file
// explicitly making directory structure seems OK on Win95
extract_path (base_path, tmp_path);
dir = fg_root + "/Scenery";
if (my_mkdir ( dir.c_str() )) { exit (-1); }
dir = fg_root + "/Scenery/" + tmp_path;
if (my_mkdir ( dir.c_str() )) { exit (-1); }
dir = fg_root + "/Scenery/" + base_path;
if (my_mkdir ( dir.c_str() )) { exit (-1); }
// #endif // WIN32
#endif //0
} else {
// assume directory exists
}
// get index and generate output file name
index = p.gen_index();
sprintf(file, "%s/%ld.node", dir.c_str(), index);
// get (optional) extra node file name (in case there is matching
// .poly file.
strcpy(exfile, file);
strcat(exfile, ".ex");
// load extra nodes if they exist
excount = 0;
if ( (fd = fopen(exfile, "r")) != NULL ) {
int junki;
fscanf(fd, "%d %d %d %d", &excount, &junki, &junki, &junki);
if ( excount > MAX_EX_NODES - 1 ) {
printf("Error, too many 'extra' nodes, increase array size\n");
exit(-1);
} else {
printf(" Expecting %d 'extra' nodes\n", excount);
}
for ( i = 1; i <= excount; i++ ) {
fscanf(fd, "%d %lf %lf %lf\n", &junki,
&exnodes[i][0], &exnodes[i][1], &exnodes[i][2]);
printf("(extra) %d %.2f %.2f %.2f\n",
i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
}
fclose(fd);
}
printf("Creating node file: %s\n", file);
fd = fopen(file, "w");
// first count regular nodes to generate header
count = 0;
for ( j = rowmin; j <= rowmax; j++ ) {
for ( i = colmin; i <= colmax; i++ ) {
if ( output_data[i][j] > -9000.0 ) {
count++;
}
}
// printf(" count = %d\n", count);
}
fprintf(fd, "%d 2 1 0\n", count + excount);
// now write out extra node data
for ( i = 1; i <= excount; i++ ) {
fprintf(fd, "%d %.2f %.2f %.2f\n",
i, exnodes[i][0], exnodes[i][1], exnodes[i][2]);
}
// write out actual node data
count = excount + 1;
for ( j = rowmin; j <= rowmax; j++ ) {
for ( i = colmin; i <= colmax; i++ ) {
if ( output_data[i][j] > -9000.0 ) {
fprintf(fd, "%d %.2f %.2f %.2f\n",
count++,
originx + (double)i * col_step,
originy + (double)j * row_step,
output_data[i][j]);
}
}
// printf(" count = %d\n", count);
}
fclose(fd);
}
#endif
FGDem::~FGDem( void ) {
// printf("class FGDem DEstructor called.\n");
delete [] dem_data;
delete [] output_data;
}
// $Log$
// Revision 1.27 1999/03/25 19:04:36 curt
// Minor tweaks related to FGBucket usage.
//
// Revision 1.26 1999/03/13 17:40:37 curt
// Moved point interpolation and least squares fitting to contruction program
// area.
// Moved leastsqs.* to Lib/Math/
//
// Revision 1.25 1999/03/12 22:53:07 curt
// Added a routine to dump out the portion of the dem data covered by a
// specified bucket. Other changes related to needs of scenery tools overhaul.
//
// Revision 1.24 1999/03/11 23:31:56 curt
// Tweaks to use newbucket.hxx
//
// Revision 1.23 1999/03/10 01:09:12 curt
// Tweaks to go along with scenery tools overhaul.
// Added a new constructor that accepts the file name.
//
// Revision 1.22 1999/01/19 20:56:56 curt
// MacOS portability changes contributed by "Robert Puyol" <puyol@abvent.fr>
//
// Revision 1.21 1998/11/06 14:04:32 curt
// Changes due to updates in fgstream.
//
// Revision 1.20 1998/10/28 19:38:20 curt
// Elliminate some unnecessary win32 specific stuff (by Norman Vine)
//
// Revision 1.19 1998/10/22 21:59:19 curt
// Fixed a couple subtle bugs that resulted from some of my c++ conversions.
// One bug could cause a segfault on certain input, and the other bug could
// cause the whole procedure to go balistic and generate huge files (also only
// on rare input combinations.)
//
// Revision 1.18 1998/10/18 01:17:09 curt
// Point3D tweaks.
//
// Revision 1.17 1998/10/16 19:08:12 curt
// Portability updates from Bernie Bright.
//
// Revision 1.16 1998/10/02 21:41:39 curt
// Fixes for win32.
//
// Revision 1.15 1998/09/21 20:53:59 curt
// minor tweaks to clean a few additional things up after the rewrite.
//
// Revision 1.14 1998/09/19 17:59:45 curt
// Use c++ streams (fg_gzifstream). Also converted many character arrays to
// the string class.
//
// Revision 1.13 1998/09/09 16:24:04 curt
// Fixed a bug in the handling of exclude files which was causing
// a crash by calling fclose() on an invalid file handle.
//
// Revision 1.12 1998/08/24 20:03:31 curt
// Eliminated a possible memory overrun error.
// Use the proper free() rather than the incorrect delete().
//
// Revision 1.11 1998/07/20 12:46:11 curt
// When outputing to a .node file, first check for an optional
// "index.node.ex" file in case there is a .poly file to go along with this
// node file. Include these nodes first since they are referenced by position
// from the .poly file. This is my first pass at adding an area "cutout"
// feature to the terrain generation pipeline.
//
// Revision 1.10 1998/07/13 20:58:02 curt
// .
//
// Revision 1.9 1998/07/13 15:29:49 curt
// Added #ifdef HAVE_CONFIG_H
//
// Revision 1.8 1998/07/04 00:47:18 curt
// typedef'd struct fgBUCKET.
//
// Revision 1.7 1998/06/05 18:14:39 curt
// Abort out early when reading the "A" record if it doesn't look like
// a proper DEM file.
//
// Revision 1.6 1998/05/02 01:49:21 curt
// Fixed a bug where the wrong variable was being initialized.
//
// Revision 1.5 1998/04/25 15:00:32 curt
// Changed "r" to "rb" in gzopen() options. This fixes bad behavior in win32.
//
// Revision 1.4 1998/04/22 13:14:46 curt
// Fixed a bug in zlib usage.
//
// Revision 1.3 1998/04/18 03:53:05 curt
// Added zlib support.
//
// Revision 1.2 1998/04/14 02:43:27 curt
// Used "new" to auto-allocate large DEM parsing arrays in class constructor.
//
// Revision 1.1 1998/04/08 22:57:22 curt
// Adopted Gnu automake/autoconf system.
//
// Revision 1.3 1998/04/06 21:09:41 curt
// Additional win32 support.
// Fixed a bad bug in dem file parsing that was causing the output to be
// flipped about x = y.
//
// Revision 1.2 1998/03/23 20:35:41 curt
// Updated to use FG_EPSILON
//
// Revision 1.1 1998/03/19 02:54:47 curt
// Reorganized into a class lib called fgDEM.
//
// Revision 1.1 1998/03/19 01:46:28 curt
// Initial revision.
//

210
Tools/DEM/dem.hxx Normal file
View file

@ -0,0 +1,210 @@
// dem.hxx -- DEM management class
//
// Written by Curtis Olson, started March 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifndef _DEM_HXX
#define _DEM_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <Bucket/newbucket.hxx>
#include <Misc/fgstream.hxx>
#define DEM_SIZE 1200
#define DEM_SIZE_1 1201
class FGDem {
private:
// file pointer for input
// gzFile fd;
fg_gzifstream *in;
// coordinates (in arc seconds) of south west corner
double originx, originy;
// number of columns and rows
int cols, rows;
// Distance between column and row data points (in arc seconds)
double col_step, row_step;
// pointers to the actual grid data allocated here
float (*dem_data)[DEM_SIZE_1];
float (*output_data)[DEM_SIZE_1];
// Current "A" Record Information
char dem_description[80], dem_quadrangle[80];
double dem_x1, dem_y1, dem_x2, dem_y2, dem_x3, dem_y3, dem_x4, dem_y4;
double dem_z1, dem_z2;
int dem_resolution, dem_num_profiles;
// Current "B" Record Information
int prof_col, prof_row;
int prof_num_cols, prof_num_rows;
double prof_x1, prof_y1;
int prof_data;
// temporary values for the class to use
char option_name[32];
int do_data;
int cur_col, cur_row;
// return next token from input stream
string next_token();
// return next integer from input stream
int next_int();
// return next double from input stream
double next_double();
// return next exponential num from input stream
double next_exp();
public:
// Constructor
FGDem( void );
FGDem( const string& file );
// Destructor
~FGDem( void );
// open a DEM file (use "-" if input is coming from stdin)
int open ( const string& file );
// close a DEM file
int close();
// parse a DEM file
int parse();
// read and parse DEM "A" record
int read_a_record();
// read and parse DEM "B" record
void read_b_record();
// write out the area of data covered by the specified bucket.
// Data is written out column by column starting at the lower left
// hand corner.
int write_area( const string& root, FGBucket& b, bool compress );
#if 0
// return the current altitude based on grid data. We should
// rewrite this to interpolate exact values, but for now this is
// good enough
double interpolate_altitude( double lon, double lat );
// Use least squares to fit a simpler data set to dem data
void fit( double error, FGBucket& p );
// Initialize output mesh structure
void outputmesh_init( void );
// Get the value of a mesh node
double outputmesh_get_pt( int i, int j );
// Set the value of a mesh node
void outputmesh_set_pt( int i, int j, double value );
// Write out a node file that can be used by the "triangle" program
void outputmesh_output_nodes( const string& fg_root, FGBucket& p );
#endif
// Informational methods
inline double get_originx() const { return originx; }
inline double get_originy() const { return originy; }
inline int get_cols() const { return cols; }
inline int get_rows() const { return rows; }
inline double get_col_step() const { return col_step; }
inline double get_row_step() const { return row_step; }
};
#endif // _DEM_HXX
// $Log$
// Revision 1.13 1999/03/13 17:40:39 curt
// Moved point interpolation and least squares fitting to contruction program
// area.
// Moved leastsqs.* to Lib/Math/
//
// Revision 1.12 1999/03/12 22:53:09 curt
// Added a routine to dump out the portion of the dem data covered by a
// specified bucket. Other changes related to needs of scenery tools overhaul.
//
// Revision 1.11 1999/03/11 23:31:57 curt
// Tweaks to use newbucket.hxx
//
// Revision 1.10 1999/03/10 01:09:13 curt
// Tweaks to go along with scenery tools overhaul.
// Added a new constructor that accepts the file name.
//
// Revision 1.9 1998/10/16 19:08:14 curt
// Portability updates from Bernie Bright.
//
// Revision 1.8 1998/09/19 17:59:46 curt
// Use c++ streams (fg_gzifstream). Also converted many character arrays to
// the string class.
//
// Revision 1.7 1998/07/04 00:47:19 curt
// typedef'd struct fgBUCKET.
//
// Revision 1.6 1998/06/05 18:14:40 curt
// Abort out early when reading the "A" record if it doesn't look like
// a proper DEM file.
//
// Revision 1.5 1998/04/22 13:14:46 curt
// Fixed a bug in zlib usage.
//
// Revision 1.4 1998/04/21 17:03:41 curt
// Prepairing for C++ integration.
//
// Revision 1.3 1998/04/18 03:53:06 curt
// Added zlib support.
//
// Revision 1.2 1998/04/14 02:43:28 curt
// Used "new" to auto-allocate large DEM parsing arrays in class constructor.
//
// Revision 1.1 1998/04/08 22:57:23 curt
// Adopted Gnu automake/autoconf system.
//
// Revision 1.2 1998/03/23 20:35:42 curt
// Updated to use FG_EPSILON
//
// Revision 1.1 1998/03/19 02:54:47 curt
// Reorganized into a class lib called fgDEM.
//
// Revision 1.1 1998/03/19 01:46:29 curt
// Initial revision.
//

58
Tools/DemChop/Makefile.am Normal file
View file

@ -0,0 +1,58 @@
#---------------------------------------------------------------------------
# Makefile
#
# Written by Curtis Olson, started March 1999.
#
# Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id$
# (Log is kept at end of this file)
#---------------------------------------------------------------------------
bin_PROGRAMS = demchop
demchop_SOURCES = \
demchop.cxx point2d.hxx
demchop_LDADD = \
$(top_builddir)/Tools/Lib/DEM/libDEM.a \
$(top_builddir)/Lib/Bucket/libBucket.a \
$(top_builddir)/Lib/Misc/libMisc.a \
$(top_builddir)/Lib/Debug/libDebug.a \
$(top_builddir)/Lib/zlib/libz.a \
$(base_LIBS)
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib
# We can't build this with "-O2" (optimization) since this causes a seg fault
# I haven't found a way to strip this out of the CXXFLAGS, so I'm just
# setting it to "-g"
# CXXFLAGS = -g
#---------------------------------------------------------------------------
# $Log$
# Revision 1.3 1999/03/17 23:51:07 curt
# Removed forced -g compiler flag.
#
# Revision 1.2 1999/03/12 22:53:45 curt
# First working version!
#
# Revision 1.1 1999/03/10 01:02:54 curt
# Initial revision.
#

113
Tools/DemChop/demchop.cxx Normal file
View file

@ -0,0 +1,113 @@
// demchop.cxx -- chop up a dem file into it's corresponding pieces and stuff
// them into the workspace directory
//
// Written by Curtis Olson, started March 1999.
//
// Copyright (C) 1997 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <Include/compiler.h>
#include STL_STRING
#include <Debug/logstream.hxx>
#include <Bucket/newbucket.hxx>
#include <DEM/dem.hxx>
#include "point2d.hxx"
FG_USING_STD(string);
int main(int argc, char **argv) {
/*
fgDEM dem;
FGBucket p;
string fg_root;
string filename;
double error;
int i, j;
*/
fglog().setLogLevels( FG_ALL, FG_DEBUG );
if ( argc != 3 ) {
FG_LOG( FG_GENERAL, FG_ALERT,
"Usage " << argv[0] << " <dem_file> <work_dir>" );
exit(-1);
}
string dem_name = argv[1];
string work_dir = argv[2];
string command = "mkdir -p " + work_dir;
system( command.c_str() );
FGDem dem(dem_name);
dem.parse();
dem.close();
point2d min, max;
min.x = dem.get_originx() / 3600.0 + FG_HALF_BUCKET_SPAN;
min.y = dem.get_originy() / 3600.0 + FG_HALF_BUCKET_SPAN;
FGBucket b_min( min.x, min.y );
max.x = (dem.get_originx() + dem.get_cols() * dem.get_col_step()) / 3600.0
- FG_HALF_BUCKET_SPAN;
max.y = (dem.get_originy() + dem.get_rows() * dem.get_row_step()) / 3600.0
- FG_HALF_BUCKET_SPAN;
FGBucket b_max( max.x, max.y );
if ( b_min == b_max ) {
dem.write_area( work_dir, b_min, true );
} else {
FGBucket b_cur;
int dx, dy, i, j;
fgBucketDiff(b_min, b_max, &dx, &dy);
cout << "DEM file spans tile boundaries" << endl;
cout << " dx = " << dx << " dy = " << dy << endl;
if ( (dx > 20) || (dy > 20) ) {
cout << "somethings really wrong!!!!" << endl;
exit(-1);
}
for ( j = 0; j <= dy; j++ ) {
for ( i = 0; i <= dx; i++ ) {
b_cur = fgBucketOffset(min.x, min.y, i, j);
dem.write_area( work_dir, b_cur, true );
}
}
}
return 0;
}
// $Log$
// Revision 1.3 1999/03/12 22:53:46 curt
// First working version!
//
// Revision 1.2 1999/03/10 16:09:44 curt
// Hacking towards the first working version.
//
// Revision 1.1 1999/03/10 01:02:54 curt
// Initial revision.
//

44
Tools/DemChop/point2d.cxx Normal file
View file

@ -0,0 +1,44 @@
// point2d.cxx -- 2d coordinate routines
//
// Written by Curtis Olson, started September 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#include <math.h>
#include "point2d.hxx"
// convert a point from cartesian to polar coordinates
point2d cart_to_polar_2d(point2d in) {
point2d result;
result.dist = sqrt( in.x * in.x + in.y * in.y );
result.theta = atan2(in.y, in.x);
return(result);
}
// $Log$
// Revision 1.1 1999/03/10 01:02:54 curt
// Initial revision.
//

62
Tools/DemChop/point2d.hxx Normal file
View file

@ -0,0 +1,62 @@
// point2d.hxx -- define a 2d point class
//
// Written by Curtis Olson, started February 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#ifndef _POINT2D_HXX
#define _POINT2D_HXX
#include <list>
class point2d {
public:
union {
double x;
double dist;
double lon;
};
union {
double y;
double theta;
double lat;
};
};
// convert a point from cartesian to polar coordinates
point2d cart_to_polar_2d(point2d in);
#endif // _POINT2D_HXX
// $Log$
// Revision 1.1 1999/03/10 16:09:45 curt
// Hacking towards the first working version.
//
// Revision 1.1 1998/09/04 23:04:53 curt
// Beginning of convex hull genereration routine.
//
//

70
Tools/DemInfo/Makefile.am Normal file
View file

@ -0,0 +1,70 @@
#---------------------------------------------------------------------------
# Makefile
#
# Written by Curtis Olson, started June 1998.
#
# Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id$
# (Log is kept at end of this file)
#---------------------------------------------------------------------------
bin_PROGRAMS = deminfo
deminfo_SOURCES = \
deminfo.cxx
deminfo_LDADD = \
$(top_builddir)/Tools/Lib/DEM/libDEM.a \
$(top_builddir)/Lib/Bucket/libBucket.a \
$(top_builddir)/Lib/Misc/libMisc.a \
$(top_builddir)/Lib/zlib/libz.a \
$(base_LIBS)
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib
# We can't build this with "-O2" (optimization) since this causes a seg fault
# I haven't found a way to strip this out of the CXXFLAGS, so I'm just
# setting it to "-g"
# CXXFLAGS = -g
#---------------------------------------------------------------------------
# $Log$
# Revision 1.7 1999/03/17 23:51:14 curt
# Removed forced -g compiler flag.
#
# Revision 1.6 1999/03/08 22:00:46 curt
# Lots of directory layout reorganization.
#
# Revision 1.5 1999/02/01 21:09:27 curt
# Moving location of Lib/DEM/ to Tools/DEM/
#
# Revision 1.4 1998/11/04 23:01:48 curt
# Changes to the automake/autoconf system to reduce the number of libraries
# that are unnecessarily linked into the various executables.
#
# Revision 1.3 1998/09/19 18:01:21 curt
# Support for changes to libDEM.a
#
# Revision 1.2 1998/07/30 23:49:24 curt
# Removed libtool support.
#
# Revision 1.1 1998/06/04 19:18:04 curt
# Initial revision.
#

78
Tools/DemInfo/deminfo.cxx Normal file
View file

@ -0,0 +1,78 @@
// deminfo.cxx -- main loop
//
// Written by Curtis Olson, started June 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <DEM/dem.hxx>
// static float dem_data[DEM_SIZE_1][DEM_SIZE_1];
// static float output_data[DEM_SIZE_1][DEM_SIZE_1];
int main(int argc, char **argv) {
// DEM data
FGDem dem;
string filename;
double error;
int i, j;
if ( argc != 2 ) {
printf("Usage: %s <file.dem>\n", argv[0]);
exit(-1);
}
// set input dem file name
filename = argv[1];
dem.open(filename);
if ( dem.read_a_record() ) {
cout << "Results = " << filename << " "
<< dem.get_originx() / 3600.0 << " "
<< dem.get_originy() / 3600.0 << "\n";
} else {
cout << "Error parsing DEM file.\n";
}
dem.close();
return(0);
}
// $Log$
// Revision 1.3 1999/03/12 22:54:04 curt
// Convert fgDEM to FGDem ...
//
// Revision 1.2 1998/09/19 18:01:22 curt
// Support for changes to libDEM.a
//
// Revision 1.1 1998/06/04 19:18:05 curt
// Initial revision.
//

View file

@ -0,0 +1,61 @@
#!/usr/bin/perl
#---------------------------------------------------------------------------
# script to gather DEM position info so we can associate a file name with a
# position.
#
# Written by Curtis Olson, started June 1998.
#
# Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id$
# (Log is kept at end of this file)
#---------------------------------------------------------------------------
if ( $#ARGV < 0 ) {
die "Usage: $0 search_dir ... \n";
}
while ( $dir = shift(@ARGV) ) {
# print "processing $dir\n";
@allfiles = `find $dir -print`;
foreach $file (@allfiles) {
chop($file);
# print "trying $file\n";
if ( -f $file ) {
# print "really trying $file\n";
open ( INFO, "./deminfo $file |" );
while ( <INFO> ) {
if ( m/Results = / ) {
$_ =~ s/Results = //;
print $_;
}
}
close(INFO);
}
}
}
#---------------------------------------------------------------------------
# $Log$
# Revision 1.1 1998/06/04 19:18:06 curt
# Initial revision.
#

View file

@ -0,0 +1,47 @@
#---------------------------------------------------------------------------
# Makefile
#
# Written by Curtis Olson, started February 1998.
#
# Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id$
# (Log is kept at end of this file)
#---------------------------------------------------------------------------
bin_PROGRAMS = raw2ascii
raw2ascii_SOURCES = main.c rawdem.c rawdem.h
raw2ascii_LDADD = $(base_LIBS)
INCLUDES +=
#---------------------------------------------------------------------------
# $Log$
# Revision 1.3 1998/11/04 23:01:50 curt
# Changes to the automake/autoconf system to reduce the number of libraries
# that are unnecessarily linked into the various executables.
#
# Revision 1.2 1998/04/24 00:44:04 curt
# Added zlib support.
#
# Revision 1.1 1998/04/18 03:59:44 curt
# Incorporated into gnu automake/autoconf system.
#

90
Tools/DemRaw2ascii/main.c Normal file
View file

@ -0,0 +1,90 @@
/* main.c -- main loop
*
* Written by Curtis Olson, started February 1998.
*
* Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
* (Log is kept at end of this file)
*/
#include <stdio.h>
#include <string.h>
#include "rawdem.h"
int main(int argc, char **argv) {
fgRAWDEM raw;
char basename[256], output_dir[256], hdr_file[256], dem_file[256];
int i, start_lat, end_lat;
if ( argc != 3 ) {
printf("Usage: %s <input_file_basename> <output_dir>\n", argv[0]);
exit(-1);
}
/* get basename */
strcpy(basename, argv[1]);
/* get output dir */
strcpy(output_dir, argv[2]);
/* generate header file name */
strcpy(hdr_file, basename);
strcat(hdr_file, ".HDR");
/* generate input file name (raw dem) */
strcpy(dem_file, basename);
strcat(dem_file, ".DEM");
printf("Header file = %s Input file = %s\n", hdr_file, dem_file);
printf("Output Directory = %s\n", output_dir);
/* scan the header file and extract important values */
rawReadDemHdr(&raw, hdr_file);
/* open up the raw data file */
rawOpenDemFile(&raw, dem_file);
end_lat = raw.rooty / 3600;
start_lat = end_lat - ((raw.nrows * raw.ydim) / 3600);
printf("Latitude ranges from %d to %d\n", start_lat, end_lat);
for ( i = start_lat + 1; i <= end_lat; i++ ) {
rawProcessStrip(&raw, i, output_dir);
}
/* close the raw data file */
rawCloseDemFile(&raw);
return(0);
}
/* $Log$
/* Revision 1.3 1998/03/03 21:54:50 curt
/* Changes to process 30 arcsec binary DEM files.
/*
* Revision 1.2 1998/03/03 13:10:28 curt
* Close to a working version.
*
* Revision 1.1 1998/03/02 23:31:01 curt
* Initial revision.
*
*/

485
Tools/DemRaw2ascii/rawdem.c Normal file
View file

@ -0,0 +1,485 @@
/* rawdem.c -- library of routines for processing raw dem files (30 arcsec)
*
* Written by Curtis Olson, started February 1998.
*
* Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
* (Log is kept at end of this file)
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <math.h> /* rint() */
#include <stdio.h>
#include <stdlib.h> /* atoi() atof() */
#include <string.h> /* swab() */
#include <sys/types.h> /* open() */
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> /* close() */
#include "rawdem.h"
/* Read the DEM header to determine various key parameters for this
* DEM file */
void rawReadDemHdr( fgRAWDEM *raw, char *hdr_file ) {
FILE *hdr;
char line[256], key[256], value[256];
int i, len, offset;
double tmp;
if ( (hdr = fopen(hdr_file, "r")) == NULL ) {
printf("Error opening DEM header file: %s\n", hdr_file);
exit(-1);
}
/* process each line */
while ( (fgets(line, 256, hdr) != NULL) ) {
/* printf("%s", line); */
len = strlen(line);
/* extract key */
i = 0;
while ( (line[i] != ' ') && (i < len) ) {
key[i] = line[i];
i++;
}
key[i] = '\0';
/* skip middle space */
while ( (line[i] == ' ') && (i < len) ) {
i++;
}
offset = i;
/* extract value */
while ( (line[i] != '\n') && (i < len) ) {
value[i-offset] = line[i];
i++;
}
value[i-offset] = '\0';
/* printf("key='%s' value='%s'\n", key, value); */
if ( strcmp(key, "NROWS") == 0 ) {
raw->nrows = atoi(value);
} else if ( strcmp(key, "NCOLS") == 0 ) {
raw->ncols = atoi(value);
} else if ( strcmp(key, "ULXMAP") == 0 ) {
tmp = atof(value);
#ifdef HAVE_RINT
raw->ulxmap = (int)rint(tmp * 3600.0); /* convert to arcsec */
#else
# error Port me rint()
#endif
} else if ( strcmp(key, "ULYMAP") == 0 ) {
tmp = atof(value);
#ifdef HAVE_RINT
raw->ulymap = (int)rint(tmp * 3600.0); /* convert to arcsec */
#else
# error Port me rint()
#endif
} else if ( strcmp(key, "XDIM") == 0 ) {
tmp = atof(value);
#ifdef HAVE_RINT
raw->xdim = (int)rint(tmp * 3600.0); /* convert to arcsec */
#else
# error Port me rint()
#endif
} else if ( strcmp(key, "YDIM") == 0 ) {
tmp = atof(value);
#ifdef HAVE_RINT
raw->ydim = (int)rint(tmp * 3600.0); /* convert to arcsec */
#else
# error Port me rint()
#endif
} else {
/* ignore for now */
}
}
raw->rootx = raw->ulxmap - (raw->xdim / 2);
raw->rooty = raw->ulymap + (raw->ydim / 2);
printf("%d %d %d %d %d %d %d %d\n", raw->nrows, raw->ncols,
raw->ulxmap, raw->ulymap, raw->rootx, raw->rooty, raw->xdim,
raw->ydim);
}
/* Open a raw DEM file. */
void rawOpenDemFile( fgRAWDEM *raw, char *raw_dem_file ) {
printf("Opening Raw DEM file: %s\n", raw_dem_file);
if ( (raw->fd = open(raw_dem_file ,O_RDONLY)) == -1 ) {
printf("Error opening Raw DEM file: %s\n", raw_dem_file);
exit(-1);
}
}
/* Close a raw DEM file. */
void rawCloseDemFile( fgRAWDEM *raw ) {
close(raw->fd);
}
/* Advance file pointer position to correct latitude (row) */
void rawAdvancePosition( fgRAWDEM *raw, int arcsec ) {
long offset, result;
offset = 2 * raw->ncols * ( arcsec / raw->ydim );
if ( (result = lseek(raw->fd, offset, SEEK_SET)) == -1 ) {
printf("Error lseek filed trying to offset by %ld\n", offset);
exit(-1);
}
printf("Successful seek ahead of %ld bytes\n", result);
}
/* Read the next row of data */
void rawReadNextRow( fgRAWDEM *raw, int index ) {
char buf[MAX_COLS_X_2];
int i, result;
if ( raw->ncols > MAX_ROWS ) {
printf("Error, buf needs to be bigger in rawReadNextRow()\n");
exit(-1);
}
/* printf("Attempting to read %d bytes\n", 2 * raw->ncols); */
result = read(raw->fd, buf, 2 * raw->ncols);
/* printf("Read %d bytes\n", result); */
/* reverse byte order */
/* it would be nice to test in advance some how if we need to do
* this */
/* swab(frombuf, tobuf, 2 * raw->ncols); */
for ( i = 0; i < raw->ncols; i++ ) {
/* printf("hi = %d lo = %d\n", buf[2*i], buf[2*i + 1]); */
raw->strip[index][i] = ( (buf[2*i] + 1) << 8 ) + buf[2*i + 1];
}
}
/* Convert from pixel centered values to pixel corner values. This is
accomplished by taking the average of the closes center nodes. In
the following diagram "x" marks the data point location:
+-----+ x-----x
| | | |
| x | ===> | |
| | | |
+-----+ x-----x
*/
void rawConvertCenter2Edge( fgRAWDEM *raw ) {
int i, j;
/* derive corner nodes */
raw->edge[0][0] = raw->center[0][0];
raw->edge[120][0] = raw->center[119][0];
raw->edge[120][120] = raw->center[119][119];
raw->edge[0][120] = raw->center[0][119];
/* derive edge nodes */
for ( i = 1; i < 120; i++ ) {
raw->edge[i][0] = (raw->center[i-1][0] + raw->center[i][0]) / 2.0;
raw->edge[i][120] = (raw->center[i-1][119] + raw->center[i][119]) / 2.0;
raw->edge[0][i] = (raw->center[0][i-1] + raw->center[0][i]) / 2.0;
raw->edge[120][i] = (raw->center[119][i-1] + raw->center[119][i]) / 2.0;
}
/* derive internal nodes */
for ( j = 1; j < 120; j++ ) {
for ( i = 1; i < 120; i++ ) {
raw->edge[i][j] = ( raw->center[i-1][j-1] +
raw->center[i] [j-1] +
raw->center[i] [j] +
raw->center[i-1][j] ) / 4;
}
}
}
/* Dump out the ascii format DEM file */
void rawDumpAsciiDEM( fgRAWDEM *raw, char *path, int ilon, int ilat ) {
char outfile[256];
char tmp[256];
int lon, lat;
char lon_sign, lat_sign;
int i, j;
FILE *fd;
/* Generate output file name */
if ( ilon >= 0 ) {
lon = ilon;
lon_sign = 'e';
} else {
lon = -ilon;
lon_sign = 'w';
}
if ( ilat >= 0 ) {
lat = ilat;
lat_sign = 'n';
} else {
lat = -ilat;
lat_sign = 's';
}
sprintf(outfile, "%s/%c%03d%c%03d.dem", path, lon_sign, lon, lat_sign, lat);
printf("outfile = %s\n", outfile);
if ( (fd = fopen(outfile, "w")) == NULL ) {
printf("Error opening output file = %s\n", outfile);
exit(-1);
}
/* Dump the "A" record */
/* print descriptive header (144 characters) */
sprintf(tmp, "%s - Generated from a 30 arcsec binary DEM", outfile);
fprintf(fd, "%-144s", tmp);
/* DEM level code, 3 reflects processing by DMA */
fprintf(fd, "%6d", 1);
/* Pattern code, 1 indicates a regular elevation pattern */
fprintf(fd, "%6d", 1);
/* Planimetric reference system code, 0 indicates geographic
* coordinate system. */
fprintf(fd, "%6d", 0);
/* Zone code */
fprintf(fd, "%6d", 0);
/* Map projection parameters (ignored) */
for ( i = 0; i < 15; i++ ) {
fprintf(fd, "%6.1f%18s", 0.0, "");
}
/* Units code, 3 represents arc-seconds as the unit of measure for
* ground planimetric coordinates throughout the file. */
fprintf(fd, "%6d", 3);
/* Units code; 2 represents meters as the unit of measure for
* elevation coordinates throughout the file. */
fprintf(fd, "%6d", 2);
/* Number (n) of sides in the polygon which defines the coverage of
* the DEM file (usually equal to 4). */
fprintf(fd, "%6d", 4);
/* Ground coordinates of bounding box in arc-seconds */
fprintf(fd, "%20.15fD+06", ilon * 3600.0 / 1000000.0);
fprintf(fd, "%20.15fD+06", ilat * 3600.0 / 1000000.0);
fprintf(fd, "%20.15fD+06", ilon * 3600.0 / 1000000.0);
fprintf(fd, "%20.15fD+06", (ilat+1) * 3600.0 / 1000000.0);
fprintf(fd, "%20.15fD+06", (ilon+1) * 3600.0 / 1000000.0);
fprintf(fd, "%20.15fD+06", (ilat+1) * 3600.0 / 1000000.0);
fprintf(fd, "%20.15fD+06", (ilon+1) * 3600.0 / 1000000.0);
fprintf(fd, "%20.15fD+06", (ilat) * 3600.0 / 1000000.0);
/* Minimum/maximum elevations in meters */
fprintf(fd, " %20.15E", (double)raw->tmp_min);
fprintf(fd, " %20.15E", (double)raw->tmp_max);
/* Counterclockwise angle from the primary axis of ground
* planimetric referenced to the primary axis of the DEM local
* reference system. */
fprintf(fd, "%6.1f", 0.0);
/* Accuracy code; 0 indicates that a record of accuracy does not
* exist and that no record type C will follow. */
fprintf(fd, "%24d", 0);
/* DEM spacial resolution. Usually (3,3) (3,6) or (3,9)
* depending on latitude */
fprintf(fd, "%12.6E", 30.0);
fprintf(fd, "%12.6E", 30.0);
/* accuracy code */
fprintf(fd, "%12.6E", 1.0);
/* dimension of arrays to follow (1)*/
fprintf(fd, "%6d", 1);
/* number of profiles */
fprintf(fd, "%6d", 3600 / raw->ydim + 1);
/* pad the end */
fprintf(fd, "%160s", "");
/* Dump "B" records */
for ( j = 0; j <= 120; j++ ) {
/* row / column id of this profile */
fprintf(fd, "%6d%6d", 1, j + 1);
/* Number of rows and columns (elevation points) in this
profile */
fprintf(fd, "%6d%6d", 3600 / raw->xdim + 1, 1);
/* Ground planimetric coordinates (arc-seconds) of the first
* elevation in the profile */
fprintf(fd, "%20.15fD+06", ilon * 3600.0 / 1000000.0);
fprintf(fd, "%20.15fD+06", (ilat * 3600.0 + j * raw->ydim) / 1000000.0);
/* Elevation of local datum for the profile. Always zero for
* 1-degree DEM, the reference is mean sea level. */
fprintf(fd, "%6.1f", 0.0);
fprintf(fd, "%18s", "");
/* Minimum and maximum elevations for the profile. */
fprintf(fd, " %20.15E", 0.0);
fprintf(fd, " %20.15E", 0.0);
/* One (usually) dimensional array (1,prof_num_cols) of
elevations */
for ( i = 0; i <= 120; i++ ) {
fprintf(fd, "%6.0f", raw->edge[j][i]);
}
}
fprintf(fd, "\n");
fclose(fd);
}
/* Read a horizontal strip of (1 vertical degree) from the raw DEM
* file specified by the upper latitude of the stripe specified in
* degrees. The output the individual ASCII format DEM tiles. */
void rawProcessStrip( fgRAWDEM *raw, int lat_degrees, char *path ) {
int lat, yrange;
int i, j, index, row, col;
int min, max;
int span, num_degrees, tile_width;
int xstart, xend;
/* convert to arcsec */
lat = lat_degrees * 3600;
printf("Max Latitude = %d arcsec\n", lat);
/* validity check ... */
if ( (lat > raw->rooty) ||
(lat < (raw->rooty - raw->nrows * raw->ydim + 1)) ) {
printf("Latitude out of range for this DEM file\n");
return;
}
printf ("Reading strip starting at %d (top and working down)\n", lat);
/* advance to the correct latitude */
rawAdvancePosition(raw, (raw->rooty - lat));
/* printf("short = %d\n", sizeof(short)); */
yrange = 3600 / raw->ydim;
for ( i = 0; i < yrange; i++ ) {
index = yrange - i - 1;
/* printf("About to read into row %d\n", index); */
rawReadNextRow(raw, index);
for ( j = 0; j < raw->ncols; j++ ) {
if ( raw->strip[index][j] == -9999 ) {
/* map ocean to 0 for now */
raw->strip[index][j] = 0;
}
}
}
/* extract individual tiles from the strip */
span = raw->ncols * raw->xdim;
num_degrees = span / 3600;
tile_width = raw->ncols / num_degrees;
printf("span = %d num_degrees = %d width = %d\n",
span, num_degrees, tile_width);
for ( i = 0; i < num_degrees; i++ ) {
xstart = i * tile_width;
xend = xstart + 120;
min = 10000; max = -10000;
for ( row = 0; row < yrange; row++ ) {
for ( col = xstart; col < xend; col++ ) {
/* Copy from strip to pixel centered tile. Yep,
* row/col are reversed here. raw->strip is backwards
* for convenience. I am converting to [x,y] now. */
raw->center[col-xstart][row] = raw->strip[row][col];
if ( raw->strip[row][col] < min) {
min = raw->strip[row][col];
}
if ( raw->strip[row][col] > max) {
max = raw->strip[row][col];
}
}
}
raw->tmp_min = min;
raw->tmp_max = max;
/* Convert from pixel centered to pixel edge values */
rawConvertCenter2Edge(raw);
/* Dump out the ascii format DEM file */
rawDumpAsciiDEM(raw, path, (raw->rootx / 3600) + i, lat_degrees - 1);
}
}
/* $Log$
/* Revision 1.6 1998/04/27 03:32:03 curt
/* Wrapped rint()'s in #ifdef HAVE_RINT
/*
* Revision 1.5 1998/04/18 03:59:46 curt
* Incorporated into gnu automake/autoconf system.
*
* Revision 1.4 1998/04/06 21:09:43 curt
* Additional win32 support.
* Fixed a bad bug in dem file parsing that was causing the output to be
* flipped about x = y.
*
* Revision 1.3 1998/03/03 13:10:29 curt
* Close to a working version.
*
* Revision 1.2 1998/03/03 02:04:01 curt
* Starting DEM Ascii format output routine.
*
* Revision 1.1 1998/03/02 23:31:01 curt
* Initial revision.
*
*/

View file

@ -0,0 +1,85 @@
/* rawdem.h -- library of routines for processing raw dem files (30 arcsec)
*
* Written by Curtis Olson, started February 1998.
*
* Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
* (Log is kept at end of this file)
*/
#ifndef _RAWDEM_H
#define _RAWDEM_H
#define MAX_ROWS 6000
#define MAX_COLS 7200
#define MAX_COLS_X_2 14400
typedef struct {
/* header info */
int nrows; /* number of rows */
int ncols; /* number of cols */
int ulxmap; /* X coord of center of upper left pixel in arcsec */
int ulymap; /* Y coord of center of upper left pixel in arcsec */
int rootx; /* X coord of upper left *edge* of DEM region in degrees */
int rooty; /* Y coord of upper left *edge* of DEM region in degrees */
int xdim; /* X dimension of a pixel */
int ydim; /* Y dimension of a pixel */
int tmp_min; /* current 1x1 degree tile minimum */
int tmp_max; /* current 1x1 degree tile maximum */
/* file ptr */
int fd; /* Raw DEM file descriptor */
/* storage area for a 1 degree high strip of data. Note, for
* convenience this is in y,x order */
short strip[120][MAX_ROWS];
short center[120][120]; /* tile with data taken at center of pixel */
float edge[121][121]; /* tile with data converted to corners */
} fgRAWDEM;
/* Read the DEM header to determine various key parameters for this
* DEM file */
void rawReadDemHdr( fgRAWDEM *raw, char *hdr_file );
/* Open a raw DEM file. */
void rawOpenDemFile( fgRAWDEM *raw, char *raw_dem_file );
/* Close a raw DEM file. */
void rawCloseDemFile( fgRAWDEM *raw );
/* Read a horizontal strip of (1 vertical degree) from the raw DEM
* file specified by the upper latitude of the stripe specified in
* degrees. The output the individual ASCII format DEM tiles. */
void rawProcessStrip( fgRAWDEM *raw, int lat_degrees, char *path );
#endif /* _RAWDEM_H */
/* $Log$
/* Revision 1.2 1998/03/03 13:10:30 curt
/* Close to a working version.
/*
* Revision 1.1 1998/03/02 23:31:02 curt
* Initial revision.
*
*/

95
Tools/FixNode/Makefile.am Normal file
View file

@ -0,0 +1,95 @@
#---------------------------------------------------------------------------
# Makefile
#
# Written by Curtis Olson, started October 1997.
#
# Copyright (C) 1997 - 1998 Curtis L. Olson - curt@me.umn.edu
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id$
# (Log is kept at end of this file)
#---------------------------------------------------------------------------
bin_PROGRAMS = fixnode
fixnode_SOURCES = \
fixnode.cxx fixnode.hxx \
main.cxx
fixnode_LDADD = \
$(top_builddir)/Tools/Lib/DEM/libDEM.a \
$(top_builddir)/Lib/Bucket/libBucket.a \
$(top_builddir)/Lib/Misc/libMisc.a \
$(top_builddir)/Lib/zlib/libz.a \
$(base_LIBS)
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib
# We can't build this with "-O2" (optimization) since this causes a seg fault
# I haven't found a way to strip this out of the CXXFLAGS, so I'm just
# setting it to "-g"
# CXXFLAGS = -g
#---------------------------------------------------------------------------
# $Log$
# Revision 1.10 1999/03/17 23:50:59 curt
# Removed forced -g compiler flag.
#
# Revision 1.9 1999/03/08 22:00:45 curt
# Lots of directory layout reorganization.
#
# Revision 1.8 1999/02/01 21:09:30 curt
# Moving location of Lib/DEM/ to Tools/DEM/
#
# Revision 1.7 1998/11/04 23:01:51 curt
# Changes to the automake/autoconf system to reduce the number of libraries
# that are unnecessarily linked into the various executables.
#
# Revision 1.6 1998/09/19 20:43:50 curt
# C++-ified and STL-ified the code. Combined triload.* and fixnode.* into
# a single file.
#
# Revision 1.5 1998/09/19 18:01:26 curt
# Support for changes to libDEM.a
#
# Revision 1.4 1998/07/30 23:49:24 curt
# Removed libtool support.
#
# Revision 1.3 1998/04/18 04:02:54 curt
# Added zlib support in placed and other misc. tweaks.
#
# Revision 1.2 1998/04/14 02:26:02 curt
# Code reorganizations. Added a Lib/ directory for more general libraries.
#
# Revision 1.1 1998/04/08 23:05:54 curt
# Adopted Gnu automake/autoconf system.
#
# Revision 1.4 1998/04/06 21:09:44 curt
# Additional win32 support.
# Fixed a bad bug in dem file parsing that was causing the output to be
# flipped about x = y.
#
# Revision 1.3 1998/03/19 02:50:19 curt
# Updated to support -lDEM class.
#
# Revision 1.2 1998/01/21 02:55:50 curt
# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
#
# Revision 1.1 1997/11/27 00:17:32 curt
# Initial revision.
#

161
Tools/FixNode/fixnode.cxx Normal file
View file

@ -0,0 +1,161 @@
// fixnode.cxx -- traverse the node file and fix the elevation of all the new
// interpolated points.
//
// Written by Curtis Olson, started November 1997.
//
// Copyright (C) 1997 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <string>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif // HAVE_STDLIB_H
#include <Misc/fgstream.hxx>
#include "fixnode.hxx"
// load extra nodes
void load_extra(const string& filename, container& extra_list) {
}
// load the node information
void load_nodes(const string& filename, container& node_list) {
Point3D node;
int dim, junk1, junk2;
int i, nodecount;
cout << "Loading node file: " << filename << " ...\n";
fg_gzifstream in( filename );
if ( !in ) {
cout << "Cannot open " + filename + "\n";
// exit immediately assuming an airport file for this tile
// doesn't exist.
exit(-1);
}
// Read header line
in >> nodecount >> dim >> junk1 >> junk2;
cout << " Expecting " << nodecount << " nodes\n";
// start with an empty list :-)
node_list.erase( node_list.begin(), node_list.end() );
in >> skipcomment;
while ( ! in.eof() ) {
in >> junk1 >> node >> junk2;
in >> skipcomment;
node_list.push_back(node);
}
}
// fix the node elevations
void fix_nodes( const string& filename, fgDEM& dem, container& node_list )
{
string toname;
FILE *fd;
int i;
cout << "Fixing up node elevations\n";
iterator current;
iterator last = node_list.end();
for ( current = node_list.begin() ; current != last ; ++current ) {
// printf("Current: %d %.2f %.2f %.2f\n", i, nodes[i][0],
// nodes[i][1], nodes[i][2]);
(*current).setz(
dem.interpolate_altitude( (*current).x(),
(*current).y() ) );
// printf("Fixed: %d %.2f %.2f %.2f\n", i, nodes[i][0],
// nodes[i][1], nodes[i][2]);
}
toname = filename + ".orig";
cout << "Moving " + filename + " to " + toname + "\n";
rename( filename.c_str(), toname.c_str() );
cout << "Saving new node file: " + filename + "\n";
fd = fopen(filename.c_str(), "w");
fprintf( fd, "%d 2 1 0\n", node_list.size() );
i = 1;
for ( current = node_list.begin() ; current != last ; ++current ) {
fprintf( fd, "%d %.2f %.2f %.2f 0\n", i,
(*current).x(), (*current).y(), (*current).z() );
++i;
}
fclose(fd);
}
// $Log$
// Revision 1.7 1998/11/06 21:33:55 curt
// Updates to go along with changes in fgstream.
//
// Revision 1.6 1998/10/20 15:49:22 curt
// Converted to Point3D class.
//
// Revision 1.5 1998/09/22 23:49:10 curt
// eliminated a left over #include
//
// Revision 1.4 1998/09/19 20:43:52 curt
// C++-ified and STL-ified the code. Combined triload.* and fixnode.* into
// a single file.
//
// Revision 1.3 1998/07/22 21:46:40 curt
// Fixed a bug that was triggering a seg fault.
//
// Revision 1.2 1998/04/14 02:26:03 curt
// Code reorganizations. Added a Lib/ directory for more general libraries.
//
// Revision 1.1 1998/04/08 23:05:56 curt
// Adopted Gnu automake/autoconf system.
//
// Revision 1.5 1998/03/19 02:50:19 curt
// Updated to support -lDEM class.
//
// Revision 1.4 1998/03/03 16:00:57 curt
// More c++ compile tweaks.
//
// Revision 1.3 1998/01/09 23:03:08 curt
// Restructured to split 1deg x 1deg dem's into 64 subsections.
//
// Revision 1.2 1997/12/02 13:12:07 curt
// Updated to fix every node.
//
// Revision 1.1 1997/11/27 00:17:33 curt
// Initial revision.
//

95
Tools/FixNode/fixnode.hxx Normal file
View file

@ -0,0 +1,95 @@
// fixnode.hxx -- traverse the node file and fix the elevation of all the new
// interpolated points.
//
// Written by Curtis Olson, started November 1997.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#ifndef _FIXNODE_H
#define _FIXNODE_H
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#include "Include/fg_stl_config.h"
#ifdef NEEDNAMESPACESTD
using namespace std;
#endif
#include <DEM/dem.hxx>
#include <Math/point3d.hxx>
typedef vector < Point3D > container;
typedef container::iterator iterator;
typedef container::const_iterator const_iterator;
// Initialize a new mesh structure
void load_nodes(const string& basename, container& node_list);
// load the extra nodes. These are always the first n nodes of the
// .node file. (??? These will be tagged with a code indicating what
// needs to be done with this node's elevation such as adjust to local
// DEM elevation, or massage the local DEM points to match this
// elevation point. ???)
void load_extra_nodes(const string& filename, container& node_list);
// fix the node elevations
void fix_nodes( const string& basename, fgDEM& dem, container& node_list );
#endif // _FIXNODE_H
// $Log$
// Revision 1.4 1998/10/20 15:49:23 curt
// Converted to Point3D class.
//
// Revision 1.3 1998/09/19 20:43:53 curt
// C++-ified and STL-ified the code. Combined triload.* and fixnode.* into
// a single file.
//
// Revision 1.2 1998/07/22 21:46:41 curt
// Fixed a bug that was triggering a seg fault.
//
// Revision 1.1 1998/04/08 23:05:56 curt
// Adopted Gnu automake/autoconf system.
//
// Revision 1.4 1998/03/19 02:50:19 curt
// Updated to support -lDEM class.
//
// Revision 1.3 1998/03/03 16:00:58 curt
// More c++ compile tweaks.
//
// Revision 1.2 1997/12/02 13:12:07 curt
// Updated to fix every node.
//
// Revision 1.1 1997/11/27 00:17:33 curt
// Initial revision.
//

146
Tools/FixNode/main.cxx Normal file
View file

@ -0,0 +1,146 @@
// main.cxx -- read in a .node file and fix the z values of the interpolated
// points
//
// Written by Curtis Olson, started November 1997.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#include <sys/types.h>
#include <dirent.h>
// #include <stdio.h>
#include <string.h>
#include <string>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif // HAVE_STDLIB_H
#include <DEM/dem.hxx>
#include "fixnode.hxx"
// find all the matching files in the specified directory and fix them
void process_files(const string& root_path, fgDEM& dem) {
container node_list;
DIR *d;
struct dirent *de;
string file_path;
char *ptr;
int len;
if ( (d = opendir( root_path.c_str() )) == NULL ) {
cout << "cannot open directory " + root_path + "\n";
exit(-1);
}
while ( (de = readdir(d)) != NULL ) {
len = strlen(de->d_name);
if ( len > 7 ) {
ptr = de->d_name;
ptr += (len - 7);
// printf("--> %s \n", ptr);
if ( strcmp(ptr, ".1.node") == 0 ) {
file_path = root_path + "/" + de->d_name;
cout << "File = " + file_path + "\n";
// load the input data files
load_nodes(file_path, node_list);
fix_nodes(file_path, dem, node_list);
}
}
}
}
// main
int main(int argc, char **argv) {
fgDEM dem;
string demfile, root_path;
if ( argc != 3 ) {
cout << "Usage " << argv[0] << " demfile root_path\n";
exit(-1);
}
cout << "Starting fixnode\n";
demfile = argv[1];
root_path = argv[2];
// load the corresponding dem file so we can interpolate elev values
dem.open(demfile);
dem.parse();
dem.close();
// process all the *.1.node files in the specified directory
process_files(root_path, dem);
return(0);
}
// $Log$
// Revision 1.7 1998/09/19 20:43:54 curt
// C++-ified and STL-ified the code. Combined triload.* and fixnode.* into
// a single file.
//
// Revision 1.6 1998/09/19 18:01:27 curt
// Support for changes to libDEM.a
//
// Revision 1.5 1998/07/22 21:46:41 curt
// Fixed a bug that was triggering a seg fault.
//
// Revision 1.4 1998/06/27 16:55:24 curt
// Changed include order for <sys/types.h>
//
// Revision 1.3 1998/04/26 05:02:06 curt
// Added #ifdef HAVE_STDLIB_H
//
// Revision 1.2 1998/04/14 02:26:04 curt
// Code reorganizations. Added a Lib/ directory for more general libraries.
//
// Revision 1.1 1998/04/08 23:05:57 curt
// Adopted Gnu automake/autoconf system.
//
// Revision 1.6 1998/04/06 21:09:44 curt
// Additional win32 support.
// Fixed a bad bug in dem file parsing that was causing the output to be
// flipped about x = y.
//
// Revision 1.5 1998/03/19 02:50:20 curt
// Updated to support -lDEM class.
//
// Revision 1.4 1998/03/03 16:00:58 curt
// More c++ compile tweaks.
//
// Revision 1.3 1998/01/09 23:03:08 curt
// Restructured to split 1deg x 1deg dem's into 64 subsections.
//
// Revision 1.2 1997/12/02 13:12:07 curt
// Updated to fix every node.
//
// Revision 1.1 1997/11/27 00:17:34 curt
// Initial revision.
//

69
Tools/FixObj/Makefile.am Normal file
View file

@ -0,0 +1,69 @@
#---------------------------------------------------------------------------
# Makefile
#
# Written by Curtis Olson, started October 1997.
#
# Copyright (C) 1997 - 1998 Curtis L. Olson - curt@me.umn.edu
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id$
# (Log is kept at end of this file)
#---------------------------------------------------------------------------
bin_PROGRAMS = fixobj
fixobj_SOURCES = main.cxx obj.cxx obj.hxx
fixobj_LDADD = \
$(top_builddir)/Lib/Math/libMath.a \
$(top_builddir)/Lib/Debug/libDebug.a \
$(top_builddir)/Lib/zlib/libz.a \
$(base_LIBS)
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
#---------------------------------------------------------------------------
# $Log$
# Revision 1.7 1998/11/04 23:01:53 curt
# Changes to the automake/autoconf system to reduce the number of libraries
# that are unnecessarily linked into the various executables.
#
# Revision 1.6 1998/07/30 23:49:25 curt
# Removed libtool support.
#
# Revision 1.5 1998/06/08 17:11:44 curt
# Renamed *.[ch] to *.[ch]xx
#
# Revision 1.4 1998/04/24 00:44:05 curt
# Added zlib support.
#
# Revision 1.3 1998/04/18 04:01:02 curt
# Now use libMath rather than having local copies of math routines.
#
# Revision 1.2 1998/04/14 02:26:05 curt
# Code reorganizations. Added a Lib/ directory for more general libraries.
#
# Revision 1.1 1998/04/08 23:19:35 curt
# Adopted Gnu automake/autoconf system.
#
# Revision 1.2 1998/01/21 02:55:53 curt
# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
#
# Revision 1.1 1997/12/08 19:28:54 curt
# Initial revision.
#

57
Tools/FixObj/main.cxx Normal file
View file

@ -0,0 +1,57 @@
// main.cxx -- read and fix the stripping order of a .obj file
//
// Written by Curtis Olson, started December 1997.
//
// Copyright (C) 1997 - 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <stdio.h>
#include "obj.hxx"
int main(int argc, char **argv) {
char infile[256], outfile[256];
if ( argc != 3 ) {
printf("Usage %s: infile outfile\n", argv[0]);
}
strcpy(infile, argv[1]);
strcpy(outfile, argv[2]);
// load the input data files
obj_fix(infile, outfile);
return(0);
}
// $Log$
// Revision 1.1 1998/06/08 17:11:45 curt
// Renamed *.[ch] to *.[ch]xx
//
// Revision 1.2 1998/01/09 23:03:12 curt
// Restructured to split 1deg x 1deg dem's into 64 subsections.
//
// Revision 1.1 1997/12/08 19:28:54 curt
// Initial revision.
//

647
Tools/FixObj/obj.cxx Normal file
View file

@ -0,0 +1,647 @@
// obj.cxx -- routines to handle WaveFront .obj format files.
//
// Written by Curtis Olson, started October 1997.
//
// Copyright (C) 1997 - 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <vector>
#include "Include/compiler.h"
#ifdef NEEDNAMESPACESTD
using namespace std;
#endif
#include "obj.hxx"
#include <Math/mat3.h>
#include <Math/point3d.hxx>
typedef vector < Point3D > container3;
typedef container3::iterator iterator3;
typedef container3::const_iterator const_iterator3;
// what do ya' know, here's some global variables
container3 nodes;
container3 normals;
static int faces[MAXNODES][3];
int vncount, fcount;
static int ccw_list[MAXNODES];
int ccw_list_ptr;
static int cw_list[MAXNODES];
int cw_list_ptr;
FILE *in, *out;
Point3D ref;
// some simple list routines
// reset the list
void list_init(int *list_ptr) {
*list_ptr = 0;
}
// add to list
void list_add(int *list, int *list_ptr, int node) {
if ( *list_ptr >= MAXNODES ) {
printf("ERROR: list overflow in list_add()\n");
exit(-1);
}
list[*list_ptr] = node;
*list_ptr += 1;
// printf("list pointer = %d adding %d\n", *list_ptr, node);
}
// fix the cw list and append to ccw_list
void fix_cw_list(int *list, int list_ptr) {
int i, j, len;
if ( list_ptr < 3 ) {
printf("List is empty ... skipping\n");
return;
}
printf("Fixing cw list, size = %d\n", list_ptr);
i = 0;
while ( i < list_ptr ) {
// do next strip
// find length
len = 0;
// scan rest of strip (until -1)
while ( ((i+len) < list_ptr) && (list[i+len] != -1) ) {
// printf("len = %d item = %d\n", len, list[i+len] );
len++;
}
// printf(" Final length = %d\n", len);
if ( (len % 2) != 0 ) {
// if length is odd, just reverse order of nodes to
// reverse winding
if ( ccw_list_ptr ) {
list_add(ccw_list, &ccw_list_ptr, -1);
}
for ( j = i + len - 1; j >= i; j-- ) {
// printf(" odd -> item = %d\n", list[j] );
list_add(ccw_list, &ccw_list_ptr, list[j]);
}
} else {
// if length is even, reverse order of (n-1) nodes to
// reverse winding, and create an orphan triangle for the
// last "nth" node
if ( ccw_list_ptr ) {
list_add(ccw_list, &ccw_list_ptr, -1);
}
for ( j = i + len - 2; j >= i; j-- ) {
// printf(" even -> item = %d\n", list[j] );
list_add(ccw_list, &ccw_list_ptr, list[j]);
}
// printf(" even bonus -> item = %d\n", list[i + len - 1] );
// printf(" even bonus -> item = %d\n", list[i + len - 2] );
// printf(" even bonus -> item = %d\n", list[i + len - 3] );
list_add(ccw_list, &ccw_list_ptr, -1);
list_add(ccw_list, &ccw_list_ptr, list[i + len - 3]);
list_add(ccw_list, &ccw_list_ptr, list[i + len - 2]);
list_add(ccw_list, &ccw_list_ptr, list[i + len - 1]);
}
i += len + 1;
}
}
void dump_global_bounds( void ) {
double dist_squared, radius, radius_squared;
radius = 0.0;
fprintf(out, "\n");
iterator3 current = nodes.begin();
iterator3 last = nodes.end();
// skip first dummy node
++current;
for ( ; current != last; ++current ) {
dist_squared = ref.distance3Dsquared(*current);
// cout << "node = " << *current << " dist = " << dist_squared << endl;
if ( dist_squared > radius_squared ) {
radius_squared = dist_squared;
}
}
radius = sqrt(radius_squared);
fprintf( out,
"gbs %.5f %.5f %.5f %.2f\n",
ref.x(), ref.y(), ref.z(), radius);
}
// dump nodes
void dump_nodes( void ) {
Point3D p;
fprintf(out, "\n");
iterator3 current = nodes.begin();
iterator3 last = nodes.end();
// skip first dummy node
++current;
for ( ; current != last; ++current ) {
p = *current - ref;
fprintf( out, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
}
}
// dump normals
void dump_normals( void ) {
Point3D p;
fprintf(out, "\n");
iterator3 current = normals.begin();
iterator3 last = normals.end();
// skip first dummy normal
++current;
for ( ; current != last; ++current ) {
p = *current;
fprintf(out, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
}
}
// dump faces
void dump_faces( void ) {
Point3D p;
int i, n1, n2, n3;
double xmax, xmin, ymax, ymin, zmax, zmin, dist, radius;
fprintf(out, "\n");
for ( i = 1; i < fcount; i++ ) {
n1 = faces[i][0];
n2 = faces[i][1];
n3 = faces[i][2];
// calc center of face
xmin = xmax = nodes[n1].x();
ymin = ymax = nodes[n1].y();
zmin = zmax = nodes[n1].z();
if ( nodes[n2].x() < xmin ) { xmin = nodes[n2].x(); }
if ( nodes[n2].x() > xmax ) { xmax = nodes[n2].x(); }
if ( nodes[n2].y() < ymin ) { ymin = nodes[n2].y(); }
if ( nodes[n2].y() > ymax ) { ymax = nodes[n2].y(); }
if ( nodes[n2].z() < zmin ) { zmin = nodes[n2].z(); }
if ( nodes[n2].z() > zmax ) { zmax = nodes[n2].z(); }
if ( nodes[n3].x() < xmin ) { xmin = nodes[n3].x(); }
if ( nodes[n3].x() > xmax ) { xmax = nodes[n3].x(); }
if ( nodes[n3].y() < ymin ) { ymin = nodes[n3].y(); }
if ( nodes[n3].y() > ymax ) { ymax = nodes[n3].y(); }
if ( nodes[n3].z() < zmin ) { zmin = nodes[n3].z(); }
if ( nodes[n3].z() > zmax ) { zmax = nodes[n3].z(); }
p = Point3D( (xmin + xmax) / 2.0,
(ymin + ymax) / 2.0,
(zmin + zmax) / 2.0 );
// calc bounding radius
radius = p.distance3D(nodes[n1]);
dist = p.distance3D(nodes[n2]);
if ( dist > radius ) { radius = dist; }
dist = p.distance3D(nodes[n3]);
if ( dist > radius ) { radius = dist; }
// output data
fprintf(out, "bs %.2f %.2f %.2f %.2f\n", p.x(), p.y(), p.z(), radius);
fprintf(out, "f %d %d %d\n", n1, n2, n3);
}
}
// dump list
void dump_list(int *list, int list_ptr) {
Point3D p;
double xmax, xmin, ymax, ymin, zmax, zmin, dist_squared, radius_squared;
double radius;
int i, j, len, n;
if ( list_ptr < 3 ) {
printf("List is empty ... skipping\n");
return;
}
printf("Dumping list, size = %d\n", list_ptr);
i = 0;
while ( i < list_ptr ) {
// do next strip
if ( (i % 2) == 0 ) {
fprintf(out, "\nusemtl desert1\n");
} else {
fprintf(out, "\nusemtl desert2\n");
}
// find length of next tri strip
len = 0;
// scan rest of strip (until -1)
while ( ((i+len) < list_ptr) && (list[i+len] != -1) ) {
// printf("len = %d item = %d\n", len, list[i+len] );
len++;
}
// printf("strip length = %d\n", len);
// calc center of face
n = list[i];
xmin = xmax = nodes[n].x();
ymin = ymax = nodes[n].y();
zmin = zmax = nodes[n].z();
// printf("%.2f %.2f %.2f\n", nodes[n].x(), nodes[n].y(), nodes[n].z());
for ( j = i + 1; j < i + len; j++ ) {
// printf("j = %d\n", j);
n = list[j];
if ( nodes[n].x() < xmin ) { xmin = nodes[n].x(); }
if ( nodes[n].x() > xmax ) { xmax = nodes[n].x(); }
if ( nodes[n].y() < ymin ) { ymin = nodes[n].y(); }
if ( nodes[n].y() > ymax ) { ymax = nodes[n].y(); }
if ( nodes[n].z() < zmin ) { zmin = nodes[n].z(); }
if ( nodes[n].z() > zmax ) { zmax = nodes[n].z(); }
// printf("%.2f %.2f %.2f\n", nodes[n].x(), nodes[n].y(), nodes[n].z());
}
p = Point3D( (xmin + xmax) / 2.0,
(ymin + ymax) / 2.0,
(zmin + zmax) / 2.0 );
// printf("center = %.2f %.2f %.2f\n", p.x(), p.y(), p.z());
// calc bounding radius
n = list[i];
radius_squared = p.distance3Dsquared(nodes[n]);
for ( j = i + 1; j < i + len; j++ ) {
n = list[j];
dist_squared = p.distance3Dsquared(nodes[n]);
if ( dist_squared > radius_squared ) {
radius_squared = dist_squared;
}
}
radius = sqrt(radius_squared);
// printf("radius = %.2f\n", radius);
// dump bounding sphere and header
fprintf(out, "bs %.2f %.2f %.2f %.2f\n", p.x(), p.y(), p.z(), radius);
fprintf(out, "t %d %d %d\n", list[i], list[i+1], list[i+2]);
// printf("t %d %d %d\n", list[i], list[i+1], list[i+2]);
i += 3;
// dump rest of strip (until -1)
while ( (i < list_ptr) && (list[i] != -1) ) {
fprintf(out, "q %d", list[i]);
i++;
if ( (i < list_ptr) && (list[i] != -1) ) {
fprintf(out, " %d", list[i]);
i++;
}
fprintf(out, "\n");
}
i++;
}
}
// Check the direction the current triangle faces, compared to it's
// pregenerated normal. Returns the dot product between the target
// normal and actual normal. If the dot product is close to 1.0, they
// nearly match. If the are close to -1.0, the are nearly opposite.
double check_cur_face(int n1, int n2, int n3) {
double v1[3], v2[3], approx_normal[3], dot_prod, temp;
// check for the proper rotation by calculating an approximate
// normal and seeing if it is close to the precalculated normal
v1[0] = nodes[n2].x() - nodes[n1].x();
v1[1] = nodes[n2].y() - nodes[n1].y();
v1[2] = nodes[n2].z() - nodes[n1].z();
v2[0] = nodes[n3].x() - nodes[n1].x();
v2[1] = nodes[n3].y() - nodes[n1].y();
v2[2] = nodes[n3].z() - nodes[n1].z();
MAT3cross_product(approx_normal, v1, v2);
MAT3_NORMALIZE_VEC(approx_normal,temp);
dot_prod = MAT3_DOT_PRODUCT(normals[n1], approx_normal);
// not first triangle
// if ( ((dot_prod < -0.5) && !is_backwards) ||
// ((dot_prod > 0.5) && is_backwards) ) {
// printf(" Approx normal = %.2f %.2f %.2f\n", approx_normal[0],
// approx_normal[1], approx_normal[2]);
// printf(" Dot product = %.4f\n", dot_prod);
// }
// angle = acos(dot_prod);
// printf("Normal ANGLE = %.3f rads.\n", angle);
return(dot_prod);
}
// Load a .obj file
void obj_fix(char *infile, char *outfile) {
Point3D node, normal;
char line[256];
double dot_prod;
int first, n1, n2, n3, n4;
double x, y, z, xmax, xmin, ymax, ymin, zmax, zmin;
int is_ccw;
if ( (in = fopen(infile, "r")) == NULL ) {
printf("Cannot open file: %s\n", infile);
exit(-1);
}
if ( (out = fopen(outfile, "w")) == NULL ) {
printf("Cannot open file: %s\n", outfile);
exit(-1);
}
// push dummy records onto the lists since we start counting with "1"
node = Point3D(0.0, 0.0, 0.0);
nodes.push_back(node);
normal = Point3D(0.0, 0.0, 0.0);
normals.push_back(normal);
// initialize other lists
list_init(&ccw_list_ptr);
list_init(&cw_list_ptr);
// I start counting at one because that is how the triangle
// program refers to nodes and normals
first = 1;
vncount = 1;
fcount = 1;
printf("Reading file: %s\n", infile);
while ( fgets(line, 250, in) != NULL ) {
if ( line[0] == '#' ) {
// pass along the comments verbatim
fprintf(out, "%s", line);
} else if ( strlen(line) <= 1 ) {
// don't pass along empty lines
// fprintf(out, "%s", line);
} else if ( strncmp(line, "v ", 2) == 0 ) {
// save vertex to memory and output to file
// printf("vertex = %s", line);
sscanf(line, "v %lf %lf %lf\n", &x, &y, &z);
if ( nodes.size() == 1 ) {
// first time through set min's and max'es
xmin = x;
xmax = x;
ymin = y;
ymax = y;
zmin = z;
zmax = z;
} else {
// update min/max vertex values
if ( x < xmin ) xmin = x;
if ( x > xmax ) xmax = x;
if ( y < ymin ) ymin = y;
if ( y > ymax ) ymax = y;
if ( z < zmin ) zmin = z;
if ( z > zmax ) zmax = z;
}
node = Point3D(x, y, z);
nodes.push_back(node);
// fprintf(out, "v %.2f %.2f %.2f\n",
// node.x(), node.y(), node.z());
} else if ( strncmp(line, "vn ", 3) == 0 ) {
// save vertex normals to memory and output to file
// printf("vertex normal = %s", line);
sscanf(line, "vn %lf %lf %lf\n", &x, &y, &z);
normal = Point3D(x, y, z);
normals.push_back(normal);
} else if ( line[0] == 't' ) {
// starting a new triangle strip
printf("Starting a new triangle strip\n");
n1 = n2 = n3 = n4 = 0;
printf("new tri strip = %s", line);
sscanf(line, "t %d %d %d %d\n", &n1, &n2, &n3, &n4);
// special cases to handle bugs in our beloved tri striper
if ( (n1 == 4) && (n2 == 2) && (n3 == 2) && (n4 == 1) ) {
n2 = 3;
}
if ( (n1 == 3) && (n2 == 1) && (n3 == 1) && (n4 == 0) ) {
n3 = 4;
}
dot_prod = check_cur_face(n1, n2, n3);
if ( dot_prod < 0.0 ) {
// this stripe is backwards (CW)
is_ccw = 0;
printf(" -> Starting a backwards stripe\n");
} else {
// this stripe is normal (CCW)
is_ccw = 1;
}
if ( is_ccw ) {
if ( ccw_list_ptr ) {
list_add(ccw_list, &ccw_list_ptr, -1);
}
list_add(ccw_list, &ccw_list_ptr, n1);
list_add(ccw_list, &ccw_list_ptr, n2);
list_add(ccw_list, &ccw_list_ptr, n3);
} else {
if ( cw_list_ptr ) {
list_add(cw_list, &cw_list_ptr, -1);
}
list_add(cw_list, &cw_list_ptr, n1);
list_add(cw_list, &cw_list_ptr, n2);
list_add(cw_list, &cw_list_ptr, n3);
}
if ( n4 > 0 ) {
if ( is_ccw ) {
list_add(ccw_list, &ccw_list_ptr, n4);
} else {
list_add(cw_list, &cw_list_ptr, n4);
}
}
} else if ( line[0] == 'f' ) {
if ( fcount < MAXNODES ) {
// pass along the unoptimized faces verbatim
sscanf(line, "f %d %d %d\n", &n1, &n2, &n3);
faces[fcount][0] = n1;
faces[fcount][1] = n2;
faces[fcount][2] = n3;
fcount++;
} else {
printf("Read too many unoptimized faces ... dying :-(\n");
exit(-1);
}
// fprintf(out, "%s", line);
} else if ( line[0] == 'q' ) {
// continue a triangle strip
n1 = n2 = 0;
// printf("continued tri strip = %s ", line);
sscanf(line, "q %d %d\n", &n1, &n2);
if ( is_ccw ) {
list_add(ccw_list, &ccw_list_ptr, n1);
} else {
list_add(cw_list, &cw_list_ptr, n1);
}
if ( n2 > 0 ) {
if ( is_ccw ) {
list_add(ccw_list, &ccw_list_ptr, n2);
} else {
list_add(cw_list, &cw_list_ptr, n2);
}
}
} else {
printf("Unknown line in %s = %s\n", infile, line);
}
}
// reference point is the "center"
ref = Point3D( (xmin + xmax) / 2.0,
(ymin + ymax) / 2.0,
(zmin + zmax) / 2.0 );
// convert the cw_list to ccw add append to ccw_list
fix_cw_list(cw_list, cw_list_ptr);
dump_global_bounds();
dump_nodes();
dump_normals();
if ( fcount > 1 ) {
dump_faces();
}
dump_list(ccw_list, ccw_list_ptr);
fclose(in);
fclose(out);
}
// $Log$
// Revision 1.3 1999/02/01 21:09:40 curt
// Optimizations from Norman Vine.
//
// Revision 1.2 1998/10/21 14:55:55 curt
// Converted to Point3D class.
//
// Revision 1.1 1998/06/08 17:11:46 curt
// Renamed *.[ch] to *.[ch]xx
//
// Revision 1.16 1998/05/27 02:27:22 curt
// Commented out a couple of debugging messages.
//
// Revision 1.15 1998/05/24 02:47:47 curt
// For each strip, specify a default material property and calculate a center
// and bounding sphere.
//
// Revision 1.14 1998/05/23 15:19:49 curt
// Output more digits after the decimal place.
//
// Revision 1.13 1998/05/20 20:55:19 curt
// Fixed arbitrary polygon winding problem here so all tristrips are passed
// to runtime simulator with a consistant counter clockwise winding.
//
// Revision 1.12 1998/05/16 13:11:26 curt
// Fixed an off by one error in node, normal, and face counters.
//
// Revision 1.11 1998/04/27 15:59:24 curt
// Fixed an off by one error.
//
// Revision 1.10 1998/04/27 03:33:11 curt
// Code now calculates a center reference points and outputs everything
// relative to that. This is useful in the rendering engine to keep everything
// close to (0, 0, 0) where we can avoid many GLfloat precision problems.
//
// Revision 1.9 1998/04/18 04:01:03 curt
// Now use libMath rather than having local copies of math routines.
//
// Revision 1.8 1998/04/08 23:19:37 curt
// Adopted Gnu automake/autoconf system.
//
// Revision 1.7 1998/03/19 02:51:41 curt
// Added special case handling to compensate for bugs in our beloved tri striper
//
// Revision 1.6 1998/03/03 15:36:12 curt
// Tweaks for compiling with g++
//
// Revision 1.5 1998/03/03 03:37:03 curt
// Cumulative tweaks.
//
// Revision 1.4 1998/01/31 00:41:25 curt
// Made a few changes converting floats to doubles.
//
// Revision 1.3 1998/01/19 19:51:07 curt
// A couple final pre-release tweaks.
//
// Revision 1.2 1998/01/09 23:03:12 curt
// Restructured to split 1deg x 1deg dem's into 64 subsections.
//
// Revision 1.1 1997/12/08 19:28:54 curt
// Initial revision.
//

60
Tools/FixObj/obj.hxx Normal file
View file

@ -0,0 +1,60 @@
// obj.hxx -- routines to handle WaveFront .obj format files.
//
// Written by Curtis Olson, started October 1997.
//
// Copyright (C) 1997 - 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifndef OBJ_HXX
#define OBJ_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#define MAXNODES 100000
// Load a .obj file
void obj_fix(char *infile, char *outfile);
#endif // OBJ_HXX
// $Log$
// Revision 1.1 1998/06/08 17:11:46 curt
// Renamed *.[ch] to *.[ch]xx
//
// Revision 1.4 1998/03/03 15:36:13 curt
// Tweaks for compiling with g++
//
// Revision 1.3 1998/01/31 00:41:25 curt
// Made a few changes converting floats to doubles.
//
// Revision 1.2 1998/01/09 23:03:13 curt
// Restructured to split 1deg x 1deg dem's into 64 subsections.
//
// Revision 1.1 1997/12/08 19:28:55 curt
// Initial revision.
//

View file

@ -0,0 +1,86 @@
#---------------------------------------------------------------------------
# Makefile
#
# Written by Curtis Olson, started January 1998.
#
# Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id$
# (Log is kept at end of this file)
#---------------------------------------------------------------------------
bin_PROGRAMS = genapts
genapts_SOURCES = \
area.cxx area.hxx \
convex_hull.cxx convex_hull.hxx \
main.cxx \
point2d.cxx point2d.hxx
genapts_LDADD = \
$(top_builddir)/Tools/Lib/Polygon/libPolygon.a \
$(top_builddir)/Lib/Bucket/libBucket.a \
$(top_builddir)/Lib/Debug/libDebug.a \
$(top_builddir)/Lib/Misc/libMisc.a \
$(top_builddir)/Lib/zlib/libz.a \
$(base_LIBS)
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib
#---------------------------------------------------------------------------
# $Log$
# Revision 1.6 1999/03/08 22:00:47 curt
# Lots of directory layout reorganization.
#
# Revision 1.5 1999/02/25 21:32:47 curt
# Modified to adhere to new polygon naming convention, and also to read the
# new Robin Peel aiport format.
#
# Revision 1.4 1999/02/11 01:10:50 curt
# Start of scenery revamp project.
#
# Revision 1.3 1998/11/04 23:01:54 curt
# Changes to the automake/autoconf system to reduce the number of libraries
# that are unnecessarily linked into the various executables.
#
# Revision 1.2 1998/09/04 23:04:47 curt
# Beginning of convex hull genereration routine.
#
# Revision 1.1 1998/09/01 19:34:32 curt
# Initial revision.
#
# Revision 1.2 1998/07/30 23:49:18 curt
# Removed libtool support.
#
# Revision 1.1 1998/07/20 12:54:53 curt
# Whoops, need to commit Makefile.am, not Makefile.
#
# Revision 1.2 1998/04/14 02:25:59 curt
# Code reorganizations. Added a Lib/ directory for more general libraries.
#
# Revision 1.1 1998/04/08 22:54:57 curt
# Adopted Gnu automake/autoconf system.
#
# Revision 1.2 1998/01/21 02:55:46 curt
# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
#
# Revision 1.1 1998/01/15 02:45:25 curt
# Initial revision.
#

241
Tools/GenAirports/area.cxx Normal file
View file

@ -0,0 +1,241 @@
// area.c -- routines to assist with inserting "areas" into FG terrain
//
// Written by Curtis Olson, started March 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#include <math.h>
#include <stdio.h>
#include <Include/fg_constants.h>
#include "area.hxx"
#include "point2d.hxx"
// calc new x, y for a rotation
double rot_x(double x, double y, double theta) {
return ( x * cos(theta) + y * sin(theta) );
}
// calc new x, y for a rotation
double rot_y(double x, double y, double theta) {
return ( -x * sin(theta) + y * cos(theta) );
}
// calc new lon/lat given starting lon/lat, and offset radial, and
// distance. NOTE: distance is specified in meters (and converted
// internally to radians)
point2d calc_lon_lat( point2d orig, point2d offset ) {
point2d result;
// printf("calc_lon_lat() offset.theta = %.2f offset.dist = %.2f\n",
// offset.theta, offset.dist);
offset.dist *= METER_TO_NM * NM_TO_RAD;
result.lat = asin( sin(orig.lat) * cos(offset.dist) +
cos(orig.lat) * sin(offset.dist) * cos(offset.theta) );
if ( cos(result.lat) < FG_EPSILON ) {
result.lon = orig.lon; // endpoint a pole
} else {
result.lon =
fmod(orig.lon - asin( sin(offset.theta) * sin(offset.dist) /
cos(result.lat) ) + FG_PI, FG_2PI) - FG_PI;
}
return(result);
}
list < point2d >
batch_cart_to_polar_2d( list < point2d > in_list)
{
list < point2d > out_list;
list < point2d > :: iterator current;
list < point2d > :: iterator last;
point2d p;
current = in_list.begin();
last = in_list.end();
for ( ; current != last ; ++current ) {
p = cart_to_polar_2d( *current );
out_list.push_back(p);
}
return out_list;
}
// given a set of 2d coordinates relative to a center point, and the
// lon, lat of that center point (specified in degrees), as well as a
// potential orientation angle, generate the corresponding lon and lat
// of the original 2d verticies.
list < point2d >
gen_area(point2d origin, double angle, list < point2d > cart_list)
{
list < point2d > rad_list;
list < point2d > result_list;
list < point2d > :: iterator current;
list < point2d > :: iterator last;
point2d origin_rad, p;
origin_rad.lon = origin.lon * DEG_TO_RAD;
origin_rad.lat = origin.lat * DEG_TO_RAD;
// convert to polar coordinates
rad_list = batch_cart_to_polar_2d(cart_list);
/*
// display points
printf("converted to polar\n");
current = rad_list.begin();
last = rad_list.end();
while ( current != last ) {
printf("(%.2f, %.2f)\n", current->theta, current->dist);
++current;
}
printf("\n");
*/
// rotate by specified angle
// printf("Rotating points by %.2f\n", angle);
current = rad_list.begin();
last = rad_list.end();
for ( ; current != last ; ++current ) {
current->theta -= angle;
while ( current->theta > FG_2PI ) {
current->theta -= FG_2PI;
// (*current).theta -= angle;
// while ( (*current).theta > FG_2PI ) {
// (*current).theta -= FG_2PI;
}
// printf("(%.2f, %.2f)\n", current->theta, current->dist);
}
// printf("\n");
// find actual lon,lat of coordinates
// printf("convert to lon, lat relative to %.2f %.2f\n",
// origin.lon, origin.lat);
current = rad_list.begin();
last = rad_list.end();
for ( ; current != last ; ++current ) {
p = calc_lon_lat(origin_rad, *current);
// convert from radians to degress
p.lon *= RAD_TO_DEG;
p.lat *= RAD_TO_DEG;
// printf("(%.8f, %.8f)\n", p.lon, p.lat);
result_list.push_back(p);
}
// printf("\n");
return result_list;
}
// generate an area for a runway
list < point2d >
gen_runway_area( double lon, double lat, double heading,
double length, double width)
{
list < point2d > result_list;
list < point2d > tmp_list;
list < point2d > :: iterator current;
list < point2d > :: iterator last;
point2d p;
point2d origin;
double l, w;
int i;
/*
printf("runway: lon = %.2f lat = %.2f hdg = %.2f len = %.2f width = %.2f\n",
lon, lat, heading, length, width);
*/
origin.lon = lon;
origin.lat = lat;
l = length / 2.0;
w = width / 2.0;
// generate untransformed runway area vertices
p.x = l; p.y = w; tmp_list.push_back(p);
p.x = l; p.y = -w; tmp_list.push_back(p);
p.x = -l; p.y = -w; tmp_list.push_back(p);
p.x = -l; p.y = w; tmp_list.push_back(p);
/*
// display points
printf("Untransformed, unrotated runway\n");
current = tmp_list.begin();
last = tmp_list.end();
while ( current != last ) {
printf("(%.2f, %.2f)\n", current->x, current->y);
++current;
}
printf("\n");
*/
// rotate, transform, and convert points to lon, lat in degrees
result_list = gen_area(origin, heading, tmp_list);
/*
// display points
printf("Results in radians.\n");
current = result_list.begin();
last = result_list.end();
while ( current != last ) {
printf("(%.8f, %.8f)\n", current->lon, current->lat);
++current;
}
printf("\n");
*/
return result_list;
}
// $Log$
// Revision 1.5 1998/10/20 15:49:54 curt
// tweak ...
//
// Revision 1.4 1998/09/09 20:59:53 curt
// Loop construct tweaks for STL usage.
// Output airport file to be used to generate airport scenery on the fly
// by the run time sim.
//
// Revision 1.3 1998/09/09 16:26:31 curt
// Continued progress in implementing the convex hull algorithm.
//
// Revision 1.2 1998/09/04 23:04:48 curt
// Beginning of convex hull genereration routine.
//
// Revision 1.1 1998/09/01 19:34:33 curt
// Initial revision.
//
// Revision 1.1 1998/07/20 12:54:05 curt
// Initial revision.
//
//

View file

@ -0,0 +1,54 @@
// area.h -- routines to assist with inserting "areas" into FG terrain
//
// Written by Curtis Olson, started February 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#ifndef _AREA_H
#define _AREA_H
#include <list>
#include "point2d.hxx"
// generate an area for a runway (return result points in degrees)
list < point2d >
gen_runway_area( double lon, double lat, double heading,
double length, double width);
#endif // _AREA_H
// $Log$
// Revision 1.2 1998/09/04 23:04:49 curt
// Beginning of convex hull genereration routine.
//
// Revision 1.1 1998/09/01 19:34:33 curt
// Initial revision.
//
// Revision 1.1 1998/07/20 12:54:05 curt
// Initial revision.
//
//

View file

@ -0,0 +1,277 @@
// convex_hull.cxx -- calculate the convex hull of a set of points
//
// Written by Curtis Olson, started September 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#include <math.h>
#include <stdio.h>
#include <list>
#include <map>
#ifdef NEEDNAMESPACESTD
using namespace std;
#endif
#include <Include/fg_constants.h>
#include "convex_hull.hxx"
#include "point2d.hxx"
// stl map typedefs
typedef map < double, double, less<double> > map_container;
typedef map_container::iterator map_iterator;
// Calculate theta of angle (a, b, c)
double calc_angle(point2d a, point2d b, point2d c) {
point2d u, v;
double udist, vdist, uv_dot, tmp;
// u . v = ||u|| * ||v|| * cos(theta)
u.x = b.x - a.x;
u.y = b.y - a.y;
udist = sqrt( u.x * u.x + u.y * u.y );
// printf("udist = %.6f\n", udist);
v.x = b.x - c.x;
v.y = b.y - c.y;
vdist = sqrt( v.x * v.x + v.y * v.y );
// printf("vdist = %.6f\n", vdist);
uv_dot = u.x * v.x + u.y * v.y;
// printf("uv_dot = %.6f\n", uv_dot);
tmp = uv_dot / (udist * vdist);
// printf("tmp = %.6f\n", tmp);
return acos(tmp);
}
// Test to see if angle(Pa, Pb, Pc) < 180 degrees
bool test_point(point2d Pa, point2d Pb, point2d Pc) {
point2d origin, a, b, c;
double a1, a2;
origin.x = origin.y = 0.0;
a.x = cos(Pa.theta) * Pa.dist;
a.y = sin(Pa.theta) * Pa.dist;
b.x = cos(Pb.theta) * Pb.dist;
b.y = sin(Pb.theta) * Pb.dist;
c.x = cos(Pc.theta) * Pc.dist;
c.y = sin(Pc.theta) * Pc.dist;
// printf("a is %.6f %.6f\n", a.x, a.y);
// printf("b is %.6f %.6f\n", b.x, b.y);
// printf("c is %.6f %.6f\n", c.x, c.y);
a1 = calc_angle(a, b, origin);
a2 = calc_angle(origin, b, c);
// printf("a1 = %.2f a2 = %.2f\n", a1 * RAD_TO_DEG, a2 * RAD_TO_DEG);
return ( (a1 + a2) < FG_PI );
}
// calculate the convex hull of a set of points, return as a list of
// point2d. The algorithm description can be found at:
// http://riot.ieor.berkeley.edu/riot/Applications/ConvexHull/CHDetails.html
list_container convex_hull( list_container input_list )
{
list_iterator current, last;
map_iterator map_current, map_next, map_next_next, map_last;
// list of translated points
list_container trans_list;
// points sorted by radian degrees
map_container radians_map;
// will contain the convex hull
list_container con_hull;
point2d p, average, Pa, Pb, Pc, result;
double sum_x, sum_y;
int in_count, last_size;
// STEP ONE: Find an average midpoint of the input set of points
current = input_list.begin();
last = input_list.end();
in_count = input_list.size();
sum_x = sum_y = 0.0;
for ( ; current != last ; ++current ) {
sum_x += (*current).x;
sum_y += (*current).y;
}
average.x = sum_x / in_count;
average.y = sum_y / in_count;
// printf("Average center point is %.4f %.4f\n", average.x, average.y);
// STEP TWO: Translate input points so average is at origin
current = input_list.begin();
last = input_list.end();
trans_list.erase( trans_list.begin(), trans_list.end() );
for ( ; current != last ; ++current ) {
p.x = (*current).x - average.x;
p.y = (*current).y - average.y;
// printf("%.6f %.6f\n", p.x, p.y);
trans_list.push_back(p);
}
// STEP THREE: convert to radians and sort by theta
current = trans_list.begin();
last = trans_list.end();
radians_map.erase( radians_map.begin(), radians_map.end() );
for ( ; current != last ; ++current) {
p = cart_to_polar_2d(*current);
if ( p.dist > radians_map[p.theta] ) {
radians_map[p.theta] = p.dist;
}
}
// printf("Sorted list\n");
map_current = radians_map.begin();
map_last = radians_map.end();
for ( ; map_current != map_last ; ++map_current ) {
p.x = (*map_current).first;
p.y = (*map_current).second;
// printf("p is %.6f %.6f\n", p.x, p.y);
}
// STEP FOUR: traverse the sorted list and eliminate everything
// not on the perimeter.
// printf("Traversing list\n");
// double check list size ... this should never fail because a
// single runway will always generate four points.
if ( radians_map.size() < 3 ) {
cout << "convex hull not possible with < 3 points" << endl;
exit(-1);
}
// ensure that we run the while loop at least once
last_size = radians_map.size() + 1;
while ( last_size > radians_map.size() ) {
// printf("Running an iteration of the graham scan algorithm\n");
last_size = radians_map.size();
map_current = radians_map.begin();
while ( map_current != radians_map.end() ) {
// get first element
Pa.theta = (*map_current).first;
Pa.dist = (*map_current).second;
// get second element
map_next = map_current;
++map_next;
if ( map_next == radians_map.end() ) {
map_next = radians_map.begin();
}
Pb.theta = (*map_next).first;
Pb.dist = (*map_next).second;
// get third element
map_next_next = map_next;
++map_next_next;
if ( map_next_next == radians_map.end() ) {
map_next_next = radians_map.begin();
}
Pc.theta = (*map_next_next).first;
Pc.dist = (*map_next_next).second;
// printf("Pa is %.6f %.6f\n", Pa.theta, Pa.dist);
// printf("Pb is %.6f %.6f\n", Pb.theta, Pb.dist);
// printf("Pc is %.6f %.6f\n", Pc.theta, Pc.dist);
if ( test_point(Pa, Pb, Pc) ) {
// printf("Accepted a point\n");
// accept point, advance Pa, Pb, and Pc.
++map_current;
} else {
// printf("REJECTED A POINT\n");
// reject point, delete it and advance only Pb and Pc
map_next = map_current;
++map_next;
if ( map_next == radians_map.end() ) {
map_next = radians_map.begin();
}
radians_map.erase( map_next );
}
}
}
// translate back to correct lon/lat
// printf("Final sorted convex hull\n");
con_hull.erase( con_hull.begin(), con_hull.end() );
map_current = radians_map.begin();
map_last = radians_map.end();
for ( ; map_current != map_last ; ++map_current ) {
p.theta = (*map_current).first;
p.dist = (*map_current).second;
result.x = cos(p.theta) * p.dist + average.x;
result.y = sin(p.theta) * p.dist + average.y;
// printf("%.6f %.6f\n", result.x, result.y);
con_hull.push_back(result);
}
return con_hull;
}
// $Log$
// Revision 1.5 1999/02/25 21:32:48 curt
// Modified to adhere to new polygon naming convention, and also to read the
// new Robin Peel aiport format.
//
// Revision 1.4 1998/09/17 18:40:42 curt
// Debug message tweaks.
//
// Revision 1.3 1998/09/09 20:59:55 curt
// Loop construct tweaks for STL usage.
// Output airport file to be used to generate airport scenery on the fly
// by the run time sim.
//
// Revision 1.2 1998/09/09 16:26:32 curt
// Continued progress in implementing the convex hull algorithm.
//
// Revision 1.1 1998/09/04 23:04:51 curt
// Beginning of convex hull genereration routine.
//
//

View file

@ -0,0 +1,60 @@
// convex_hull.hxx -- calculate the convex hull of a set of points
//
// Written by Curtis Olson, started September 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#ifndef _CONVEX_HULL_HXX
#define _CONVEX_HULL_HXX
#include <list>
#ifdef NEEDNAMESPACESTD
using namespace std;
#endif
#include "point2d.hxx"
// stl list typedefs
typedef list < point2d > list_container;
typedef list_container::iterator list_iterator;
// calculate the convex hull of a set of points, return as a list of
// point2d. The algorithm description can be found at:
// http://riot.ieor.berkeley.edu/riot/Applications/ConvexHull/CHDetails.html
list_container convex_hull( list_container input_list );
#endif // _CONVEX_HULL_HXX
// $Log$
// Revision 1.2 1998/09/09 16:26:33 curt
// Continued progress in implementing the convex hull algorithm.
//
// Revision 1.1 1998/09/04 23:04:51 curt
// Beginning of convex hull genereration routine.
//
//

374
Tools/GenAirports/main.cxx Normal file
View file

@ -0,0 +1,374 @@
// main.cxx -- main loop
//
// Written by Curtis Olson, started March 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <Include/compiler.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <list>
#include <stdio.h>
#include <string.h>
#include STL_STRING
#include <Bucket/newbucket.hxx>
#include <Debug/logstream.hxx>
#include <Include/fg_constants.h>
#include <Misc/fgstream.hxx>
#include <Polygon/index.hxx>
#include "area.hxx"
#include "convex_hull.hxx"
// write out airport data
void write_airport( long int p_index, list_container hull_list, FGBucket b,
const string& root, const bool cut_and_keep ) {
char tile_name[256], poly_index[256];
string base = b.gen_base_path();
string path = root + "/Scenery/" + base;
string command = "mkdir -p " + path;
system( command.c_str() );
long int b_index = b.gen_index();
sprintf(tile_name, "%ld", b_index);
string aptfile = path + "/" + tile_name;
sprintf( poly_index, "%ld", p_index );
aptfile += ".";
aptfile += poly_index;
cout << "apt file = " << aptfile << endl;
FILE *fd;
if ( (fd = fopen(aptfile.c_str(), "a")) == NULL ) {
cout << "Cannot open file: " << aptfile << endl;
exit(-1);
}
// polygon type
if ( cut_and_keep ) {
fprintf( fd, "AirportKeep\n" );
} else {
fprintf( fd, "AirportIgnore\n" );
}
// number of contours
fprintf( fd, "1\n" );
// size of first contour
fprintf( fd, "%d\n", hull_list.size() );
// write contour (polygon) points
list_iterator current = hull_list.begin();
list_iterator last = hull_list.end();
for ( ; current != last ; ++current ) {
fprintf( fd, "%.7f %.7f\n", (*current).lon, (*current).lat );
}
fclose(fd);
}
// process and airport + runway list
void process_airport( string airport, list < string > & runway_list,
const string& root ) {
list_container rwy_list, apt_list, hull_list;
list_iterator current, last;
// parse main airport information
int elev;
cout << airport << endl;
string apt_type = airport.substr(0, 1);
string apt_code = airport.substr(2, 4);
string apt_lat = airport.substr(7, 10);
string apt_lon = airport.substr(18, 11);
string apt_elev = airport.substr(30, 5);
sscanf( apt_elev.c_str(), "%d", &elev );
string apt_use = airport.substr(36, 1);
string apt_twr = airport.substr(37, 1);
string apt_bldg = airport.substr(38, 1);
string apt_name = airport.substr(40);
/*
cout << " type = " << apt_type << endl;
cout << " code = " << apt_code << endl;
cout << " lat = " << apt_lat << endl;
cout << " lon = " << apt_lon << endl;
cout << " elev = " << apt_elev << " " << elev << endl;
cout << " use = " << apt_use << endl;
cout << " twr = " << apt_twr << endl;
cout << " bldg = " << apt_bldg << endl;
cout << " name = " << apt_name << endl;
*/
// parse runways and generate the vertex list
string rwy_str;
double lon, lat, hdg;
int len, width;
list < string >::iterator last_runway = runway_list.end();
for ( list < string >::iterator current_runway = runway_list.begin();
current_runway != last_runway ; ++current_runway ) {
rwy_str = (*current_runway);
cout << rwy_str << endl;
string rwy_no = rwy_str.substr(2, 4);
string rwy_lat = rwy_str.substr(6, 10);
sscanf( rwy_lat.c_str(), "%lf", &lat);
string rwy_lon = rwy_str.substr(17, 11);
sscanf( rwy_lon.c_str(), "%lf", &lon);
string rwy_hdg = rwy_str.substr(29, 7);
sscanf( rwy_hdg.c_str(), "%lf", &hdg);
string rwy_len = rwy_str.substr(36, 7);
sscanf( rwy_len.c_str(), "%d", &len);
string rwy_width = rwy_str.substr(43, 4);
sscanf( rwy_width.c_str(), "%d", &width);
string rwy_sfc = rwy_str.substr(47, 4);
string rwy_end1 = rwy_str.substr(52, 8);
string rwy_end2 = rwy_str.substr(61, 8);
/*
cout << " no = " << rwy_no << endl;
cout << " lat = " << rwy_lat << " " << lat << endl;
cout << " lon = " << rwy_lon << " " << lon << endl;
cout << " hdg = " << rwy_hdg << " " << hdg << endl;
cout << " len = " << rwy_len << " " << len << endl;
cout << " width = " << rwy_width << " " << width << endl;
cout << " sfc = " << rwy_sfc << endl;
cout << " end1 = " << rwy_end1 << endl;
cout << " end2 = " << rwy_end2 << endl;
*/
rwy_list = gen_runway_area( lon, lat, hdg * DEG_TO_RAD,
(double)len * FEET_TO_METER,
(double)width * FEET_TO_METER );
// add rwy_list to apt_list
current = rwy_list.begin();
last = rwy_list.end();
for ( ; current != last ; ++current ) {
apt_list.push_back(*current);
}
}
if ( apt_list.size() == 0 ) {
cout << "no runway points generated" << endl;
return;
}
// printf("Runway points in degrees\n");
// current = apt_list.begin();
// last = apt_list.end();
// for ( ; current != last; ++current ) {
// printf( "%.5f %.5f\n", current->lon, current->lat );
// }
// printf("\n");
// generate convex hull
hull_list = convex_hull(apt_list);
// get next polygon index
long int index = poly_index_next();
// find average center, min, and max point of convex hull
point2d average, min, max;
double sum_x, sum_y;
int count = hull_list.size();
current = hull_list.begin();
last = hull_list.end();
sum_x = sum_y = 0.0;
min.x = min.y = 200.0;
max.x = max.y = -200.0;
for ( ; current != last; ++current ) {
// printf("return = %.6f %.6f\n", (*current).x, (*current).y);
sum_x += (*current).x;
sum_y += (*current).y;
if ( (*current).x < min.x ) { min.x = (*current).x; }
if ( (*current).y < min.y ) { min.y = (*current).y; }
if ( (*current).x > max.x ) { max.x = (*current).x; }
if ( (*current).y > max.y ) { max.y = (*current).y; }
}
average.x = sum_x / count;
average.y = sum_y / count;
// find buckets for center, min, and max points of convex hull.
// note to self: self, you should think about checking for runways
// that span the data line
FGBucket b(average.lon, average.lat);
FGBucket b_min(min.x, min.y);
FGBucket b_max(max.x, max.y);
cout << "Bucket center = " << b << endl;
cout << "Bucket min = " << b_min << endl;
cout << "Bucket max = " << b_max << endl;
if ( b_min == b_max ) {
write_airport( index, hull_list, b, root, true );
} else {
FGBucket b_cur;
int dx, dy, i, j;
fgBucketDiff(b_min, b_max, &dx, &dy);
cout << "airport spans tile boundaries" << endl;
cout << " dx = " << dx << " dy = " << dy << endl;
if ( (dx > 2) || (dy > 2) ) {
cout << "somethings really wrong!!!!" << endl;
exit(-1);
}
for ( j = 0; j <= dy; j++ ) {
for ( i = 0; i <= dx; i++ ) {
b_cur = fgBucketOffset(min.x, min.y, i, j);
if ( b_cur == b ) {
write_airport( index, hull_list, b_cur, root, true );
} else {
write_airport( index, hull_list, b_cur, root, false );
}
}
}
// string answer; cin >> answer;
}
}
// reads the apt_full file and extracts and processes the individual
// airport records
int main( int argc, char **argv ) {
list < string > runway_list;
string airport, last_airport;
string line;
char tmp[256];
fglog().setLogLevels( FG_ALL, FG_DEBUG );
if ( argc != 3 ) {
FG_LOG( FG_GENERAL, FG_ALERT,
"Usage " << argv[0] << " <apt_file> <work_dir>" );
exit(-1);
}
// make work directory
string work_dir = argv[2];
string command = "mkdir -p " + work_dir;
system( command.c_str() );
// initialize persistant polygon counter
string counter_file = work_dir + "/../work.counter";
poly_index_init( counter_file );
fg_gzifstream in( argv[1] );
if ( !in ) {
FG_LOG( FG_GENERAL, FG_ALERT, "Cannot open file: " << argv[1] );
exit(-1);
}
// throw away the first 3 lines
in.getline(tmp, 256);
in.getline(tmp, 256);
in.getline(tmp, 256);
last_airport = "";
while ( ! in.eof() ) {
in.getline(tmp, 256);
line = tmp;
// cout << line << endl;
if ( line.length() == 0 ) {
// empty, skip
} else if ( line[0] == '#' ) {
// comment, skip
} else if ( (line[0] == 'A') || (line[0] == 'S') ) {
// start of airport record
airport = line;
if ( last_airport.length() ) {
// process previous record
process_airport(last_airport, runway_list, argv[2]);
}
// clear runway list for start of next airport
runway_list.erase(runway_list.begin(), runway_list.end());
last_airport = airport;
} else if ( line[0] == 'R' ) {
// runway entry
runway_list.push_back(line);
} else if ( line == "[End]" ) {
// end of file
break;
} else {
FG_LOG( FG_GENERAL, FG_ALERT,
"Unknown line in file" << endl << line );
exit(-1);
}
}
if ( last_airport.length() ) {
// process previous record
process_airport(last_airport, runway_list, argv[2]);
}
return 0;
}
// $Log$
// Revision 1.11 1999/03/19 00:27:38 curt
// Use long int for index instead of just int.
//
// Revision 1.10 1999/03/17 23:51:25 curt
// Changed polygon index counter file.
//
// Revision 1.9 1999/03/12 22:54:19 curt
// Rearrange a bit of code ...
//
// Revision 1.8 1999/03/01 15:35:26 curt
// Fixed bug in output format generated.
//
// Revision 1.7 1999/02/25 21:32:49 curt
// Modified to adhere to new polygon naming convention, and also to read the
// new Robin Peel aiport format.
//
// Revision 1.6 1999/02/11 01:10:51 curt
// Start of scenery revamp project.
//
// Revision 1.5 1998/09/17 18:40:43 curt
// Debug message tweaks.
//
// Revision 1.4 1998/09/09 20:59:56 curt
// Loop construct tweaks for STL usage.
// Output airport file to be used to generate airport scenery on the fly
// by the run time sim.
//
//

View file

@ -0,0 +1,45 @@
// point2d.cxx -- 2d coordinate routines
//
// Written by Curtis Olson, started September 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#include <math.h>
#include "point2d.hxx"
// convert a point from cartesian to polar coordinates
point2d cart_to_polar_2d(point2d in) {
point2d result;
result.dist = sqrt( in.x * in.x + in.y * in.y );
result.theta = atan2(in.y, in.x);
return(result);
}
// $Log$
// Revision 1.1 1998/09/04 23:04:53 curt
// Beginning of convex hull genereration routine.
//
//

View file

@ -0,0 +1,59 @@
// point2d.hxx -- define a 2d point class
//
// Written by Curtis Olson, started February 1998.
//
// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
//
#ifndef _POINT2D_HXX
#define _POINT2D_HXX
#include <list>
class point2d {
public:
union {
double x;
double dist;
double lon;
};
union {
double y;
double theta;
double lat;
};
};
// convert a point from cartesian to polar coordinates
point2d cart_to_polar_2d(point2d in);
#endif // _POINT2D_HXX
// $Log$
// Revision 1.1 1998/09/04 23:04:53 curt
// Beginning of convex hull genereration routine.
//
//

View file

@ -0,0 +1,9 @@
noinst_LIBRARIES = libGenOutput.a
libGenOutput_a_SOURCES = genobj.cxx genobj.hxx
INCLUDES += \
-I$(top_builddir) \
-I$(top_builddir)/Lib \
-I$(top_builddir)/Tools/Lib \
-I$(top_builddir)/Tools/Construct

469
Tools/GenOutput/genobj.cxx Normal file
View file

@ -0,0 +1,469 @@
// genobj.hxx -- Generate the flight gear "obj" file format from the
// triangle output
//
// Written by Curtis Olson, started March 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <time.h>
#include <Math/mat3.h>
#include <Polygon/names.hxx>
#include <Tools/scenery_version.hxx>
#include "genobj.hxx"
// build the wgs-84 point list
void FGGenOutput::gen_wgs84_points( const FGArray& array ) {
cout << "calculating wgs84 point" << endl;
Point3D geod, radians, cart;
const_point_list_iterator current = geod_nodes.begin();
const_point_list_iterator last = geod_nodes.end();
double real_z;
for ( ; current != last; ++current ) {
geod = *current;
real_z = array.interpolate_altitude( geod.x() * 3600.0,
geod.y() * 3600.0 );
// convert to radians
radians = Point3D( geod.x() * DEG_TO_RAD,
geod.y() * DEG_TO_RAD,
real_z );
cart = fgGeodToCart(radians);
// cout << cart << endl;
wgs84_nodes.push_back(cart);
}
}
// build the node -> element (triangle) reverse lookup table. there
// is an entry for each point containing a list of all the triangles
// that share that point.
void FGGenOutput::gen_node_ele_lookup_table() {
int_list ele_list;
ele_list.erase( ele_list.begin(), ele_list.end() );
// initialize reverse_ele_lookup structure by creating an empty
// list for each point
const_point_list_iterator w_current = wgs84_nodes.begin();
const_point_list_iterator w_last = wgs84_nodes.end();
for ( ; w_current != w_last; ++w_current ) {
reverse_ele_lookup.push_back( ele_list );
}
// traverse triangle structure building reverse lookup table
const_triele_list_iterator current = tri_elements.begin();
const_triele_list_iterator last = tri_elements.end();
int counter = 0;
for ( ; current != last; ++current ) {
reverse_ele_lookup[ current->get_n1() ].push_back( counter );
reverse_ele_lookup[ current->get_n2() ].push_back( counter );
reverse_ele_lookup[ current->get_n3() ].push_back( counter );
++counter;
}
}
// caclulate the normal for the specified triangle face
Point3D FGGenOutput::calc_normal( int i ) {
double v1[3], v2[3], normal[3];
double temp;
Point3D p1 = wgs84_nodes[ tri_elements[i].get_n1() ];
Point3D p2 = wgs84_nodes[ tri_elements[i].get_n2() ];
Point3D p3 = wgs84_nodes[ tri_elements[i].get_n3() ];
v1[0] = p2.x() - p1.x(); v1[1] = p2.y() - p1.y(); v1[2] = p2.z() - p1.z();
v2[0] = p3.x() - p1.x(); v2[1] = p3.y() - p1.y(); v2[2] = p3.z() - p1.z();
MAT3cross_product(normal, v1, v2);
MAT3_NORMALIZE_VEC(normal,temp);
return Point3D( normal[0], normal[1], normal[2] );
}
// build the face normal list
void FGGenOutput::gen_face_normals() {
// traverse triangle structure building the face normal table
cout << "calculating face normals" << endl;
for ( int i = 0; i < (int)tri_elements.size(); i++ ) {
// cout << calc_normal( i ) << endl;
face_normals.push_back( calc_normal( i ) );
}
}
// calculate the normals for each point in wgs84_nodes
void FGGenOutput::gen_normals() {
Point3D normal;
cout << "caculating node normals" << endl;
// for each node
for ( int i = 0; i < (int)wgs84_nodes.size(); ++i ) {
int_list tri_list = reverse_ele_lookup[i];
int_list_iterator current = tri_list.begin();
int_list_iterator last = tri_list.end();
Point3D average( 0.0 );
// for each triangle that shares this node
for ( ; current != last; ++current ) {
normal = face_normals[ *current ];
average += normal;
// cout << normal << endl;
}
average /= tri_list.size();
// cout << "average = " << average << endl;
point_normals.push_back( average );
}
}
// calculate the global bounding sphere. Center is the average of the
// points.
void FGGenOutput::calc_gbs() {
double dist_squared;
double radius_squared = 0;
gbs_center = Point3D( 0.0 );
const_point_list_iterator current = wgs84_nodes.begin();
const_point_list_iterator last = wgs84_nodes.end();
for ( ; current != last; ++current ) {
gbs_center += *current;
}
gbs_center /= wgs84_nodes.size();
current = wgs84_nodes.begin();
for ( ; current != last; ++current ) {
dist_squared = gbs_center.distance3Dsquared(*current);
if ( dist_squared > radius_squared ) {
radius_squared = dist_squared;
}
}
gbs_radius = sqrt(radius_squared);
}
// build the necessary output structures based on the triangulation
// data
int FGGenOutput::build( const FGArray& array, const FGTriangle& t ) {
FGTriNodes trinodes = t.get_out_nodes();
// copy the geodetic node list into this class
geod_nodes = trinodes.get_node_list();
// copy the triangle list into this class
tri_elements = t.get_elelist();
// build the trifan list
cout << "total triangles = " << tri_elements.size() << endl;
FGGenFans f;
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
triele_list area_tris;
area_tris.erase( area_tris.begin(), area_tris.end() );
const_triele_list_iterator t_current = tri_elements.begin();
const_triele_list_iterator t_last = tri_elements.end();
for ( ; t_current != t_last; ++t_current ) {
if ( (int)t_current->get_attribute() == i ) {
area_tris.push_back( *t_current );
}
}
if ( (int)area_tris.size() > 0 ) {
cout << "generating fans for area = " << i << endl;
fans[i] = f.greedy_build( area_tris );
}
}
// generate the point list in wgs-84 coordinates
gen_wgs84_points( array );
// calculate the global bounding sphere
calc_gbs();
cout << "center = " << gbs_center << " radius = " << gbs_radius << endl;
// build the node -> element (triangle) reverse lookup table
gen_node_ele_lookup_table();
// build the face normal list
gen_face_normals();
// calculate the normals for each point in wgs84_nodes
gen_normals();
return 1;
}
// caclulate the bounding sphere for a list of triangle faces
void FGGenOutput::calc_group_bounding_sphere( const fan_list& fans,
Point3D *center, double *radius )
{
cout << "calculate group bounding sphere for " << fans.size() << " fans."
<< endl;
// generate a list of unique points from the triangle list
FGTriNodes nodes;
const_fan_list_iterator f_current = fans.begin();
const_fan_list_iterator f_last = fans.end();
for ( ; f_current != f_last; ++f_current ) {
const_int_list_iterator i_current = f_current->begin();
const_int_list_iterator i_last = f_current->end();
for ( ; i_current != i_last; ++i_current ) {
Point3D p1 = wgs84_nodes[ *i_current ];
nodes.unique_add(p1);
}
}
// find average of point list
Point3D c( 0.0 );
point_list points = nodes.get_node_list();
// cout << "found " << points.size() << " unique nodes" << endl;
point_list_iterator p_current = points.begin();
point_list_iterator p_last = points.end();
for ( ; p_current != p_last; ++p_current ) {
c += *p_current;
}
c /= points.size();
// find max radius
double dist_squared;
double max_squared = 0;
p_current = points.begin();
p_last = points.end();
for ( ; p_current != p_last; ++p_current ) {
dist_squared = c.distance3Dsquared(*p_current);
if ( dist_squared > max_squared ) {
max_squared = dist_squared;
}
}
*center = c;
*radius = sqrt(max_squared);
}
// caclulate the bounding sphere for the specified triangle face
void FGGenOutput::calc_bounding_sphere( const FGTriEle& t,
Point3D *center, double *radius )
{
Point3D c( 0.0 );
Point3D p1 = wgs84_nodes[ t.get_n1() ];
Point3D p2 = wgs84_nodes[ t.get_n2() ];
Point3D p3 = wgs84_nodes[ t.get_n3() ];
c = p1 + p2 + p3;
c /= 3;
double dist_squared;
double max_squared = 0;
dist_squared = c.distance3Dsquared(p1);
if ( dist_squared > max_squared ) {
max_squared = dist_squared;
}
dist_squared = c.distance3Dsquared(p2);
if ( dist_squared > max_squared ) {
max_squared = dist_squared;
}
dist_squared = c.distance3Dsquared(p3);
if ( dist_squared > max_squared ) {
max_squared = dist_squared;
}
*center = c;
*radius = sqrt(max_squared);
}
// write out the fgfs scenery file
int FGGenOutput::write( const string& base, const FGBucket& b ) {
Point3D p;
string dir = base + "/Scenery/" + b.gen_base_path();
string command = "mkdir -p " + dir;
system(command.c_str());
string file = dir + "/" + b.gen_index_str();
cout << "Output file = " << file << endl;
FILE *fp;
if ( (fp = fopen( file.c_str(), "w" )) == NULL ) {
cout << "ERROR: opening " << file << " for writing!" << endl;
exit(-1);
}
// write headers
fprintf(fp, "# FGFS Scenery Version %s\n", FG_SCENERY_FILE_FORMAT);
time_t calendar_time = time(NULL);
struct tm *local_tm;
local_tm = localtime( &calendar_time );
char time_str[256];
strftime( time_str, 256, "%a %b %d %H:%M:%S %Z %Y", local_tm);
fprintf(fp, "# Created %s\n", time_str );
fprintf(fp, "\n");
// write global bounding sphere
fprintf(fp, "# gbs %.5f %.5f %.5f %.2f\n",
gbs_center.x(), gbs_center.y(), gbs_center.z(), gbs_radius);
fprintf(fp, "\n");
// write nodes
fprintf(fp, "# vertex list\n");
const_point_list_iterator w_current = wgs84_nodes.begin();
const_point_list_iterator w_last = wgs84_nodes.end();
for ( ; w_current != w_last; ++w_current ) {
p = *w_current - gbs_center;
fprintf(fp, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z());
}
fprintf(fp, "\n");
// write vertex normals
fprintf(fp, "# vertex normal list\n");
const_point_list_iterator n_current = point_normals.begin();
const_point_list_iterator n_last = point_normals.end();
for ( ; n_current != n_last; ++n_current ) {
p = *n_current;
fprintf(fp, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z());
}
fprintf(fp, "\n");
// write triangles (grouped by type for now)
Point3D center;
double radius;
fprintf(fp, "# triangle groups\n");
fprintf(fp, "\n");
int total_tris = 0;
for ( int i = 0; i < FG_MAX_AREA_TYPES; ++i ) {
if ( (int)fans[i].size() > 0 ) {
string attr_name = get_area_name( (AreaType)i );
calc_group_bounding_sphere( fans[i], &center, &radius );
cout << "writing " << (int)fans[i].size() << " fans for "
<< attr_name << endl;
fprintf(fp, "# usemtl %s\n", attr_name.c_str() );
fprintf(fp, "# bs %.4f %.4f %.4f %.2f\n",
center.x(), center.y(), center.z(), radius);
fan_list_iterator f_current = fans[i].begin();
fan_list_iterator f_last = fans[i].end();
for ( ; f_current != f_last; ++f_current ) {
fprintf( fp, "tf" );
total_tris += f_current->size() - 2;
int_list_iterator i_current = f_current->begin();
int_list_iterator i_last = f_current->end();
for ( ; i_current != i_last; ++i_current ) {
fprintf( fp, " %d", *i_current );
}
fprintf( fp, "\n" );
#if 0
{
int_list_iterator i_current = f_current->begin();
int_list_iterator i_last = f_current->end();
int center = *i_current;
++i_current;
int n2 = *i_current;
++i_current;
for ( ; i_current != i_last; ++i_current ) {
int n3 = *i_current;
fprintf( fp, "f %d %d %d\n", center, n2, n3 );
n2 = n3;
}
}
#endif
}
fprintf( fp, "\n" );
}
}
cout << "wrote " << total_tris << " tris to output file" << endl;
fclose(fp);
command = "gzip --force --best " + file;
system(command.c_str());
return 1;
}
// $Log$
// Revision 1.10 1999/03/31 23:46:57 curt
// Debugging output tweaks.
//
// Revision 1.9 1999/03/31 13:26:40 curt
// Debugging output tweeaks.
//
// Revision 1.8 1999/03/31 05:35:05 curt
// Fixed bug in genfans (deleting the wrong triangles from the available pool.)
//
// Revision 1.7 1999/03/30 23:50:43 curt
// Modifications to fanify by attribute.
//
// Revision 1.6 1999/03/29 13:11:03 curt
// Shuffled stl type names a bit.
// Began adding support for tri-fanning (or maybe other arrangments too.)
//
// Revision 1.5 1999/03/27 14:06:42 curt
// Tweaks to bounding sphere calculation routines.
// Group like triangles together for output to be in a single display list,
// even though they are individual, non-fanified, triangles.
//
// Revision 1.4 1999/03/27 05:23:22 curt
// Interpolate real z value of all nodes from dem data.
// Write scenery file to correct location.
// Pass along correct triangle attributes and write to output file.
//
// Revision 1.3 1999/03/25 19:04:21 curt
// Preparations for outputing scenery file to correct location.
//
// Revision 1.2 1999/03/23 22:02:03 curt
// Worked on creating data to output ... normals, bounding spheres, etc.
//
// Revision 1.1 1999/03/22 23:51:51 curt
// Initial revision.
//

165
Tools/GenOutput/genobj.hxx Normal file
View file

@ -0,0 +1,165 @@
// genobj.hxx -- Generate the flight gear "obj" file format from the
// triangle output
//
// Written by Curtis Olson, started March 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifndef _GENOBJ_HXX
#define _GENOBJ_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <Include/compiler.h>
#include STL_STRING
#include <Bucket/newbucket.hxx>
#include <Math/fg_geodesy.hxx>
#include <Math/point3d.hxx>
#include <Combine/genfans.hxx>
#include <Main/construct_types.hxx>
#include <Triangulate/triangle.hxx>
FG_USING_STD(string);
FG_USING_STD(vector);
typedef vector < int_list > belongs_to_list;
typedef belongs_to_list::iterator belongs_to_list_iterator;
typedef belongs_to_list::const_iterator belongs_to_list_tripoly_iterator;
class FGGenOutput {
private:
// node list in geodetic coordinats
point_list geod_nodes;
// node list in cartesian coords (wgs84 model)
point_list wgs84_nodes;
// face normal list (for flat shading)
point_list face_normals;
// normal list (for each point) in cart coords (for smooth
// shading)
point_list point_normals;
// triangles (by index into point list)
triele_list tri_elements;
// fan list
fan_list fans[FG_MAX_AREA_TYPES];
// for each node, a list of triangle indices that contain this node
belongs_to_list reverse_ele_lookup;
// global bounding sphere
Point3D gbs_center;
double gbs_radius;
// build the wgs-84 point list
void gen_wgs84_points( const FGArray& array );
// build the node -> element (triangle) reverse lookup table.
// there is an entry for each point containing a list of all the
// triangles that share that point.
void gen_node_ele_lookup_table();
// calculate the normals for each point in wgs84_nodes
void gen_normals();
// build the face normal list
void gen_face_normals();
// caclulate the normal for the specified triangle face
Point3D calc_normal( int i );
// calculate the global bounding sphere. Center is the average of
// the points.
void calc_gbs();
// caclulate the bounding sphere for a list of triangle faces
void calc_group_bounding_sphere( const fan_list& fans,
Point3D *center, double *radius );
// caclulate the bounding sphere for the specified triangle face
void calc_bounding_sphere( const FGTriEle& t,
Point3D *center, double *radius );
public:
// Constructor && Destructor
inline FGGenOutput() { }
inline ~FGGenOutput() { }
// build the necessary output structures based on the
// triangulation data
int build( const FGArray& array, const FGTriangle& t );
// write out the fgfs scenery file
int write( const string& base, const FGBucket& b );
};
#endif // _GENOBJ_HXX
// $Log$
// Revision 1.9 1999/03/31 23:46:58 curt
// Debugging output tweaks.
//
// Revision 1.8 1999/03/30 23:50:44 curt
// Modifications to fanify by attribute.
//
// Revision 1.7 1999/03/29 13:11:04 curt
// Shuffled stl type names a bit.
// Began adding support for tri-fanning (or maybe other arrangments too.)
//
// Revision 1.6 1999/03/27 14:06:43 curt
// Tweaks to bounding sphere calculation routines.
// Group like triangles together for output to be in a single display list,
// even though they are individual, non-fanified, triangles.
//
// Revision 1.5 1999/03/27 05:23:23 curt
// Interpolate real z value of all nodes from dem data.
// Write scenery file to correct location.
// Pass along correct triangle attributes and write to output file.
//
// Revision 1.4 1999/03/25 19:04:22 curt
// Preparations for outputing scenery file to correct location.
//
// Revision 1.3 1999/03/23 22:02:04 curt
// Worked on creating data to output ... normals, bounding spheres, etc.
//
// Revision 1.2 1999/03/23 17:44:49 curt
// Beginning work on generating output scenery.
//
// Revision 1.1 1999/03/22 23:51:51 curt
// Initial revision.
//

4
Tools/Lib/Makefile.am Normal file
View file

@ -0,0 +1,4 @@
SUBDIRS = \
DEM \
Polygon \
Triangle

24
Tools/Main/Makefile.am Normal file
View file

@ -0,0 +1,24 @@
bin_PROGRAMS = construct
construct_SOURCES = construct.cxx construct_types.hxx
construct_LDADD = \
$(top_builddir)/Tools/Construct/Array/libArray.a \
$(top_builddir)/Tools/Construct/Clipper/libClipper.a \
$(top_builddir)/Tools/Construct/GenOutput/libGenOutput.a \
$(top_builddir)/Tools/Construct/Combine/libCombine.a \
$(top_builddir)/Tools/Construct/Triangulate/libTriangulate.a \
$(top_builddir)/Tools/Lib/Polygon/libPolygon.a \
$(top_builddir)/Tools/Lib/Triangle/libTriangle.a \
$(top_builddir)/Lib/Bucket/libBucket.a \
$(top_builddir)/Lib/Math/libMath.a \
$(top_builddir)/Lib/Misc/libMisc.a \
$(top_builddir)/Lib/Debug/libDebug.a \
$(top_builddir)/Lib/zlib/libz.a \
-lgpc -lgfc
INCLUDES += \
-I$(top_builddir) \
-I$(top_builddir)/Lib \
-I$(top_builddir)/Tools/Lib \
-I$(top_builddir)/Tools/Construct

373
Tools/Main/construct.cxx Normal file
View file

@ -0,0 +1,373 @@
// main.cxx -- top level construction routines
//
// Written by Curtis Olson, started March 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <sys/types.h> // for directory reading
#include <dirent.h> // for directory reading
#include <Bucket/newbucket.hxx>
#include <Include/fg_constants.h>
#include <Debug/logstream.hxx>
#include <Array/array.hxx>
#include <Clipper/clipper.hxx>
#include <GenOutput/genobj.hxx>
#include <Triangulate/triangle.hxx>
// load regular grid of elevation data (dem based), return list of
// fitted nodes
int load_dem(const string& work_base, FGBucket& b, FGArray& array) {
point_list result;
string base = b.gen_base_path();
string dem_path = work_base + ".dem" + "/Scenery/" + base
+ "/" + b.gen_index_str() + ".dem";
cout << "dem_path = " << dem_path << endl;
if ( ! array.open(dem_path) ) {
cout << "ERROR: cannot open " << dem_path << endl;
}
array.parse( b );
return 1;
}
// fit dem nodes, return number of fitted nodes
int fit_dem(FGArray& array, int error) {
return array.fit( error );
}
// do actual scan of directory and loading of files
int actual_load_polys( const string& dir, FGBucket& b, FGClipper& clipper ) {
int counter = 0;
string base = b.gen_base_path();
string tile_str = b.gen_index_str();
string ext;
DIR *d;
struct dirent *de;
if ( (d = opendir( dir.c_str() )) == NULL ) {
cout << "cannot open directory " << dir << "\n";
return 0;
}
// load all matching polygon files
string file, f_index, full_path;
int pos;
while ( (de = readdir(d)) != NULL ) {
file = de->d_name;
pos = file.find(".");
f_index = file.substr(0, pos);
if ( tile_str == f_index ) {
ext = file.substr(pos + 1);
cout << file << " " << f_index << " '" << ext << "'" << endl;
full_path = dir + "/" + file;
if ( (ext == "dem") || (ext == "dem.gz") ) {
// skip
} else {
cout << "ext = '" << ext << "'" << endl;
clipper.load_polys( full_path );
++counter;
}
}
}
return counter;
}
// load all 2d polygons matching the specified base path and clip
// against each other to resolve any overlaps
int load_polys( const string& work_base, FGBucket& b, FGClipper& clipper) {
string base = b.gen_base_path();
int result;
// initialize clipper
clipper.init();
// load airports
string poly_path = work_base + ".apt" + "/Scenery/" + base;
cout << "poly_path = " << poly_path << endl;
result = actual_load_polys( poly_path, b, clipper );
cout << " loaded " << result << " polys" << endl;
// load hydro
poly_path = work_base + ".hydro" + "/Scenery/" + base;
cout << "poly_path = " << poly_path << endl;
result = actual_load_polys( poly_path, b, clipper );
cout << " loaded " << result << " polys" << endl;
point2d min, max;
min.x = b.get_center_lon() - 0.5 * b.get_width();
min.y = b.get_center_lat() - 0.5 * b.get_height();
max.x = b.get_center_lon() + 0.5 * b.get_width();
max.y = b.get_center_lat() + 0.5 * b.get_height();
// do clipping
cout << "clipping polygons" << endl;
clipper.clip_all(min, max);
return 1;
}
// triangulate the data for each polygon
void do_triangulate( const FGArray& array, const FGClipper& clipper,
FGTriangle& t ) {
// first we need to consolidate the points of the DEM fit list and
// all the polygons into a more "Triangle" friendly format
point_list corner_list = array.get_corner_node_list();
point_list fit_list = array.get_fit_node_list();
FGgpcPolyList gpc_polys = clipper.get_polys_clipped();
cout << "ready to build node list and polygons" << endl;
t.build( corner_list, fit_list, gpc_polys );
cout << "done building node list and polygons" << endl;
cout << "ready to do triangulation" << endl;
t.run_triangulate();
cout << "finished triangulation" << endl;
}
// generate the flight gear scenery file
void do_output( const string& base, const FGBucket &b, const FGTriangle& t,
const FGArray& array, FGGenOutput& output ) {
output.build( array, t );
output.write( base, b );
}
void construct_tile( const string& work_base, const string& output_base,
FGBucket& b )
{
cout << "Construct tile, bucket = " << b << endl;
// fit with ever increasing error tolerance until we produce <=
// 80% of max nodes. We should really have the sim end handle
// arbitrarily complex tiles.
const int min_nodes = 50;
const int max_nodes = (int)(MAX_NODES * 0.8);
bool acceptable = false;
double error = 200.0;
int count = 0;
// load and fit grid of elevation data
FGArray array;
load_dem( work_base, b, array );
FGTriangle t;
while ( ! acceptable ) {
// fit the data
array.fit( error );
// load and clip 2d polygon data
FGClipper clipper;
load_polys( work_base, b, clipper );
// triangulate the data for each polygon
do_triangulate( array, clipper, t );
acceptable = true;
count = t.get_out_nodes_size();
if ( (count < min_nodes) && (error >= 25.0) ) {
// reduce error tolerance until number of points exceeds the
// minimum threshold
cout << "produced too few nodes ..." << endl;
acceptable = false;
error /= 1.5;
cout << "Setting error to " << error << " and retrying fit."
<< endl;
}
if ( (count > max_nodes) && (error <= 1000.0) ) {
// increase error tolerance until number of points drops below
// the maximum threshold
cout << "produced too many nodes ..." << endl;
acceptable = false;
error *= 1.5;
cout << "Setting error to " << error << " and retrying fit."
<< endl;
}
}
cout << "finished fit with error = " << error << " node count = "
<< count << endl;
// generate the output
FGGenOutput output;
do_output( output_base, b, t, array, output );
}
main(int argc, char **argv) {
double lon, lat;
fglog().setLogLevels( FG_ALL, FG_DEBUG );
if ( argc != 3 ) {
cout << "Usage: " << argv[0] << " <work_base> <output_base>" << endl;
exit(-1);
}
string work_base = argv[1];
string output_base = argv[2];
// lon = -146.248360; lat = 61.133950; // PAVD (Valdez, AK)
// lon = -110.664244; lat = 33.352890; // P13
// lon = -93.211389; lat = 45.145000; // KANE
// lon = -92.486188; lat = 44.590190; // KRGK
// lon = -89.744682312011719; lat= 29.314495086669922;
// lon = -122.488090; lat = 42.743183; // 64S
// lon = -114.861097; lat = 35.947480; // 61B
// lon = -112.012175; lat = 41.195944; // KOGD
// lon = -90.757128; lat = 46.790212; // WI32
// lon = -122.220717; lat = 37.721291; // KOAK
// lon = -111.721477; lat = 40.215641; // KPVU
// lon = -122.309313; lat = 47.448982; // KSEA
lon = -148.798131; lat = 63.645099; // AK06 (Danali, AK)
double min_x = lon - 3;
double min_y = lat - 1;
FGBucket b_min( min_x, min_y );
FGBucket b_max( lon + 3, lat + 1 );
FGBucket b_omit(550314L);
// FGBucket b(517745L);
// FGBucket b(-146.248360, 61.133950);
// construct_tile( work_base, output_base, b );
// exit(0);
if ( b_min == b_max ) {
construct_tile( work_base, output_base, b_min );
} else {
FGBucket b_cur;
int dx, dy, i, j;
fgBucketDiff(b_min, b_max, &dx, &dy);
cout << " construction area spans tile boundaries" << endl;
cout << " dx = " << dx << " dy = " << dy << endl;
for ( j = 0; j <= dy; j++ ) {
for ( i = 0; i <= dx; i++ ) {
b_cur = fgBucketOffset(min_x, min_y, i, j);
if ( b_cur != b_omit ) {
construct_tile( work_base, output_base, b_cur );
}
}
}
// string answer; cin >> answer;
}
}
// $Log$
// Revision 1.18 1999/04/05 02:16:51 curt
// Dynamically update "error" until the resulting tile data scales within
// a lower and upper bounds.
//
// Revision 1.17 1999/04/03 05:22:57 curt
// Found a bug in dividing and adding unique verticle segments which could
// cause the triangulator to end up in an infinite loop. Basically the code
// was correct, but the verticle line test was a bit to selective.
//
// Revision 1.16 1999/04/01 13:52:12 curt
// Version 0.6.0
// Shape name tweak.
// Removing tool: FixNode
//
// Revision 1.15 1999/03/31 23:47:02 curt
// Debugging output tweaks.
//
// Revision 1.14 1999/03/31 13:26:41 curt
// Debugging output tweeaks.
//
// Revision 1.13 1999/03/31 05:35:06 curt
// Fixed bug in genfans (deleting the wrong triangles from the available pool.)
//
// Revision 1.12 1999/03/30 23:51:14 curt
// fiddling ...
//
// Revision 1.11 1999/03/29 13:11:06 curt
// Shuffled stl type names a bit.
// Began adding support for tri-fanning (or maybe other arrangments too.)
//
// Revision 1.10 1999/03/27 05:25:02 curt
// Fit with a value of 200 rather than 100.
// Handle corner nodes separately from the rest of the fitted nodes.
// Write scenery file to correct location.
// First hack at generating scenery for multiple tiles in one invocation.
//
// Revision 1.9 1999/03/25 19:04:31 curt
// Preparations for outputing scenery file to correct location.
// Minor tweaks related to FGBucket usage.
//
// Revision 1.8 1999/03/23 22:02:17 curt
// Worked on creating data to output ... normals, bounding spheres, etc.
//
// Revision 1.7 1999/03/22 23:48:29 curt
// Added GenOutput/
//
// Revision 1.6 1999/03/21 15:48:01 curt
// Removed Dem2node from the Tools fold.
// Tweaked the triangulator options to add quality mesh refinement.
//
// Revision 1.5 1999/03/21 14:02:05 curt
// Added a mechanism to dump out the triangle structures for viewing.
// Fixed a couple bugs in first pass at triangulation.
// - needed to explicitely initialize the polygon accumulator in triangle.cxx
// before each polygon rather than depending on the default behavior.
// - Fixed a problem with region attribute propagation where I wasn't generating
// the hole points correctly.
//
// Revision 1.4 1999/03/20 20:32:54 curt
// First mostly successful tile triangulation works. There's plenty of tweaking
// to do, but we are marching in the right direction.
//
// Revision 1.3 1999/03/19 00:26:52 curt
// Minor tweaks ...
//
// Revision 1.2 1999/03/17 23:49:52 curt
// Started work on Triangulate/ section.
//
// Revision 1.1 1999/03/14 00:03:24 curt
// Initial revision.
//

View file

@ -0,0 +1,58 @@
// construct_types.hxx -- commonly used types in the construction business.
//
// Written by Curtis Olson, started March 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifndef _CONSTRUCT_TYPES_HXX
#define _CONSTRUCT_TYPES_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <Include/compiler.h>
#include <vector>
#include <Math/point3d.hxx>
FG_USING_STD(vector);
typedef vector < int > int_list;
typedef int_list::iterator int_list_iterator;
typedef int_list::const_iterator const_int_list_iterator;
typedef vector < Point3D > point_list;
typedef point_list::iterator point_list_iterator;
typedef point_list::const_iterator const_point_list_iterator;
#endif // _CONSTRUCT_TYPES_HXX
// $Log$
// Revision 1.1 1999/03/29 13:19:44 curt
// Initial revision.
//

View file

@ -0,0 +1,9 @@
bin_PROGRAMS = makedir
makedir_SOURCES = makedir.cxx
makedir_LDADD = \
$(top_builddir)/Lib/Bucket/libBucket.a \
$(base_LIBS)
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib

119
Tools/Makedir/makedir.cxx Normal file
View file

@ -0,0 +1,119 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <stdio.h>
#include <sys/stat.h> // stat()
#include <unistd.h> // stat()
#include <string>
#include <Bucket/bucketutils.h>
#ifdef WIN32
#ifndef TRUE
#define FALSE 0
#define TRUE 1
#endif
char* PathDivider()
{
return "\\";
} // PathDivider
void ReplaceDivider( char* path )
{
char div = PathDivider()[0];
int i;
if ( ! path )
return;
if ( div == '/' )
return;
for ( i = 0; path[i]; i++ )
if ( path[i] == '/' )
path[i] = div;
} // ReplaceDivider
int Exists( char* path )
{
struct stat statbuff;
ReplaceDivider( path );
if ( path[strlen( path ) - 1] == ':' )
return TRUE;
if ( _stat( path, &statbuff ) != 0 )
return FALSE;
return TRUE;
} // Exists
void CreateDir( char* path )
{
if ( ! path || ! strlen( path ) )
return;
ReplaceDivider( path );
// see if the parent exists yet
int i; // looping index
string parent; // path to parent
parent = path;
for ( i = strlen( parent.c_str() )-1; i >= 0; i-- )
if ( parent[i] == PathDivider()[0] )
{
parent[i] = '\0';
break;
}
if ( ! Exists( parent.c_str() ) )
{
CreateDir( parent.c_str() );
}
if ( ! Exists( path ) )
{
if (mkdir(path, S_IRWXU) != 0 )
{
cout << "Could not create directory " << path << endl;
}else{
cout << "CreateDir: " << path << endl;
}
}
} // CreateDir
int main(int argc, char **argv)
{
string root;
if(argc != 2)
{
cout << "Makedir failed needs one argument\n";
return(10);
}
root = argv[1];
CreateDir(root.c_str());
return(0);
}
#else
int main(int argc, char **argv)
{
cout << "This program is intended to work with windoze\n";
cout << "Other platforms can use mkdir\n";
}
#endif // WIN32

View file

@ -0,0 +1,7 @@
noinst_LIBRARIES = libPolygon.a
libPolygon_a_SOURCES = \
index.cxx index.hxx \
names.cxx names.hxx
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib

79
Tools/Polygon/index.cxx Normal file
View file

@ -0,0 +1,79 @@
// index.cxx -- routines to handle a unique/persistant integer polygon index
//
// Written by Curtis Olson, started February 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <Include/compiler.h>
#include STL_STRING
#include <stdio.h>
#include "index.hxx"
static long int poly_index;
static string poly_path;
// initialize the unique polygon index counter stored in path
bool poly_index_init( string path ) {
poly_path = path;
FILE *fp = fopen( poly_path.c_str(), "r" );
if ( fp == NULL ) {
cout << "Error cannot open " << poly_path << endl;
poly_index = 0;
return false;
}
fscanf( fp, "%ld", &poly_index );
fclose( fp );
}
// increment the persistant counter and return the next poly_index
long int poly_index_next() {
++poly_index;
FILE *fp = fopen( poly_path.c_str(), "w" );
if ( fp == NULL ) {
cout << "Error cannot open " << poly_path << " for writing" << endl;
}
fprintf( fp, "%ld\n", poly_index );
fclose( fp );
return poly_index;
}
// $Log$
// Revision 1.2 1999/03/19 00:27:30 curt
// Use long int for index instead of just int.
//
// Revision 1.1 1999/02/25 21:30:24 curt
// Initial revision.
//

51
Tools/Polygon/index.hxx Normal file
View file

@ -0,0 +1,51 @@
// index.cxx -- routines to handle a unique/persistant integer polygon index
//
// Written by Curtis Olson, started February 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifndef _INDEX_HXX
#define _INDEX_HXX
#include <Include/compiler.h>
#include STL_STRING
// initialize the unique polygon index counter stored in path
bool poly_index_init( string path );
// increment the persistant counter and return the next poly_index
long int poly_index_next();
#endif // _INDEX_HXX
// $Log$
// Revision 1.2 1999/03/19 00:27:31 curt
// Use long int for index instead of just int.
//
// Revision 1.1 1999/02/25 21:30:24 curt
// Initial revision.
//

146
Tools/Polygon/names.cxx Normal file
View file

@ -0,0 +1,146 @@
// names.cxx -- process shapefiles names
//
// Written by Curtis Olson, started February 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <Include/compiler.h>
#include STL_STRING
#include "names.hxx"
// return area type from text name
AreaType get_area_type( string area ) {
if ( area == "Default" ) {
return DefaultArea;
} else if ( area == "AirportKeep" ) {
return AirportKeepArea;
} else if ( area == "AirportIgnore" ) {
return AirportIgnoreArea;
} else if ( (area == "Swamp or Marsh")
|| (area == "Marsh") ) {
return MarshArea;
} else if ( (area == "Bay Estuary or Ocean")
|| (area == "Ocean") ) {
return OceanArea;
} else if ( area == "Lake" ) {
return LakeArea;
} else if ( (area == "Lake Dry")
|| (area == "DryLake") ) {
return DryLakeArea;
} else if ( (area == "Lake Intermittent")
|| (area == "IntermittentLake") ) {
return IntLakeArea;
} else if ( area == "Reservoir" ) {
return ReservoirArea;
} else if ( (area == "Reservoir Intermittent")
|| (area == "IntermittentReservoir") ) {
return IntReservoirArea;
} else if ( area == "Stream" ) {
return StreamArea;
} else if ( area == "Canal" ) {
return CanalArea;
} else if ( area == "Glacier" ) {
return GlacierArea;
} else if ( area == "Void Area" ) {
return VoidArea;
} else if ( area == "Null" ) {
return NullArea;
} else {
cout << "unknown area = '" << area << "'" << endl;
// cout << "area = " << area << endl;
// for ( int i = 0; i < area.length(); i++ ) {
// cout << i << ") " << (int)area[i] << endl;
// }
return UnknownArea;
}
}
// return text from of area name
string get_area_name( AreaType area ) {
if ( area == DefaultArea ) {
return "Default";
} else if ( area == AirportKeepArea ) {
return "AirportKeep";
} else if ( area == AirportIgnoreArea ) {
return "AirportIgnore";
} else if ( area == MarshArea ) {
return "Marsh";
} else if ( area == OceanArea ) {
return "Ocean";
} else if ( area == LakeArea ) {
return "Lake";
} else if ( area == DryLakeArea ) {
return "DryLake";
} else if ( area == IntLakeArea ) {
return "IntermittentLake";
} else if ( area == ReservoirArea ) {
return "Reservoir";
} else if ( area == IntReservoirArea ) {
return "IntermittentReservoir";
} else if ( area == StreamArea ) {
return "Stream";
} else if ( area == CanalArea ) {
return "Canal";
} else if ( area == GlacierArea ) {
return "Glacier";
} else if ( area == VoidArea ) {
return "VoidArea";
} else if ( area == NullArea ) {
return "Null";
} else {
cout << "unknown area code = " << (int)area << endl;
return "Unknown";
}
}
// $Log$
// Revision 1.7 1999/04/01 13:52:13 curt
// Version 0.6.0
// Shape name tweak.
// Removing tool: FixNode
//
// Revision 1.6 1999/03/27 05:31:24 curt
// Make 0 the default area type since this corresponds well with the conventions
// used by the triangulator.
//
// Revision 1.5 1999/03/22 23:49:29 curt
// Moved AreaType get_shapefile_type(GDBFile *dbf, int rec) to where it
// belongs in ShapeFile/
//
// Revision 1.4 1999/03/13 18:47:04 curt
// Removed an unused variable.
//
// Revision 1.3 1999/03/02 01:03:58 curt
// Added more reverse lookup support.
//
// Revision 1.2 1999/03/01 15:35:52 curt
// Generalized the routines a bit to make them more useful.
//
// Revision 1.1 1999/02/25 21:30:24 curt
// Initial revision.
//
// Revision 1.1 1999/02/23 01:29:05 curt
// Additional progress.
//

89
Tools/Polygon/names.hxx Normal file
View file

@ -0,0 +1,89 @@
// names.hxx -- process shapefiles names
//
// Written by Curtis Olson, started February 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifndef _NAMES_HXX
#define _NAMES_HXX
#include <Include/compiler.h>
#include STL_STRING
FG_USING_STD(string);
// Posible shape file types. Note the order of these is important and
// defines the priority of these shapes if they should intersect. The
// smaller the number, the higher the priority.
enum AreaType {
DefaultArea = 0,
AirportKeepArea = 1,
AirportIgnoreArea = 2,
OceanArea = 3,
LakeArea = 4,
DryLakeArea = 5,
IntLakeArea = 6,
ReservoirArea = 7,
IntReservoirArea = 8,
StreamArea = 9,
CanalArea = 10,
GlacierArea = 11,
MarshArea = 12,
VoidArea = 9997,
NullArea = 9998,
UnknownArea = 9999
};
// return area type from text name
AreaType get_area_type( string area );
// return text form of area name
string get_area_name( AreaType area );
#endif // _NAMES_HXX
// $Log$
// Revision 1.5 1999/03/27 05:31:25 curt
// Make 0 the default area type since this corresponds well with the conventions
// used by the triangulator.
//
// Revision 1.4 1999/03/22 23:49:30 curt
// Moved AreaType get_shapefile_type(GDBFile *dbf, int rec) to where it
// belongs in ShapeFile/
//
// Revision 1.3 1999/03/01 15:35:53 curt
// Generalized the routines a bit to make them more useful.
//
// Revision 1.2 1999/02/26 22:10:42 curt
// Updated names and priorities of area types.
//
// Revision 1.1 1999/02/25 21:30:24 curt
// Initial revision.
//
// Revision 1.1 1999/02/23 01:29:05 curt
// Additional progress.
//

6
Tools/Prep/Makefile.am Normal file
View file

@ -0,0 +1,6 @@
SUBDIRS = \
DemChop \
DemInfo \
DemRaw2ascii \
GenAirports \
ShapeFile

View file

@ -0,0 +1,14 @@
bin_PROGRAMS = shape-decode
shape_decode_SOURCES = main.cxx shape.cxx shape.hxx
shape_decode_LDADD = \
$(top_builddir)/Tools/Lib/Polygon/libPolygon.a \
$(top_builddir)/Lib/Debug/libDebug.a \
$(top_builddir)/Lib/Bucket/libBucket.a \
$(top_builddir)/Lib/Misc/libMisc.a \
$(top_builddir)/Lib/zlib/libz.a \
-lgfc -lgpc
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib -I$(top_builddir)/Tools/Lib

333
Tools/ShapeFile/main.cxx Normal file
View file

@ -0,0 +1,333 @@
// main.cxx -- process shapefiles and extract polygon outlines,
// clipping against and sorting them into the revelant
// tiles.
//
// Written by Curtis Olson, started February 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
// Include Geographic Foundation Classes library
// libgfc.a includes need this bit o' strangeness
#if defined ( linux )
# define _LINUX_
#endif
#include <gfc/gadt_polygon.h>
#include <gfc/gdbf.h>
#include <gfc/gshapefile.h>
#undef E
#undef DEG_TO_RAD
#undef RAD_TO_DEG
// include Generic Polygon Clipping Library
extern "C" {
#include <gpc.h>
}
#include <Include/compiler.h>
#include STL_STRING
#include <Debug/logstream.hxx>
#include <Polygon/index.hxx>
#include <Polygon/names.hxx>
#include "shape.hxx"
// return the type of the shapefile record
AreaType get_shapefile_type(GDBFile *dbf, int rec) {
// GDBFieldDesc *fdesc[128]; // 128 is an arbitrary number here
GDBFValue *fields; //an array of field values
char* dbf_rec; //a record containing all the fields
// grab the meta-information for all the fields
// this applies to all the records in the DBF file.
// for ( int i = 0; i < dbf->numFields(); i++ ) {
// fdesc[i] = dbf->getFieldDesc(i);
// cout << i << ") " << fdesc[i]->name << endl;
// }
// this is the whole name record
dbf_rec = dbf->getRecord( rec );
// parse it into individual fields
if ( dbf_rec ) {
fields = dbf->recordDeform( dbf_rec );
} else {
return UnknownArea;
}
string area = fields[4].str_v;
// strip leading spaces
while ( area[0] == ' ' ) {
area = area.substr(1, area.length() - 1);
}
// strip trailing spaces
while ( area[area.length() - 1] == ' ' ) {
area = area.substr(0, area.length() - 1);
}
// strip other junk encountered
while ( (int)area[area.length() - 1] == 9 ) {
area = area.substr(0, area.length() - 1);
}
return get_area_type( area );
}
int main( int argc, char **argv ) {
gpc_polygon gpc_shape;
int i, j;
fglog().setLogLevels( FG_ALL, FG_DEBUG );
if ( argc != 3 ) {
FG_LOG( FG_GENERAL, FG_ALERT, "Usage: " << argv[0]
<< " <shape_file> <work_dir>" );
exit(-1);
}
FG_LOG( FG_GENERAL, FG_DEBUG, "Opening " << argv[1] << " for reading." );
// make work directory
string work_dir = argv[2];
string command = "mkdir -p " + work_dir;
system( command.c_str() );
// initialize persistant polygon counter
string counter_file = work_dir + "/../work.counter";
poly_index_init( counter_file );
// initialize structure for building gpc polygons
shape_utils_init();
GShapeFile * sf = new GShapeFile( argv[1] );
GDBFile *dbf = new GDBFile( argv[1] );
string path = argv[2];
GPolygon shape;
double *coords; // in decimal degrees
int n_vertices;
FG_LOG( FG_GENERAL, FG_INFO, "shape file records = " << sf->numRecords() );
GShapeFile::ShapeType t = sf->shapeType();
if ( t != GShapeFile::av_Polygon ) {
FG_LOG( FG_GENERAL, FG_ALERT, "Can't handle non-polygon shape files" );
exit(-1);
}
for ( i = 0; i < sf->numRecords(); i++ ) {
//fetch i-th record (shape)
sf->getShapeRec(i, &shape);
FG_LOG( FG_GENERAL, FG_DEBUG, "Record = " << i << " rings = "
<< shape.numRings() );
AreaType area = get_shapefile_type(dbf, i);
FG_LOG( FG_GENERAL, FG_DEBUG, "area type = " << get_area_name(area)
<< " (" << (int)area << ")" );
FG_LOG( FG_GENERAL, FG_INFO, " record = " << i
<< " ring = " << 0 );
if ( area == MarshArea ) {
// interior of polygon is marsh, holes are water
// do main outline first
init_shape(&gpc_shape);
n_vertices = shape.getRing(0, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
process_shape(path, area, &gpc_shape);
free_shape(&gpc_shape);
// do lakes (individually) next
for ( j = 1; j < shape.numRings(); j++ ) {
FG_LOG( FG_GENERAL, FG_INFO, " record = " << i
<< " ring = " << j );
init_shape(&gpc_shape);
n_vertices = shape.getRing(j, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
process_shape(path, LakeArea, &gpc_shape);
free_shape(&gpc_shape);
}
} else if ( area == OceanArea ) {
// interior of polygon is ocean, holes are islands
init_shape(&gpc_shape);
for ( j = 0; j < shape.numRings(); j++ ) {
n_vertices = shape.getRing(j, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
}
process_shape(path, area, &gpc_shape);
free_shape(&gpc_shape);
} else if ( area == LakeArea ) {
// interior of polygon is lake, holes are islands
init_shape(&gpc_shape);
for ( j = 0; j < shape.numRings(); j++ ) {
n_vertices = shape.getRing(j, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
}
process_shape(path, area, &gpc_shape);
free_shape(&gpc_shape);
} else if ( area == DryLakeArea ) {
// interior of polygon is dry lake, holes are islands
init_shape(&gpc_shape);
for ( j = 0; j < shape.numRings(); j++ ) {
n_vertices = shape.getRing(j, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
}
process_shape(path, area, &gpc_shape);
free_shape(&gpc_shape);
} else if ( area == IntLakeArea ) {
// interior of polygon is intermittent lake, holes are islands
init_shape(&gpc_shape);
for ( j = 0; j < shape.numRings(); j++ ) {
n_vertices = shape.getRing(j, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
}
process_shape(path, area, &gpc_shape);
free_shape(&gpc_shape);
} else if ( area == ReservoirArea ) {
// interior of polygon is reservoir, holes are islands
init_shape(&gpc_shape);
for ( j = 0; j < shape.numRings(); j++ ) {
n_vertices = shape.getRing(j, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
}
process_shape(path, area, &gpc_shape);
free_shape(&gpc_shape);
} else if ( area == IntReservoirArea ) {
// interior of polygon is intermittent reservoir, holes are islands
init_shape(&gpc_shape);
for ( j = 0; j < shape.numRings(); j++ ) {
n_vertices = shape.getRing(j, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
}
process_shape(path, area, &gpc_shape);
free_shape(&gpc_shape);
} else if ( area == StreamArea ) {
// interior of polygon is stream, holes are islands
init_shape(&gpc_shape);
for ( j = 0; j < shape.numRings(); j++ ) {
n_vertices = shape.getRing(j, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
}
process_shape(path, area, &gpc_shape);
free_shape(&gpc_shape);
} else if ( area == CanalArea ) {
// interior of polygon is canal, holes are islands
init_shape(&gpc_shape);
for ( j = 0; j < shape.numRings(); j++ ) {
n_vertices = shape.getRing(j, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
}
process_shape(path, area, &gpc_shape);
free_shape(&gpc_shape);
} else if ( area == GlacierArea ) {
// interior of polygon is glacier, holes are dry land
init_shape(&gpc_shape);
for ( j = 0; j < shape.numRings(); j++ ) {
n_vertices = shape.getRing(j, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
}
process_shape(path, area, &gpc_shape);
free_shape(&gpc_shape);
} else if ( area == VoidArea ) {
// interior is ????
// skip for now
FG_LOG( FG_GENERAL, FG_ALERT, "Void area ... SKIPPING!" );
if ( shape.numRings() > 1 ) {
FG_LOG( FG_GENERAL, FG_ALERT, " Void area with holes!" );
// exit(-1);
}
init_shape(&gpc_shape);
for ( j = 0; j < shape.numRings(); j++ ) {
n_vertices = shape.getRing(j, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
}
// process_shape(path, area, &gpc_shape);
free_shape(&gpc_shape);
} else if ( area == NullArea ) {
// interior is ????
// skip for now
FG_LOG( FG_GENERAL, FG_ALERT, "Null area ... SKIPPING!" );
if ( shape.numRings() > 1 ) {
FG_LOG( FG_GENERAL, FG_ALERT, " Null area with holes!" );
// exit(-1);
}
init_shape(&gpc_shape);
for ( j = 0; j < shape.numRings(); j++ ) {
n_vertices = shape.getRing(j, coords);
add_to_shape(n_vertices, coords, &gpc_shape);
}
// process_shape(path, area, &gpc_shape);
free_shape(&gpc_shape);
} else {
FG_LOG( FG_GENERAL, FG_ALERT, "Uknown area!" );
exit(-1);
}
}
return 0;
}
// $Log$
// Revision 1.8 1999/03/22 23:49:36 curt
// Moved AreaType get_shapefile_type(GDBFile *dbf, int rec) to where it
// belongs in ShapeFile/
//
// Revision 1.7 1999/03/17 23:51:29 curt
// Changed polygon index counter file.
//
// Revision 1.6 1999/03/02 01:04:28 curt
// Don't crash when work directory doesn't exist ... create it.
//
// Revision 1.5 1999/03/01 15:36:28 curt
// Tweaked a function call name in "names.hxx".
//
// Revision 1.4 1999/02/25 21:31:05 curt
// First working version???
//
// Revision 1.3 1999/02/23 01:29:04 curt
// Additional progress.
//
// Revision 1.2 1999/02/19 19:05:18 curt
// Working on clipping shapes and distributing into buckets.
//
// Revision 1.1 1999/02/15 19:10:23 curt
// Initial revision.
//

255
Tools/ShapeFile/shape.cxx Normal file
View file

@ -0,0 +1,255 @@
// shape.cxx -- shape/gpc utils
//
// Written by Curtis Olson, started February 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <Include/compiler.h>
#include STL_STRING
#include <Bucket/newbucket.hxx>
#include <Debug/logstream.hxx>
#include <Polygon/index.hxx>
#include <Polygon/names.hxx>
#include "shape.hxx"
#define FG_MAX_VERTICES 100000
static gpc_vertex_list v_list;
class point2d {
public:
double x, y;
};
static void clip_and_write_poly( string root, long int p_index, AreaType area,
FGBucket b, gpc_polygon *shape ) {
point2d c, min, max;
c.x = b.get_center_lon();
c.y = b.get_center_lat();
double span = bucket_span(c.y);
gpc_polygon base, result;
char tile_name[256], poly_index[256];
// calculate bucket dimensions
if ( (c.y >= -89.0) && (c.y < 89.0) ) {
min.x = c.x - span / 2.0;
max.x = c.x + span / 2.0;
min.y = c.y - FG_HALF_BUCKET_SPAN;
max.y = c.y + FG_HALF_BUCKET_SPAN;
} else if ( c.y < -89.0) {
min.x = -90.0;
max.x = -89.0;
min.y = -180.0;
max.y = 180.0;
} else if ( c.y >= 89.0) {
min.x = 89.0;
max.x = 90.0;
min.y = -180.0;
max.y = 180.0;
} else {
FG_LOG ( FG_GENERAL, FG_ALERT,
"Out of range latitude in clip_and_write_poly() = " << c.y );
}
FG_LOG( FG_GENERAL, FG_INFO, " (" << min.x << "," << min.y << ") ("
<< max.x << "," << max.y << ")" );
// set up clipping tile
v_list.vertex[0].x = min.x;
v_list.vertex[0].y = min.y;
v_list.vertex[1].x = max.x;
v_list.vertex[1].y = min.y;
v_list.vertex[2].x = max.x;
v_list.vertex[2].y = max.y;
v_list.vertex[3].x = min.x;
v_list.vertex[3].y = max.y;
v_list.num_vertices = 4;
base.num_contours = 0;
base.contour = NULL;
gpc_add_contour( &base, &v_list );
// FG_LOG( FG_GENERAL, FG_DEBUG, "base = 4 vertices" );
/*
FILE *bfp= fopen("base", "w");
gpc_write_polygon(bfp, &base);
fclose(bfp);
*/
gpc_polygon_clip(GPC_INT, &base, shape, &result);
if ( result.num_contours > 0 ) {
long int t_index = b.gen_index();
string path = root + "/Scenery/" + b.gen_base_path();
string command = "mkdir -p " + path;
system( command.c_str() );
sprintf( tile_name, "%ld", t_index );
string polyfile = path + "/" + tile_name;
sprintf( poly_index, "%ld", p_index );
polyfile += ".";
polyfile += poly_index;
string poly_type = get_area_name( area );
if ( poly_type == "Unknown" ) {
cout << "unknown area type in clip_and_write_poly()!" << endl;
exit(-1);
}
FILE *rfp= fopen( polyfile.c_str(), "w" );
fprintf( rfp, "%s\n", poly_type.c_str() );
gpc_write_polygon( rfp, &result );
fclose( rfp );
}
gpc_free_polygon(&base);
gpc_free_polygon(&result);
}
// Initialize structure we use to create polygons for the gpc library
bool shape_utils_init() {
v_list.num_vertices = 0;
v_list.vertex = new gpc_vertex[FG_MAX_VERTICES];;
return true;
}
// initialize a gpc_polygon
void init_shape(gpc_polygon *shape) {
shape->num_contours = 0;
shape->contour = NULL;
}
// make a gpc_polygon
void add_to_shape(int count, double *coords, gpc_polygon *shape) {
for ( int i = 0; i < count; i++ ) {
v_list.vertex[i].x = coords[i*2+0];
v_list.vertex[i].y = coords[i*2+1];
}
v_list.num_vertices = count;
gpc_add_contour( shape, &v_list );
}
// process shape (write polygon to all intersecting tiles)
void process_shape(string path, AreaType area, gpc_polygon *gpc_shape) {
point2d min, max;
long int index;
int i, j;
min.x = min.y = 200.0;
max.x = max.y = -200.0;
// find min/max of polygon
for ( i = 0; i < gpc_shape->num_contours; i++ ) {
for ( j = 0; j < gpc_shape->contour[i].num_vertices; j++ ) {
double x = gpc_shape->contour[i].vertex[j].x;
double y = gpc_shape->contour[i].vertex[j].y;
if ( x < min.x ) { min.x = x; }
if ( y < min.y ) { min.y = y; }
if ( x > max.x ) { max.x = x; }
if ( y > max.y ) { max.y = y; }
}
}
/*
FILE *sfp= fopen("shape", "w");
gpc_write_polygon(sfp, gpc_shape);
fclose(sfp);
exit(-1);
*/
// get next polygon index
index = poly_index_next();
FG_LOG( FG_GENERAL, FG_INFO, " min = " << min.x << "," << min.y
<< " max = " << max.x << "," << max.y );
// find buckets for min, and max points of convex hull.
// note to self: self, you should think about checking for
// polygons that span the date line
FGBucket b_min(min.x, min.y);
FGBucket b_max(max.x, max.y);
FG_LOG( FG_GENERAL, FG_INFO, " Bucket min = " << b_min );
FG_LOG( FG_GENERAL, FG_INFO, " Bucket max = " << b_max );
if ( b_min == b_max ) {
clip_and_write_poly( path, index, area, b_min, gpc_shape );
} else {
FGBucket b_cur;
int dx, dy, i, j;
fgBucketDiff(b_min, b_max, &dx, &dy);
FG_LOG( FG_GENERAL, FG_INFO,
" polygon spans tile boundaries" );
FG_LOG( FG_GENERAL, FG_INFO, " dx = " << dx
<< " dy = " << dy );
if ( (dx > 100) || (dy > 100) ) {
FG_LOG( FG_GENERAL, FG_ALERT,
"somethings really wrong!!!!" );
exit(-1);
}
for ( j = 0; j <= dy; j++ ) {
for ( i = 0; i <= dx; i++ ) {
b_cur = fgBucketOffset(min.x, min.y, i, j);
clip_and_write_poly( path, index, area, b_cur, gpc_shape );
}
}
// string answer; cin >> answer;
}
}
// free a gpc_polygon
void free_shape(gpc_polygon *shape) {
gpc_free_polygon(shape);
}
// $Log$
// Revision 1.3 1999/03/19 00:27:41 curt
// Use long int for index instead of just int.
//
// Revision 1.2 1999/02/25 21:31:08 curt
// First working version???
//
// Revision 1.1 1999/02/23 01:29:06 curt
// Additional progress.
//

64
Tools/ShapeFile/shape.hxx Normal file
View file

@ -0,0 +1,64 @@
// shape.hxx -- shape/gpc utils
//
// Written by Curtis Olson, started February 1999.
//
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifndef _SHAPE_HXX
#define _SHAPE_HXX
// include Generic Polygon Clipping Library
extern "C" {
#include <gpc.h>
}
#include <Polygon/names.hxx>
// Initialize structure we use to create polygons for the gpc library
// this must be called once from main for any program that uses this library
bool shape_utils_init();
// initialize a gpc_polygon
void init_shape(gpc_polygon *shape);
// make a gpc_polygon
void add_to_shape(int count, double *coords, gpc_polygon *shape);
// process shape (write polygon to all intersecting tiles)
void process_shape(string path, AreaType area, gpc_polygon *gpc_shape);
// free a gpc_polygon
void free_shape(gpc_polygon *shape);
#endif // _SHAPE_HXX
// $Log$
// Revision 1.2 1999/02/25 21:31:09 curt
// First working version???
//
// Revision 1.1 1999/02/23 01:29:06 curt
// Additional progress.
//

View file

@ -0,0 +1,77 @@
#---------------------------------------------------------------------------
# Makefile
#
# Written by Curtis Olson, started January 1998.
#
# Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id$
# (Log is kept at end of this file)
#---------------------------------------------------------------------------
bin_PROGRAMS = splittris
splittris_SOURCES = splittris.cxx splittris.hxx
splittris_LDADD = \
$(top_builddir)/Lib/Bucket/libBucket.a \
$(top_builddir)/Lib/Math/libMath.a \
$(top_builddir)/Lib/Debug/libDebug.a \
$(top_builddir)/Lib/Misc/libMisc.a \
$(top_builddir)/Lib/zlib/libz.a \
$(base_LIBS)
INCLUDES += -I$(top_builddir) -I$(top_builddir)/Lib
#---------------------------------------------------------------------------
# $Log$
# Revision 1.8 1998/11/04 23:01:57 curt
# Changes to the automake/autoconf system to reduce the number of libraries
# that are unnecessarily linked into the various executables.
#
# Revision 1.7 1998/10/18 01:17:25 curt
# Point3D tweaks.
#
# Revision 1.6 1998/07/30 23:49:26 curt
# Removed libtool support.
#
# Revision 1.5 1998/07/08 14:49:13 curt
# tweaks.
#
# Revision 1.4 1998/04/24 00:44:06 curt
# Added zlib support.
#
# Revision 1.3 1998/04/18 04:01:17 curt
# Now use libMath rather than having local copies of math routines.
#
# Revision 1.2 1998/04/14 02:26:06 curt
# Code reorganizations. Added a Lib/ directory for more general libraries.
#
# Revision 1.1 1998/04/08 23:21:10 curt
# Adopted Gnu automake/autoconf system.
#
# Revision 1.3 1998/01/21 02:55:55 curt
# Incorporated new make system from Bob Kuehne <rpk@sgi.com>.
#
# Revision 1.2 1998/01/14 15:54:42 curt
# Initial revision completed.
#
# Revision 1.1 1998/01/14 02:11:30 curt
# Initial revision.
#

View file

@ -0,0 +1,673 @@
// splittris.cxx -- read in a .ele/.node file pair generated by the
// triangle program and output a simple Wavefront .obj
// file for the north, south, east, and west edge
// verticies ... including the normals.
//
// Written by Curtis Olson, started January 1998.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#include <math.h>
#include <stdio.h>
#include <stdlib.h> // for atoi()
#include <string.h>
#include <sys/stat.h> // for stat()
#include <unistd.h> // for stat()
#include "splittris.hxx"
#include <Include/fg_constants.h>
#include <Bucket/bucketutils.h>
#include <Math/fg_geodesy.hxx>
#include <Math/mat3.h>
#include <Math/point3d.hxx>
#include <Math/polar3d.hxx>
#include <Misc/fgstream.hxx>
// int nodecount, tricount;
double xmin, xmax, ymin, ymax;
// static double nodes_orig[MAX_NODES][3];
// static Point3D nodes_cart[MAX_NODES];
// static int tris[MAX_TRIS][3];
container_3d nodes_orig;
container_3d nodes_cart;
container_tri tri_list;
fgBUCKET ne_index, nw_index, sw_index, se_index;
fgBUCKET north_index, south_index, east_index, west_index;
// given three points defining a triangle, calculate the normal
void calc_normal(const Point3D& p1, const Point3D& p2,
const Point3D& p3, double normal[3])
{
double v1[3], v2[3];
double temp;
v1[0] = p2.x() - p1.x(); v1[1] = p2.y() - p1.y(); v1[2] = p2.z() - p1.z();
v2[0] = p3.x() - p1.x(); v2[1] = p3.y() - p1.y(); v2[2] = p3.z() - p1.z();
MAT3cross_product(normal, v1, v2);
MAT3_NORMALIZE_VEC(normal,temp);
// printf(" Normal = %.2f %.2f %.2f\n", normal[0], normal[1], normal[2]);
}
// return the file base name ( foo/bar/file.ext = file.ext )
string extract_file(const string& input) {
int pos;
pos = input.rfind("/");
++pos;
return input.substr(pos);
}
// return the file path name ( foo/bar/file.ext = foo/bar )
string extract_path(const string& input) {
int pos;
pos = input.rfind("/");
return input.substr(0, pos);
}
// return the index of all triangles containing the specified node
void find_tris(int n, int *t1, int *t2, int *t3, int *t4, int *t5) {
int i;
*t1 = *t2 = *t3 = *t4 = *t5 = 0;
i = 1;
iterator_tri last = tri_list.end();
iterator_tri current = tri_list.begin();
// skip first null record
++current;
for ( ; current != last; ++current )
{
if ( (n == (*current).n1) || (n == (*current).n2) ||
(n == (*current).n3) )
{
if ( *t1 == 0 ) {
*t1 = i;
} else if ( *t2 == 0 ) {
*t2 = i;
} else if ( *t3 == 0 ) {
*t3 = i;
} else if ( *t4 == 0 ) {
*t4 = i;
} else {
*t5 = i;
}
}
++i;
}
}
// Initialize a new mesh structure
void triload(const string& basename) {
string nodename, elename;
Point3D node1, node2, p;
triangle tri;
int nodecount, tricount, dim, junk1, junk2;
int i;
nodename = basename + ".node";
elename = basename + ".ele";
cout << "Loading node file: " + nodename + " ...\n";
fg_gzifstream node_in( nodename );
if ( !node_in ) {
cout << "Cannot open file " + nodename + "\n";
exit(-1);
}
// the triangle program starts counting at 1 by default which is
// pretty obnoxious. Let's just push null record zero's onto our
// list to compensate
nodes_orig.push_back(node1);
nodes_cart.push_back(node1);
tri_list.push_back(tri);
node_in >> nodecount >> dim >> junk1 >> junk2;
cout << " Expecting " << nodecount << " nodes\n";
for ( i = 1; i <= nodecount; i++ ) {
node_in >> junk1 >> node1 >> junk2;
nodes_orig.push_back(node1);
// printf("%d %.2f %.2f %.2f\n", junk1, node1.x, node1.y, node1.z);
// convert to radians (before we can convert to cartesian)
p = Point3D( node1.x() * ARCSEC_TO_RAD,
node1.y() * ARCSEC_TO_RAD,
node1.z() );
node2 = fgGeodToCart(p);
nodes_cart.push_back(node2);
// printf("%d %.2f %.2f %.2f\n", junk1, node2.x, node2.y, node2.z);
if ( i == 1 ) {
xmin = xmax = node1.x();
ymin = ymax = node1.y();
} else {
if ( node1.x() < xmin ) {
xmin = node1.x();
}
if ( node1.x() > xmax ) {
xmax = node1.x();
}
if ( node1.y() < ymin ) {
ymin = node1.y();
}
if ( node1.y() > ymax ) {
ymax = node1.y();
}
}
}
cout << "Loading element file: " + elename + " ...\n";
fg_gzifstream ele_in( elename );
if ( !ele_in ) {
cout << "Cannot open file " + elename + "\n";
exit(-1);
}
ele_in >> tricount >> junk1 >> junk2;
cout << " Expecting " << tricount << " elements\n";
for ( i = 1; i <= tricount; i++ ) {
// fscanf(ele_file, "%d %d %d %d\n", &junk1,
// &(tri.n1), &(tri.n2), &(tri.n3));
ele_in >> junk1 >> tri.n1 >> tri.n2 >> tri.n3;
// printf("%d %d %d %d\n", junk1, tri.n1, tri.n2, tri.n3);
tri_list.push_back(tri);
}
}
// check if a file exists
int file_exists(char *file) {
struct stat stat_buf;
int result;
cout << "checking " << file << " ... ";
result = stat(file, &stat_buf);
if ( result != 0 ) {
// stat failed, no file
cout << "not found.\n";
return 0;
} else {
// stat succeeded, file exists
cout << "exists.\n";
return 1;
}
}
// check to see if a shared object exists
int shared_object_exists(const char *basepath, const string& ext) {
char file[256], scene_path[256];
long int index;
if ( ext == ".sw" ) {
fgBucketGenBasePath(&west_index, scene_path);
index = fgBucketGenIndex(&west_index);
sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&sw_index, scene_path);
index = fgBucketGenIndex(&sw_index);
sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&south_index, scene_path);
index = fgBucketGenIndex(&south_index);
sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( ext == ".se" ) {
fgBucketGenBasePath(&east_index, scene_path);
index = fgBucketGenIndex(&east_index);
sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&se_index, scene_path);
index = fgBucketGenIndex(&se_index);
sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&south_index, scene_path);
index = fgBucketGenIndex(&south_index);
sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( ext == ".ne" ) {
fgBucketGenBasePath(&east_index, scene_path);
index = fgBucketGenIndex(&east_index);
sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&ne_index, scene_path);
index = fgBucketGenIndex(&ne_index);
sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&north_index, scene_path);
index = fgBucketGenIndex(&north_index);
sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( ext == ".nw" ) {
fgBucketGenBasePath(&west_index, scene_path);
index = fgBucketGenIndex(&west_index);
sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&nw_index, scene_path);
index = fgBucketGenIndex(&nw_index);
sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
fgBucketGenBasePath(&north_index, scene_path);
index = fgBucketGenIndex(&north_index);
sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( ext == ".south" ) {
fgBucketGenBasePath(&south_index, scene_path);
index = fgBucketGenIndex(&south_index);
sprintf(file, "%s/%s/%ld.1.north", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( ext == ".north" ) {
fgBucketGenBasePath(&north_index, scene_path);
index = fgBucketGenIndex(&north_index);
sprintf(file, "%s/%s/%ld.1.south", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( ext == ".west" ) {
fgBucketGenBasePath(&west_index, scene_path);
index = fgBucketGenIndex(&west_index);
sprintf(file, "%s/%s/%ld.1.east", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
if ( ext == ".east" ) {
fgBucketGenBasePath(&east_index, scene_path);
index = fgBucketGenIndex(&east_index);
sprintf(file, "%s/%s/%ld.1.west", basepath, scene_path, index);
if ( file_exists(file) ) {
return(1);
}
}
return(0);
}
// my custom file opening routine ... don't open if a shared edge or
// vertex alread exists
FILE *my_open(const string& basename, const string& basepath,
const string& ext)
{
FILE *fp;
string filename;
// create the output file name
filename = basename + ext;
// check if a shared object already exist from a different tile
if ( shared_object_exists(basepath.c_str(), ext) ) {
// not an actual file open error, but we've already got the
// shared edge, so we don't want to create another one
cout << "not opening\n";
return(NULL);
} else {
// open the file
fp = fopen(filename.c_str(), "w");
cout << "Opening " + filename + "\n";
return(fp);
}
}
// dump in WaveFront .obj format
void dump_obj(const string& basename, const string& basepath) {
Point3D node;
double n1[3], n2[3], n3[3], n4[3], n5[3], norm[3], temp;
FILE *fp, *sw, *se, *ne, *nw, *north, *south, *east, *west, *body;
int i, t1, t2, t3, t4, t5, count, size;
double x, y, z;
sw = my_open(basename, basepath, ".sw");
se = my_open(basename, basepath, ".se");
ne = my_open(basename, basepath, ".ne");
nw = my_open(basename, basepath, ".nw");
north = my_open(basename, basepath, ".north");
south = my_open(basename, basepath, ".south");
east = my_open(basename, basepath, ".east");
west = my_open(basename, basepath, ".west");
body = my_open(basename, basepath, ".body");
cout << "Dumping edges file basename: " + basename + " ...\n";
// dump vertices
cout << " writing vertices\n";
iterator_3d last = nodes_orig.end();
iterator_3d current = nodes_orig.begin();
++current;
for ( ; current != last; ++current) {
node = *current;
if ( (fabs(node.y() - ymin) < FG_EPSILON) &&
(fabs(node.x() - xmin) < FG_EPSILON) ) {
fp = sw;
} else if ( (fabs(node.y() - ymin) < FG_EPSILON) &&
(fabs(node.x() - xmax) < FG_EPSILON) ) {
fp = se;
} else if ( (fabs(node.y() - ymax) < FG_EPSILON) &&
(fabs(node.x() - xmax) < FG_EPSILON)) {
fp = ne;
} else if ( (fabs(node.y() - ymax) < FG_EPSILON) &&
(fabs(node.x() - xmin) < FG_EPSILON) ) {
fp = nw;
} else if ( fabs(node.x() - xmin) < FG_EPSILON ) {
fp = west;
} else if ( fabs(node.x() - xmax) < FG_EPSILON ) {
fp = east;
} else if ( fabs(node.y() - ymin) < FG_EPSILON ) {
fp = south;
} else if ( fabs(node.y() - ymax) < FG_EPSILON ) {
fp = north;
} else {
fp = body;
}
x = node.x();
y = node.y();
z = node.z();
if ( fp != NULL ) {
fprintf(fp, "gdn %.2f %.2f %.2f\n", x, y, z);
}
}
cout << " calculating and writing normals\n";
// calculate and generate normals
size = nodes_orig.size();
for ( i = 1; i < size; i++ ) {
// printf("Finding normal\n");
find_tris(i, &t1, &t2, &t3, &t4, &t5);
n1[0] = n1[1] = n1[2] = 0.0;
n2[0] = n2[1] = n2[2] = 0.0;
n3[0] = n3[1] = n3[2] = 0.0;
n4[0] = n4[1] = n4[2] = 0.0;
n5[0] = n5[1] = n5[2] = 0.0;
count = 1;
calc_normal(nodes_cart[tri_list[t1].n1],
nodes_cart[tri_list[t1].n2],
nodes_cart[tri_list[t1].n3],
n1);
if ( t2 > 0 ) {
calc_normal(nodes_cart[tri_list[t2].n1],
nodes_cart[tri_list[t2].n2],
nodes_cart[tri_list[t2].n3],
n2);
count = 2;
}
if ( t3 > 0 ) {
calc_normal(nodes_cart[tri_list[t3].n1],
nodes_cart[tri_list[t3].n2],
nodes_cart[tri_list[t3].n3],
n3);
count = 3;
}
if ( t4 > 0 ) {
calc_normal(nodes_cart[tri_list[t4].n1],
nodes_cart[tri_list[t4].n2],
nodes_cart[tri_list[t4].n3],
n4);
count = 4;
}
if ( t5 > 0 ) {
calc_normal(nodes_cart[tri_list[t5].n1],
nodes_cart[tri_list[t5].n2],
nodes_cart[tri_list[t5].n3],
n5);
count = 5;
}
// printf(" norm[2] = %.2f %.2f %.2f\n", n1[2], n2[2], n3[2]);
norm[0] = ( n1[0] + n2[0] + n3[0] + n4[0] + n5[0] ) / (double)count;
norm[1] = ( n1[1] + n2[1] + n3[1] + n4[1] + n5[1] ) / (double)count;
norm[2] = ( n1[2] + n2[2] + n3[2] + n4[2] + n5[2] ) / (double)count;
// printf(" count = %d\n", count);
// printf(" Ave. normal = %.4f %.4f %.4f\n", norm[0], norm[1],
// norm[2]);
MAT3_NORMALIZE_VEC(norm, temp);
// printf(" Normalized ave. normal = %.4f %.4f %.4f\n",
// norm[0], norm[1], norm[2]);
fp = NULL;
if ( (fabs(nodes_orig[i].y() - ymin) < FG_EPSILON) &&
(fabs(nodes_orig[i].x() - xmin) < FG_EPSILON) ) {
fp = sw;
} else if ( (fabs(nodes_orig[i].y() - ymin) < FG_EPSILON) &&
(fabs(nodes_orig[i].x() - xmax) < FG_EPSILON) ) {
fp = se;
} else if ( (fabs(nodes_orig[i].y() - ymax) < FG_EPSILON) &&
(fabs(nodes_orig[i].x() - xmax) < FG_EPSILON)) {
fp = ne;
} else if ( (fabs(nodes_orig[i].y() - ymax) < FG_EPSILON) &&
(fabs(nodes_orig[i].x() - xmin) < FG_EPSILON) ) {
fp = nw;
} else if ( fabs(nodes_orig[i].x() - xmin) < FG_EPSILON ) {
fp = west;
} else if ( fabs(nodes_orig[i].x() - xmax) < FG_EPSILON ) {
fp = east;
} else if ( fabs(nodes_orig[i].y() - ymin) < FG_EPSILON ) {
fp = south;
} else if ( fabs(nodes_orig[i].y() - ymax) < FG_EPSILON ) {
fp = north;
}
if ( fp != NULL ) {
fprintf(fp, "vn %.4f %.4f %.4f\n", norm[0], norm[1], norm[2]);
}
}
if ( sw ) { fclose(sw); }
if ( se ) { fclose(se); }
if ( ne ) { fclose(ne); }
if ( nw ) { fclose(nw); }
if ( north ) { fclose(north); }
if ( south ) { fclose(south); }
if ( east ) { fclose(east); }
if ( west ) { fclose(west); }
if ( body ) { fclose(body); }
}
int main(int argc, char **argv) {
string basename, basepath, temp;
fgBUCKET p;
long int index;
int len;
basename = argv[1];
// find the base path of the file
basepath = extract_path(basename);
basepath = extract_path(basepath);
basepath = extract_path(basepath);
cout << "basepath = " + basepath + "\n";
// find the index of the current file
temp = extract_file(basename);
len = temp.length();
if ( len >= 2 ) {
temp = temp.substr(0, len-2);
}
index = atoi( temp.c_str() );
cout << "index = " << index << "\n";
fgBucketParseIndex(index, &p);
cout << "bucket = " << p.lon << " " << p.lat << " " <<
p.x << " " << p.y << "\n";
// generate the indexes of the neighbors
fgBucketOffset(&p, &ne_index, 1, 1);
fgBucketOffset(&p, &nw_index, -1, 1);
fgBucketOffset(&p, &se_index, 1, -1);
fgBucketOffset(&p, &sw_index, -1, -1);
fgBucketOffset(&p, &north_index, 0, 1);
fgBucketOffset(&p, &south_index, 0, -1);
fgBucketOffset(&p, &east_index, 1, 0);
fgBucketOffset(&p, &west_index, -1, 0);
// printf("Corner indexes = %ld %ld %ld %ld\n",
// ne_index, nw_index, sw_index, se_index);
// printf("Edge indexes = %ld %ld %ld %ld\n",
// north_index, south_index, east_index, west_index);
// load the input data files
triload(basename);
// dump in WaveFront .obj format
dump_obj(basename, basepath);
return(0);
}
// $Log$
// Revision 1.7 1998/11/06 21:33:57 curt
// Updates to go along with changes in fgstream.
//
// Revision 1.6 1998/10/21 14:56:20 curt
// Fixed a units conversion bug.
//
// Revision 1.5 1998/10/20 15:50:33 curt
// whitespace tweak.
//
// Revision 1.4 1998/10/18 01:17:27 curt
// Point3D tweaks.
//
// Revision 1.3 1998/09/22 23:49:56 curt
// C++-ified, STL-ified, and string-ified.
//
// Revision 1.2 1998/09/21 23:16:23 curt
// Converted to c++ style comments.
//
// Revision 1.1 1998/07/08 14:59:13 curt
// *.[ch] renamed to *.[ch]xx
//
// Revision 1.11 1998/07/04 00:56:40 curt
// typedef'd struct fgBUCKET.
//
// Revision 1.10 1998/05/02 01:54:37 curt
// Converting to polar3d.h routines.
//
// Revision 1.9 1998/04/18 04:01:20 curt
// Now use libMath rather than having local copies of math routines.
//
// Revision 1.8 1998/04/14 02:26:08 curt
// Code reorganizations. Added a Lib/ directory for more general libraries.
//
// Revision 1.7 1998/04/08 23:21:13 curt
// Adopted Gnu automake/autoconf system.
//
// Revision 1.6 1998/03/03 15:36:13 curt
// Tweaks for compiling with g++
//
// Revision 1.5 1998/03/03 03:37:04 curt
// Cumulative tweaks.
//
// Revision 1.4 1998/01/31 00:41:26 curt
// Made a few changes converting floats to doubles.
//
// Revision 1.3 1998/01/27 18:37:04 curt
// Lots of updates to get back in sync with changes made over in .../Src/
//
// Revision 1.2 1998/01/14 15:54:43 curt
// Initial revision completed.
//
// Revision 1.1 1998/01/14 02:11:31 curt
// Initial revision.
//

View file

@ -0,0 +1,89 @@
// splittris.hxx -- read in a .ele/.node file pair generated by the triangle
// program and output edge vertices w/ normals.
//
// Written by Curtis Olson, started January 1998.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
// (Log is kept at end of this file)
#ifndef SPLITTRIS_HXX
#define SPLITTRIS_HXX
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#include "Include/fg_stl_config.h"
#ifdef NEEDNAMESPACESTD
using namespace std;
#endif
#include <Math/point3d.hxx>
// A triangle (indices of the three nodes)
typedef struct {
int n1, n2, n3;
} triangle;
typedef vector < Point3D > container_3d;
typedef container_3d::iterator iterator_3d;
typedef container_3d::const_iterator const_iterator_3d;
typedef vector < triangle > container_tri;
typedef container_tri::iterator iterator_tri;
typedef container_tri::const_iterator const_iterator_tri;
// Initialize a new mesh structure
void triload(const string& basename);
#endif // SPLITTRIS_HXX
// $Log$
// Revision 1.4 1998/10/18 01:17:28 curt
// Point3D tweaks.
//
// Revision 1.3 1998/09/22 23:49:58 curt
// C++-ified, STL-ified, and string-ified.
//
// Revision 1.2 1998/09/21 23:16:24 curt
// Converted to c++ style comments.
//
// Revision 1.1 1998/07/08 14:59:14 curt
// *.[ch] renamed to *.[ch]xx
//
// Revision 1.3 1998/03/03 15:36:13 curt
// Tweaks for compiling with g++
//
// Revision 1.2 1998/01/15 02:49:25 curt
// Misc. housekeeping.
//
// Revision 1.1 1998/01/14 02:11:32 curt
// Initial revision.
//

View file

@ -0,0 +1,30 @@
bin_PROGRAMS = strips
strips_SOURCES = \
add.c add.h \
bands.c \
common.c common.h \
define.h \
extend.h \
free.c free.h \
global.h \
glove.h \
init.c init.h \
local.c local.h \
my_global.h \
newpolve.c \
options.c options.h \
output.c output.h \
outputex.c outputex.h \
partial.c partial.h \
polverts.h polvertsex.h \
queue.c queue.h \
sgi_triang.c sgi_triangex.c \
struct.c struct.h \
structex.c \
sturcts.h sturctsex.h \
ties.c ties.h \
triangulate.h triangulatex.h \
util.c util.h
strips_LDADD = $(base_LIBS)

386
Tools/Stripe_u/add.c Normal file
View file

@ -0,0 +1,386 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: add.c
This file contains the procedure code that will add information
to our data structures.
*/
/*---------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "global.h"
#include "queue.h"
#include "polverts.h"
#include "triangulate.h"
#include "ties.h"
#include "outputex.h"
#include "options.h"
#include "local.h"
BOOL new_vertex(double difference, int id1,int id2,
struct vert_struct *n)
{
/* Is the difference between id1 and id2 (2 normal vertices that
mapped to the same vertex) greater than the
threshold that was specified?
*/
struct vert_struct *pn1,*pn2;
double dot_product;
double distance1, distance2,distance;
double rad;
char arg1[100];
char arg2[100];
pn1 = n + id1;
pn2 = n + id2;
dot_product = ((pn1->x) * (pn2->x)) +
((pn1->y) * (pn2->y)) +
((pn1->z) * (pn2->z));
/* Get the absolute value */
if (dot_product < 0)
dot_product = dot_product * -1;
distance1 = sqrt( (pn1->x * pn1->x) +
(pn1->y * pn1->y) +
(pn1->z * pn1->z) );
distance2 = sqrt( (pn2->x * pn2->x) +
(pn2->y * pn2->y) +
(pn2->z * pn2->z) );
distance = distance1 * distance2;
rad = acos((double)dot_product/(double)distance);
/* convert to degrees */
rad = (180 * rad)/PI;
if ( rad <= difference)
return FALSE;
/* double checking because of imprecision with floating
point acos function
*/
sprintf( arg1,"%.5f", rad );
sprintf( arg2,"%.5f", difference );
if ( strcmp( arg1, arg2 ) <=0 )
return( FALSE );
if ( rad <= difference)
return FALSE;
else
return TRUE;
}
BOOL Check_VN(int vertex,int normal, struct vert_added *added)
{
/* Check to see if we already added this vertex and normal */
register int x,n;
n = (added+vertex)->num;
for (x = 0; x < n; x++)
{
if (*((added+vertex)->normal+x) == normal)
return TRUE;
}
return FALSE;
}
BOOL norm_array(int id, int vertex, double normal_difference,
struct vert_struct *n, int num_vert)
{
static int last;
static struct vert_added *added;
register int x;
static BOOL first = TRUE;
if (first)
{
/* This is the first time that we are in here, so we will allocate
a structure that will save the vertices that we added, so that we
do not add the same thing twice
*/
first = FALSE;
added = (struct vert_added *) malloc (sizeof (struct vert_added ) * num_vert);
/* The number of vertices added for each vertex must be initialized to
zero
*/
for (x = 0; x < num_vert; x++)
(added+x)->num = 0;
}
if (vertex)
/* Set the pointer to the vertex, we will be calling again with the
normal to fill it with
*/
last = id;
else
{
/* Fill the pointer with the id of the normal */
if (*(vert_norms + last) == 0)
*(vert_norms + last) = id;
else if ((*(vert_norms + last) != id) && ((int)normal_difference != 360))
{
/* difference is big enough, we need to create a new vertex */
if (new_vertex(normal_difference,id,*(vert_norms + last),n))
{
/* First check to see if we added this vertex and normal already */
if (Check_VN(last,id,added))
return FALSE;
/* OK, create the new vertex, and have its id = the number of vertices
and its normal what we have here
*/
vert_norms = realloc(vert_norms, sizeof(int) * (num_vert + 1));
if (!vert_norms)
{
printf("Allocation error - aborting\n");
exit(1);
}
*(vert_norms + num_vert) = id;
/* We created a new vertex, now put it in our added structure so
we do not add the same thing twice
*/
(added+last)->num = (added+last)->num + 1;
if ((added+last)->num == 1)
{
/* First time */
(added+last)->normal = (int *) malloc (sizeof (int ) * 1);
*((added+last)->normal) = id;
}
else
{
/* Not the first time, reallocate space */
(added+last)->normal = realloc((added+last)->normal,sizeof(int) * (added+last)->num);
*((added+last)->normal+((added+last)->num-1)) = id;
}
return TRUE;
}
}
}
return FALSE;
}
void add_texture(int id,BOOL vertex)
{
/* Save the texture with its vertex for future use when outputting */
static int last;
if (vertex)
last = id;
else
*(vert_texture+last) = id;
}
int add_vert_id(int id, int index_count)
{
register int x;
/* Test if degenerate, if so do not add degenerate vertex */
for (x = 1; x < index_count ; x++)
{
if (ids[x] == id)
return 0;
}
ids[index_count] = id;
return 1;
}
void add_norm_id(int id, int index_count)
{
norms[index_count] = id;
}
void AddNewFace(int ids[MAX1], int vert_count, int face_id, int norms[MAX1])
{
PF_FACES pfNode;
int *pTempInt;
int *pnorms;
F_EDGES **pTempVertptr;
int *pTempmarked, *pTempwalked;
register int y,count = 0,sum = 0;
/* Add a new face into our face data structure */
pfNode = (PF_FACES) malloc(sizeof(F_FACES) );
if ( pfNode )
{
pfNode->pPolygon = (int*) malloc(sizeof(int) * (vert_count) );
pfNode->pNorms = (int*) malloc(sizeof(int) * (vert_count) );
pfNode->VertandId = (F_EDGES**)malloc(sizeof(F_EDGES*) * (vert_count));
pfNode->marked = (int*)malloc(sizeof(int) * (vert_count));
pfNode->walked = (int*)malloc(sizeof(int) * (vert_count));
}
pTempInt =pfNode->pPolygon;
pnorms = pfNode->pNorms;
pTempmarked = pfNode->marked;
pTempwalked = pfNode->walked;
pTempVertptr = pfNode->VertandId;
pfNode->nPolSize = vert_count;
pfNode->seen = -1;
pfNode->seen2 = -1;
for (y=1;y<=vert_count;y++)
{
*(pTempInt + count) = ids[y];
*(pnorms + count) = norms[y];
*(pTempmarked + count) = FALSE;
*(pTempwalked + count) = -1;
*(pTempVertptr+count) = NULL;
count++;
}
AddHead(PolFaces[face_id-1],(PLISTINFO) pfNode);
}
void CopyFace(int ids[MAX1], int vert_count, int face_id, int norms[MAX1])
{
PF_FACES pfNode;
int *pTempInt;
int *pnorms;
F_EDGES **pTempVertptr;
int *pTempmarked, *pTempwalked;
register int y,count = 0,sum = 0;
/* Copy a face node into a new node, used after the global algorithm
is run, so that we can save whatever is left into a new structure
*/
pfNode = (PF_FACES) malloc(sizeof(F_FACES) );
if ( pfNode )
{
pfNode->pPolygon = (int*) malloc(sizeof(int) * (vert_count) );
pfNode->pNorms = (int*) malloc(sizeof(int) * (vert_count) );
pfNode->VertandId = (F_EDGES**)malloc(sizeof(F_EDGES*) * (vert_count));
pfNode->marked = (int*)malloc(sizeof(int) * (vert_count));
pfNode->walked = (int*)malloc(sizeof(int) * (vert_count));
}
pTempInt =pfNode->pPolygon;
pnorms = pfNode->pNorms;
pTempmarked = pfNode->marked;
pTempwalked = pfNode->walked;
pTempVertptr = pfNode->VertandId;
pfNode->nPolSize = vert_count;
pfNode->seen = -1;
pfNode->seen2 = -1;
for (y=0;y<vert_count;y++)
{
*(pTempInt + count) = ids[y];
*(pnorms + count) = norms[y];
*(pTempmarked + count) = FALSE;
*(pTempwalked + count) = -1;
*(pTempVertptr+count) = NULL;
count++;
}
AddHead(PolFaces[face_id-1],(PLISTINFO) pfNode);
}
void Add_Edge(int v1,int v2)
{
PF_EDGES temp = NULL;
ListHead *pListHead;
BOOL flag = TRUE;
register int t,count = 0;
/* Add a new edge into the edge data structure */
if (v1 > v2)
{
t = v1;
v1 = v2;
v2 = t;
}
pListHead = PolEdges[v1];
temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
if (temp == NULL)
{
printf("Have the wrong edge \n:");
exit(1);
}
while (flag)
{
if (v2 == temp->edge[0])
return;
else
temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,++count);
}
}
void Add_AdjEdge(int v1,int v2,int fnum,int index1 )
{
PF_EDGES temp = NULL;
PF_FACES temp2 = NULL;
PF_EDGES pfNode;
ListHead *pListHead;
ListHead *pListFace;
BOOL flag = TRUE;
register int count = 0;
register int t,v3 = -1;
if (v1 > v2)
{
t = v1;
v1 = v2;
v2 = t;
}
pListFace = PolFaces[fnum];
temp2 = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
pListHead = PolEdges[v1];
temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
if (temp == NULL)
flag = FALSE;
count++;
while (flag)
{
if (v2 == temp->edge[0])
{
/* If greater than 2 polygons adjacent to an edge, then we will
only save the first 2 that we found. We will have a small performance
hit, but this does not happen often.
*/
if (temp->edge[2] == -1)
temp->edge[2] = fnum;
else
v3 = temp->edge[2];
flag = FALSE;
}
else
{
temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
count++;
if (temp == NULL)
flag = FALSE;
}
}
/* Did not find it */
if (temp == NULL)
{
pfNode = (PF_EDGES) malloc(sizeof(F_EDGES) );
if ( pfNode )
{
pfNode->edge[0] = v2;
pfNode->edge[1] = fnum;
pfNode->edge[2] = v3;
AddTail( PolEdges[v1], (PLISTINFO) pfNode );
}
else
{
printf("Out of memory!\n");
exit(1);
}
*(temp2->VertandId+index1) = pfNode;
}
else
*(temp2->VertandId+index1) = temp;
}

25
Tools/Stripe_u/add.h Normal file
View file

@ -0,0 +1,25 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: add.h
-----------------------------------------------------------------------*/
BOOL new_vertex();
BOOL Check_VN();
BOOL norm_array();
void add_texture();
int add_vert_id();
void add_norm_id();
void AddNewFace();
void CopyFace();
void Add_Edge();
void Add_AdjEdge();

549
Tools/Stripe_u/bands.c Normal file
View file

@ -0,0 +1,549 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: bands.c
This file contains the main procedure code that will read in the
object and then call the routines that produce the triangle strips.
*/
/*---------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "global.h"
#include "polverts.h"
#include "triangulate.h"
#include "ties.h"
#include "outputex.h"
#include "options.h"
#include "local.h"
#include "init.h"
#include "free.h"
#include "add.h"
#define MAX1 60
/* TIMING for Windows */
#ifdef WIN32
#include <sys/timeb.h>
#include <time.h>
/* TIMING for UNIX */
#else
#include <sys/types.h>
#include <sys/param.h>
#include <sys/times.h>
#include <sys/time.h>
struct timeval tm;
struct timezone tz;
double et;
#define START gettimeofday(&tm,&tz);\
et = (tm.tv_sec)+ (0.000001* (tm.tv_usec));
#define STOP gettimeofday(&tm,&tz);\
et = (tm.tv_sec)+(0.000001*(tm.tv_usec)) - et;
#endif
void get_time()
{
/* For timing */
#ifdef WIN32
struct _timeb timebuffer;
char *timeline;
#else
long timer;
#endif
#ifdef WIN32
_ftime( &timebuffer );
timeline = ctime( & ( timebuffer.time ) );
printf( "The time is %.19s.%hu %s", timeline, timebuffer.millitm, &timeline[20] );
#else
printf("Time for last frame = %lf seconds\n", et);
#endif
}
/*
**
Here the main program begins. It will start by loading in a .obj file
then it will convert the polygonal model into triangle strips.
**
*/
void main (int argc,char *argv[])
{
char *fname,*all,buff[255], *ptr, *ptr2;
FILE *file, *bands;
int face_id=0, vert_count, loop, num=0,num2;
float center[3];
int temp[MAX1],vertex,strips, swaps,tempi,cost,triangles;
int f,t,tr,g;
char *file_open;
int num_vert = 0,
num_faces = 0,
num_nvert = 0,
num_edges = 0,
num_texture = 0,
num_tris = 0;
double fra = 0.0;
BOOL texture, normal, normal_and_texture,quads = FALSE;
/* Options variables */
float norm_difference;
/* Structures for the object */
struct vert_struct *vertices = NULL,
*nvertices = NULL,
*pvertices = NULL,
*pnvertices = NULL;
get_time();
START
/* File that will contain the triangle strip data */
bands = fopen("bands.d","w");
/*
Scan the file once to find out the number of vertices,
vertice normals, and faces so we can set up some memory
structures
*/
/* Interpret the options specified */
norm_difference = get_options(argc,argv,&f,&t,&tr,&g);
if (f == BINARY)
file_open = "rb";
else
file_open = "r";
fname = argv[argc-1];
printf ("File: %s\n",fname);
/*printf ("Scanning...%s ",file_open);*/
/* File can be in binary for faster reading */
if (file = fopen (fname,file_open))
{
while (!feof (file))
{
/* Read a line */
if (f == BINARY)
fread (buff,sizeof(char) * 255,1, file);
else
fgets (buff, sizeof(char) * 255, file);
num++;
/* At a vertex */
if (*buff == 'v')
{
/* At a normal */
if (*(buff+1)=='n')
num_nvert++;
else if (*(buff+1)=='t')
num_texture++;
/* At a regular vertex */
else
num_vert++;
}
/* At a face */
else if (*buff == 'f')
{
num_faces++;
strtok(buff, " ");
tempi = 0;
while (strtok(NULL, " ") != NULL) tempi++;
num_tris += tempi - 2;
}
}
fclose (file);
}
else
{
printf("Error in the file name\n");
exit(1);
}
/* Allocate structures for the information */
Start_Face_Struct(num_faces);
vertices = (struct vert_struct *)
malloc (sizeof (struct vert_struct) * num_vert);
if (num_nvert > 0)
{
nvertices = (struct vert_struct *)
malloc (sizeof (struct vert_struct) * num_nvert);
vert_norms = (int *)
malloc (sizeof (int) * num_vert);
/* Initialize entries to zero, in case there are 2 hits
to the same vertex we will know it - used for determining
the normal difference
*/
init_vert_norms(num_vert);
}
else
nvertices = NULL;
if (num_texture > 0)
{
vert_texture = (int *) malloc (sizeof(int) * num_vert);
init_vert_texture(num_vert);
}
/* Set up the temporary 'p' pointers
*/
pvertices = vertices;
pnvertices = nvertices;
/* Load the object into memory */
/*printf (" Loading...");*/
fprintf(bands,"#%s: a triangle strip representation created by STRIPE.\n#This is a .objf file\n#by Francine Evans\n",fname);
/* File will be put in a list for faster execution if file is in binary */
if (file = fopen(fname,file_open))
{
if (f == BINARY)
{
all = (char *) malloc (sizeof(char) * 255 * num);
fread(all,sizeof(char) * 255 * num, 1, file);
ptr = all;
}
else
ptr = (char *) malloc (sizeof(char) * 255 * num);
}
while (num > 0)
{
num--;
if (f == ASCII)
fgets (ptr, sizeof(char) * 255, file);
else
ptr = ptr + 255;
/* Load in vertices/normals */
if (*ptr == 'v')
{
if (*(ptr+1)=='n')
{
sscanf (ptr+3,"%lf%lf%lf",
&(pnvertices->x),
&(pnvertices->y),
&(pnvertices->z));
fprintf(bands,"vn %lf %lf %lf\n",
pnvertices->x,pnvertices->y,pnvertices->z);
++pnvertices;
}
else if (*(ptr+1)=='t')
{
sscanf (ptr+3,"%f%f%f",&center[0],&center[1],&center[2]);
fprintf(bands,"vt %f %f %f\n",center[0],center[1],center[2]);
}
else
{
sscanf (ptr+2,"%lf%lf%lf",
&(pvertices->x),
&(pvertices->y),
&(pvertices->z));
fprintf(bands,"v %lf %lf %lf\n",
pvertices->x,pvertices->y,pvertices->z);
++pvertices;
}
}
else if (*ptr == 'f')
{
/* Read in faces */
num2 = 0;
face_id++;
ptr2 = ptr+1;
normal = FALSE; texture = FALSE, normal_and_texture = FALSE;
while (*ptr2)
{
if (*ptr2 >='0' && *ptr2 <='9')
{
num2++;
++ptr2;
while (*ptr2 && (*ptr2!=' ' && *ptr2!='/'))
ptr2++;
/* There are normals in this line */
if (*ptr2 == '/')
{
if (*(ptr2+1) == '/')
normal = TRUE;
else
texture = TRUE;
}
else if (*ptr2 == ' ')
{
if ((num2 == 3) && (texture))
normal_and_texture = TRUE;
}
}
else
++ptr2;
}
ptr2 = ptr+1;
/* loop on the number of numbers in this line of face data
*/
vert_count = 0;
for (loop=0;loop<num2;loop++)
{
/* skip the whitespace */
while (*ptr2<'0' || *ptr2>'9')
{
if (*ptr2 == '-')
break;
ptr2++;
}
vertex = atoi(ptr2)-1;
if (vertex < 0)
{
vertex = num_vert + vertex;
*ptr2 = ' ';
ptr2++;
}
/* If there are either normals or textures with the vertices
in this file, the data alternates so we must read it this way
*/
if ( (normal) && (!normal_and_texture))
{
if (loop%2)
{
add_norm_id(vertex,vert_count);
/* Test here to see if we added a new vertex, since the
vertex has more than one normal and the 2 normals are greater
than the threshold specified
*/
if (norm_array(vertex,0,norm_difference,nvertices,num_vert))
{
/* Add a new vertex and change the
id of the vertex that we just read to the id of the new
vertex that we just added
*/
/* Put it in the output file, note the added vertices will
be after the normals and separated from the rest of the
vertices. Will not affect our viewer
*/
fprintf(bands,"v %lf %lf %lf\n",
(vertices + temp[vert_count - 1])->x,
(vertices + temp[vert_count - 1])->y,
(vertices + temp[vert_count - 1])->z);
num_vert++;
temp[vert_count - 1] = num_vert - 1;
if (!(add_vert_id(num_vert - 1,vert_count)))
vert_count--;
}
}
/* the vertex */
else
{
temp[vert_count] = vertex ;
vert_count++;
if (!(add_vert_id(vertex,vert_count)))
vert_count--;
norm_array(vertex,1,norm_difference,nvertices,num_vert);
}
}
/* Else there are vertices and textures with the data */
else if (normal_and_texture)
{
if( !((loop+1)%3))
{
add_norm_id(vertex,vert_count);
/* Test here to see if we added a new vertex, since the
vertex has more than one normal and the 2 normals are greater
than the threshold specified
*/
if (norm_array(vertex,0,norm_difference,nvertices,num_vert))
{
/* Add a new vertex and change the
id of the vertex that we just read to the id of the new
vertex that we just added
*/
/* Put it in the output file, note the added vertices will
be after the normals and separated from the rest of the
vertices. Will not affect our viewer
*/
fprintf(bands,"v %lf %lf %lf\n",
(vertices + temp[vert_count - 1])->x,
(vertices + temp[vert_count - 1])->y,
(vertices + temp[vert_count - 1])->z);
num_vert++;
temp[vert_count - 1] = num_vert - 1;
if (!(add_vert_id(num_vert - 1,vert_count)))
vert_count--;
}
}
/* the vertex */
else if ((loop == 0) || (*(ptr2-1) == ' '))
{
temp[vert_count] = vertex ;
vert_count++;
if (vert_count == 4)
quads = TRUE;
if (!(add_vert_id(vertex,vert_count)))
vert_count--;
add_texture(vertex,TRUE);
norm_array(vertex,1,norm_difference,nvertices,num_vert);
}
else /* The texture */
add_texture(vertex,FALSE);
}
else if ( texture )
{
/* the vertex */
if (!(loop%2))
{
temp[vert_count] = vertex ;
vert_count++;
if (vert_count == 4)
quads = TRUE;
add_texture(vertex,TRUE);
if (!(add_vert_id(vertex,vert_count)))
vert_count--;
norm_array(vertex,1,norm_difference,nvertices,num_vert);
}
else /* texture */
add_texture(vertex,FALSE);
}
else
{
/*** no nvertices ***/
temp[vert_count] = vertex ;
vert_count++;
if (vert_count == 4)
quads = TRUE;
if (!(add_vert_id(vertex,vert_count)))
vert_count--;
}
while (*ptr2>='0' && *ptr2<='9')
ptr2++;
}
/* Done with the polygon */
num_edges += vert_count;
/* add it to face structure */
if (vert_count >= 3)
AddNewFace(ids,vert_count,face_id,norms);
else
face_id--;
if (vert_count == 4)
quads = TRUE;
}
else if ((g == TRUE) && (face_id > 0)
&& ((*ptr == 'g') || (*ptr == 's') || (*ptr == 'm') || (*ptr == 'o')))
{
/* The user specified that the strips will be contained in each group
from the data file, so we just finished a group and will find the
triangle strips in it.
*/
Start_Edge_Struct(num_vert);
Find_Adjacencies(face_id);
if (quads)
{
Init_Table_SGI();
Build_SGI_Table(num_vert,face_id);
/* Code for lengths of walks in each direction */
Save_Walks(face_id,TRUE);
/* Code for finding the bands */
Find_Bands(face_id,bands,&swaps,&strips,&cost,&triangles,num_nvert,vert_norms,num_texture,vert_texture);
/* Remove the faces that we did so that we can
run the strip code on the rest of the faces that are left
*/
if (cost != 0)
{
printf("Total %d triangles with %d cost\n",triangles,cost);
Save_Rest(&face_id);
printf("We saved %d .... now doing the local algorithm\n",face_id);
fprintf(bands,"\n#local\n");
End_Edge_Struct(num_vert);
Start_Edge_Struct(num_vert);
Find_Adjacencies(face_id);
}
}
SGI_Strip(num_vert,face_id,bands,t,tr);
/* Get the total cost */
Output_TriEx(-1,-2,-3,NULL,-1,-20,cost);
End_Face_Struct(num_faces);
End_Edge_Struct(num_vert);
cost = 0;
face_id = 0;
quads = FALSE;
Start_Face_Struct(num_faces-face_id);
num_faces = num_faces - face_id;
Free_Strips();
}
}
/* Done reading in all the information into data structures */
num_faces = face_id;
fclose (file);
/*printf(" Done.\n\n");*/
free(vertices);
free(nvertices);
/*printf ("Vertices: %d\nNormals: %d\nFaces: %d\n",num_vert,num_nvert,num_faces);*/
Start_Edge_Struct(num_vert);
Find_Adjacencies(num_faces);
/* Initialize it */
Init_Table_SGI();
/* Build it */
Build_SGI_Table(num_vert,num_faces);
InitStripTable();
if (quads)
{
/* Code for lengths of walks in each direction */
Save_Walks(num_faces,TRUE);
/* Code for finding the bands */
Find_Bands(num_faces,bands,&swaps,&strips,&cost,&triangles,num_nvert,vert_norms,num_texture,vert_texture);
/*printf("Total %d triangles with %d cost\n",triangles,cost);*/
/* Remove the faces that we did so that we can
run the strip code on the rest of the faces that are left
*/
Save_Rest(&num_faces);
/*printf("We saved %d .... now doing the local algorithm\n",num_faces);*/
fprintf(bands,"\n#local\n");
End_Edge_Struct(num_vert);
Start_Edge_Struct(num_vert);
Find_Adjacencies(num_faces);
}
SGI_Strip(num_vert,num_faces,bands,t,tr);
/* Get the total cost */
Output_TriEx(-1,-2,-3,NULL,-1,-20,cost);
End_Face_Struct(num_faces);
End_Edge_Struct(num_vert);
fclose(bands);
STOP
get_time();
}

811
Tools/Stripe_u/common.c Normal file
View file

@ -0,0 +1,811 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: common.c
This file contains common code used in both the local and global algorithm
*/
/*---------------------------------------------------------------------*/
#include <stdlib.h>
#include "polverts.h"
#include "extend.h"
#include "output.h"
#include "triangulate.h"
#include "util.h"
#include "add.h"
int Old_Adj(int face_id)
{
/* Find the bucket that the face_id is currently in,
because maybe we will be deleting it.
*/
PF_FACES temp = NULL;
ListHead *pListHead;
int size,y;
pListHead = PolFaces[face_id];
temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
if ( temp == NULL )
{
printf("The face was already deleted, there is an error\n");
exit(0);
}
size = temp->nPolSize;
if (Done(face_id,size,&y) == NULL)
{
printf("There is an error in finding the face\n");
exit(0);
}
return y;
}
int Number_Adj(int id1, int id2, int curr_id)
{
/* Given edge whose endpoints are specified by id1 and id2,
determine how many polygons share this edge and return that
number minus one (since we do not want to include the polygon
that the caller has already).
*/
int size,y,count=0;
PF_EDGES temp = NULL;
PF_FACES temp2 = NULL;
ListHead *pListHead;
BOOL there= FALSE;
/* Always want smaller id first */
switch_lower(&id1,&id2);
pListHead = PolEdges[id1];
temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
if (temp == NULL)
/* new edge that was created might not be here */
return 0;
while (temp->edge[0] != id2)
{
count++;
temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
if (temp == NULL)
/* This edge was not there in the original, which
mean that we created it in the partial triangulation.
So it is adjacent to nothing.
*/
return 0;
}
/* Was not adjacent to anything else except itself */
if (temp->edge[2] == -1)
return 0;
else
{
/* It was adjacent to another polygon, but maybe we did this
polygon already, and it was done partially so that this edge
could have been done
*/
if (curr_id != temp->edge[1])
{
/* Did we use this polygon already?and it was deleted
completely from the structure
*/
pListHead = PolFaces[temp->edge[1]];
temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
if (Done(temp->edge[1],temp2->nPolSize,&size) == NULL)
return 0;
}
else
{
pListHead = PolFaces[temp->edge[2]];
temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
if (Done(temp->edge[2],temp2->nPolSize,&size)== NULL)
return 0;
}
/* Now we have to check whether it was partially done, before
we can say definitely if it is adjacent.
Check each edge of the face and tally the number of adjacent
polygons to this face.
*/
if ( temp2 != NULL )
{
/* Size of the polygon */
size = temp2->nPolSize;
for (y = 0; y< size; y++)
{
/* If we are doing partial triangulation, we must check
to see whether the edge is still there in the polygon,
since we might have done a portion of the polygon
and saved the rest for later.
*/
if (y != (size-1))
{
if( ((id1 == *(temp2->pPolygon+y)) && (id2 ==*(temp2->pPolygon+y+1)))
|| ((id2 == *(temp2->pPolygon+y)) && (id1 ==*(temp2->pPolygon+y+1))))
/* edge is still there we are ok */
there = TRUE;
}
else
{
if( ((id1 == *(temp2->pPolygon)) && (id2 == *(temp2->pPolygon+size-1)))
|| ((id2 == *(temp2->pPolygon)) && (id1 ==*(temp2->pPolygon+size-1))))
/* edge is still there we are ok */
there = TRUE;
}
}
}
if (there )
return 1;
return 0;
}
}
int Min_Adj(int id)
{
/* Used for the lookahead to break ties. It will
return the minimum adjacency found at this face.
*/
int y,numverts,t,x=60;
PF_FACES temp=NULL;
ListHead *pListHead;
/* If polygon was used then we can't use this face */
if (Done(id,59,&y) == NULL)
return 60;
/* It was not used already */
pListHead = PolFaces[id];
temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
if ( temp != NULL )
{
numverts = temp->nPolSize;
for (y = 0; y< numverts; y++)
{
if (y != (numverts-1))
t = Number_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),id);
else
t = Number_Adj(*(temp->pPolygon),*(temp->pPolygon+(numverts-1)),id);
if (t < x)
x = t;
}
}
if (x == -1)
{
printf("Error in the look\n");
exit(0);
}
return x;
}
void Edge_Least(int *index,int *new1,int *new2,int face_id,int size)
{
/* We had a polygon without an input edge and now we re going to pick one
of the edges with the least number of adjacencies to be the input
edge
*/
register int x,value,smallest=60;
for (x = 0; x<size; x++)
{
if (x != (size -1) )
value = Number_Adj(*(index+x),*(index+x+1),face_id);
else
value = Number_Adj(*(index),*(index+size-1),face_id);
if (value < smallest)
{
smallest = value;
if (x != (size -1))
{
*new1 = *(index+x);
*new2 = *(index+x+1);
}
else
{
*new1 = *(index);
*new2 = *(index+size-1);
}
}
}
if ((smallest == 60) || (smallest < 0))
{
printf("There is an error in getting the least edge\n");
exit(0);
}
}
void Check_In_Polygon(int face_id, int *min, int size)
{
/* Check to see the adjacencies by going into a polygon that has
greater than 4 sides.
*/
ListHead *pListHead;
PF_FACES temp;
int y,id1,id2,id3,x=0,z=0;
int saved[2];
int big_saved[60];
pListHead = PolFaces[face_id];
temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
/* Get the input edge that we came in on */
Last_Edge(&id1,&id2,&id3,0);
/* Find the number of adjacencies to the edges that are adjacent
to the input edge.
*/
for (y=0; y< size; y++)
{
if (y != (size-1))
{
if (((*(temp->pPolygon+y) == id2) && (*(temp->pPolygon+y+1) != id3))
|| ((*(temp->pPolygon+y) == id3) && (*(temp->pPolygon+y+1) != id2)))
{
saved[x++] = Number_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),face_id);
big_saved[z++] = saved[x-1];
}
else
big_saved[z++] = Number_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),face_id);
}
else
{
if (((*(temp->pPolygon) == id2) && (*(temp->pPolygon+size-1) != id3))
|| ((*(temp->pPolygon) == id3) && (*(temp->pPolygon+size-1) != id2)))
{
saved[x++] = Number_Adj(*(temp->pPolygon),*(temp->pPolygon+size-1),face_id);
big_saved[z++] = saved[x-1];
}
else
big_saved[z++] = Number_Adj(*(temp->pPolygon),*(temp->pPolygon+size-1),face_id);
}
}
/* There was an input edge */
if (x == 2)
{
if (saved[0] < saved[1])
/* Count the polygon that we will be cutting as another adjacency*/
*min = saved[0] + 1;
else
*min = saved[1] + 1;
}
/* There was not an input edge */
else
{
if (z != size)
{
printf("There is an error with the z %d %d\n",size,z);
exit(0);
}
*min = 60;
for (x = 0; x < size; x++)
{
if (*min > big_saved[x])
*min = big_saved[x];
}
}
}
void New_Face (int face_id, int v1, int v2, int v3)
{
/* We want to change the face that was face_id, we will
change it to a triangle, since the rest of the polygon
was already outputtted
*/
ListHead *pListHead;
PF_FACES temp = NULL;
pListHead = PolFaces[face_id];
temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0);
/* Check each edge of the face and tally the number of adjacent
polygons to this face.
*/
if ( temp != NULL )
{
/* Size of the polygon */
if (temp->nPolSize != 4)
{
printf("There is a miscalculation in the partial\n");
exit (0);
}
temp->nPolSize = 3;
*(temp->pPolygon) = v1;
*(temp->pPolygon+1) = v2;
*(temp->pPolygon+2) = v3;
}
}
void New_Size_Face (int face_id)
{
/* We want to change the face that was face_id, we will
change it to a triangle, since the rest of the polygon
was already outputtted
*/
ListHead *pListHead;
PF_FACES temp = NULL;
pListHead = PolFaces[face_id];
temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
/* Check each edge of the face and tally the number of adjacent
polygons to this face.
*/
if ( temp != NULL )
(temp->nPolSize)--;
else
printf("There is an error in updating the size\n");
}
void Check_In_Quad(int face_id,int *min)
{
/* Check to see what the adjacencies are for the polygons that
are inside the quad, ie the 2 triangles that we can form.
*/
ListHead *pListHead;
int y,id1,id2,id3,x=0;
int saved[4];
PF_FACES temp;
register int size = 4;
pListHead = PolFaces[face_id];
temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
/* Get the input edge that we came in on */
Last_Edge(&id1,&id2,&id3,0);
/* Now find the adjacencies for the inside triangles */
for (y = 0; y< size; y++)
{
/* Will not do this if the edge is the input edge */
if (y != (size-1))
{
if ((((*(temp->pPolygon+y) == id2) && (*(temp->pPolygon+y+1) == id3))) ||
(((*(temp->pPolygon+y) == id3) && (*(temp->pPolygon+y+1) == id2))))
saved[x++] = -1;
else
{
if (x == 4)
{
printf("There is an error in the check in quad \n");
exit(0);
}
/* Save the number of Adjacent Polygons to this edge */
saved[x++] = Number_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1),face_id);
}
}
else if ((((*(temp->pPolygon) == id2) && (*(temp->pPolygon+size-1) == id3))) ||
(((*(temp->pPolygon) == id3) && (*(temp->pPolygon+size-1) == id2))) )
saved[x++] = -1;
else
{
if (x == 4)
{
printf("There is an error in the check in quad \n");
exit(0);
}
/* Save the number of Adjacent Polygons to this edge */
saved[x++] = Number_Adj(*(temp->pPolygon),*(temp->pPolygon+size-1),face_id);
}
}
if (x != 4)
{
printf("Did not enter all the values %d \n",x);
exit(0);
}
*min = 10;
for (x=0; x<4; x++)
{
if (x!= 3)
{
if ((saved[x] != -1) && (saved[x+1] != -1) &&
((saved[x] + saved[x+1]) < *min))
*min = saved[x] + saved[x+1];
}
else
{
if ((saved[0] != -1) && (saved[x] != -1) &&
((saved[x] + saved[0]) < *min))
*min = saved[0] + saved[x];
}
}
}
int Get_Output_Edge(int face_id, int size, int *index,int id2,int id3)
{
/* Return the vertex adjacent to either input1 or input2 that
is adjacent to the least number of polygons on the edge that
is shared with either input1 or input2.
*/
register int x=0,y;
int saved[2];
int edges[2][1];
for (y = 0; y < size; y++)
{
if (y != (size-1))
{
if (((*(index+y) == id2) && (*(index+y+1) != id3))
|| ((*(index+y) == id3) && (*(index+y+1) != id2)))
{
saved[x++] = Number_Adj(*(index+y),*(index+y+1),face_id);
edges[x-1][0] = *(index+y+1);
}
else if (y != 0)
{
if (( (*(index+y) == id2) && (*(index+y-1) != id3) ) ||
( (*(index+y) == id3) && (*(index+y-1) != id2)) )
{
saved[x++] = Number_Adj(*(index+y),*(index+y-1),face_id);
edges[x-1][0] = *(index+y-1);
}
}
else if (y == 0)
{
if (( (*(index) == id2) && (*(index+size-1) != id3) ) ||
( (*(index) == id3) && (*(index+size-1) != id2)) )
{
saved[x++] = Number_Adj(*(index),*(index+size-1),face_id);
edges[x-1][0] = *(index+size-1);
}
}
}
else
{
if (((*(index+size-1) == id2) && (*(index) != id3))
|| ((*(index+size-1) == id3) && (*(index) != id2)))
{
saved[x++] = Number_Adj(*(index),*(index+size-1),face_id);
edges[x-1][0] = *(index);
}
if (( (*(index+size-1) == id2) && (*(index+y-1) != id3) ) ||
( (*(index+size-1) == id3) && (*(index+y-1) != id2)) )
{
saved[x++] = Number_Adj(*(index+size-1),*(index+y-1),face_id);
edges[x-1][0] = *(index+y-1);
}
}
}
if ((x != 2))
{
printf("There is an error in getting the input edge %d \n",x);
exit(0);
}
if (saved[0] < saved[1])
return edges[0][0];
else
return edges[1][0];
}
void Get_Input_Edge(int *index,int id1,int id2,int id3,int *new1,int *new2,int size,
int face_id)
{
/* We had a polygon without an input edge and now we are going to pick one
as the input edge. The last triangle was id1,id2,id3, we will try to
get an edge to have something in common with one of those vertices, otherwise
we will pick the edge with the least number of adjacencies.
*/
register int x;
int saved[3];
saved[0] = -1;
saved[1] = -1;
saved[2] = -1;
/* Go through the edges to see if there is one in common with one
of the vertices of the last triangle that we had, preferably id2 or
id3 since those are the last 2 things in the stack of size 2.
*/
for (x=0; x< size; x++)
{
if (*(index+x) == id1)
{
if (x != (size-1))
saved[0] = *(index+x+1);
else
saved[0] = *(index);
}
if (*(index+x) == id2)
{
if (x != (size-1))
saved[1] = *(index+x+1);
else
saved[1] = *(index);
}
if (*(index+x) == id3)
{
if (x != (size -1))
saved[2] = *(index+x+1);
else
saved[2] = *(index);
}
}
/* Now see what we saved */
if (saved[2] != -1)
{
*new1 = id3;
*new2 = saved[2];
return;
}
else if (saved[1] != -1)
{
*new1 = id2;
*new2 = saved[1];
return;
}
else if (saved[0] != -1)
{
*new1 = id1;
*new2 = saved[0];
return;
}
/* We did not find anything so get the edge with the least number of adjacencies */
Edge_Least(index,new1,new2,face_id,size);
}
int Find_Face(int current_face, int id1, int id2, int *bucket)
{
/* Find the face that is adjacent to the edge and is not the
current face.
*/
register int size,each_poly=0,y,tally=0,count=0;
PF_EDGES temp = NULL;
PF_FACES temp2 = NULL;
ListHead *pListHead;
int next_face;
BOOL there = FALSE;
/* Always want smaller id first */
switch_lower(&id1,&id2);
pListHead = PolEdges[id1];
temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
/* The input edge was a new edge */
if (temp == NULL)
return -1;
while (temp->edge[0] != id2)
{
count++;
temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
/* The input edge was a new edge */
if (temp == NULL)
return -1;
}
/* Was not adjacent to anything else except itself */
if (temp->edge[2] == -1)
return -1;
else
{
if (temp->edge[2] == current_face)
next_face = temp->edge[1];
else
next_face = temp->edge[2];
}
/* We have the other face adjacent to this edge, it is
next_face.
*/
pListHead = PolFaces[next_face];
temp2 = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
/* See if the face was already deleted, and where
it is if it was not
*/
if (Done(next_face,59,bucket) == NULL)
return -1;
/* Make sure the edge is still in this polygon, and that it is not
done
*/
/* Size of the polygon */
size = temp2->nPolSize;
for (y = 0; y< size; y++)
{
/* Make sure that the edge is still in the
polygon and was not deleted, because if the edge was
deleted, then we used it already.
*/
if (y != (size-1))
{
if( ((id1 == *(temp2->pPolygon+y)) && (id2 ==*(temp2->pPolygon+y+1)))
|| ((id2 == *(temp2->pPolygon+y)) && (id1 ==*(temp2->pPolygon+y+1))))
/* edge is still there we are ok */
there = TRUE;
}
else
{
if( ((id1 == *(temp2->pPolygon)) && (id2 ==*(temp2->pPolygon+size-1)))
|| ((id2 == *(temp2->pPolygon)) && (id1 ==*(temp2->pPolygon+size-1))))
/* edge is still there we are ok */
there = TRUE;
}
}
if (!there)
/* Edge already used and deleted from the polygon*/
return -1;
else
return next_face;
}
BOOL Look_Up(int id1,int id2,int face_id)
{
/* See if the endpoints of the edge specified by id1 and id2
are adjacent to the face with face_id
*/
register int count = 0;
PF_EDGES temp = NULL;
ListHead *pListHead;
PF_FACES temp2 = NULL;
/* Always want smaller id first */
switch_lower(&id1,&id2);
pListHead = PolEdges[id1];
temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
if (temp == NULL)
/* Was a new edge that we created */
return 0;
while (temp->edge[0] != id2)
{
count++;
temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
if (temp == NULL)
/* Was a new edge that we created */
return 0;
}
/* Was not adjacent to anything else except itself */
if ((temp->edge[2] == face_id) || (temp->edge[1] == face_id))
{
/* Edge was adjacent to face, make sure that edge is
still there
*/
if (Exist(face_id,id1,id2))
return 1;
else
return 0;
}
else
return 0;
}
void Add_Id_Strips(int id, int where)
{
/* Just save the triangle for later */
P_STRIPS pfNode;
pfNode = (P_STRIPS) malloc(sizeof(Strips) );
if ( pfNode )
{
pfNode->face_id = id;
if (where == 1)
AddTail(strips[0],(PLISTINFO) pfNode);
/* We are backtracking in the strip */
else
AddHead(strips[0],(PLISTINFO) pfNode);
}
else
{
printf("There is not enough memory to allocate for the strips\n");
exit(0);
}
}
int Num_Adj(int id1, int id2)
{
/* Given edge whose endpoints are specified by id1 and id2,
determine how many polygons share this edge and return that
number minus one (since we do not want to include the polygon
that the caller has already).
*/
PF_EDGES temp = NULL;
ListHead *pListHead;
register count=-1;
/* Always want smaller id first */
switch_lower(&id1,&id2);
pListHead = PolEdges[id1];
temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
if (temp == NULL)
{
printf("There is an error in the creation of the table \n");
exit(0);
}
while (temp->edge[0] != id2)
{
count++;
temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count);
if (temp == NULL)
{
printf("There is an error in the creation of the table\n");
exit(0);
}
}
/* Was not adjacent to anything else except itself */
if (temp->edge[2] == -1)
return 0;
return 1;
}
void Add_Sgi_Adj(int bucket,int face_id)
{
/* This routine will add the face to the proper bucket,
depending on how many faces are adjacent to it (what the
value bucket should be).
*/
P_ADJACENCIES pfNode;
pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
if ( pfNode )
{
pfNode->face_id = face_id;
AddHead(array[bucket],(PLISTINFO) pfNode);
}
else
{
printf("Out of memory for the SGI adj list!\n");
exit(0);
}
}
void Find_Adjacencies(int num_faces)
{
register int x,y;
register int numverts;
PF_FACES temp=NULL;
ListHead *pListHead;
/* Fill in the adjacencies data structure for all the faces */
for (x=0;x<num_faces;x++)
{
pListHead = PolFaces[x];
temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
if ( temp != NULL )
{
numverts = temp->nPolSize;
if (numverts != 1)
{
for (y = 0; y< numverts; y++)
{
if (y != (numverts-1))
Add_AdjEdge(*(temp->pPolygon+y),*(temp->pPolygon+y+1),x,y);
else
Add_AdjEdge(*(temp->pPolygon),*(temp->pPolygon+(numverts-1)),x,numverts-1);
}
}
temp = NULL;
}
}
}

41
Tools/Stripe_u/common.h Normal file
View file

@ -0,0 +1,41 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: common.h
-----------------------------------------------------------------------*/
void Add_AdjEdge();
void Find_Adjacencies();
void Add_Sgi_Adj();
int Num_Adj();
void Add_Id_Strips();
BOOL Look_Up();
int Number_Adj();
int Old_Adj();
int Min_Adj();
int Find_Face();
void Edge_Least();
void Get_Input_Edge();
int Get_Output_Edge();
void Check_In_Polygon();
void Check_In_Quad();
void New_Size_Face ();
void New_Face ();

13
Tools/Stripe_u/define.h Normal file
View file

@ -0,0 +1,13 @@
#define VRDATA double
#define MAX1 60
#define TRUE 1
#define FALSE 0
#define PI 3.1415926573
struct vert_struct {
VRDATA x, y, z; /* point coordinates */
};

17
Tools/Stripe_u/extend.h Normal file
View file

@ -0,0 +1,17 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: extend.h
-----------------------------------------------------------------------*/
int Bottom_Left();
int Top_Left();
void Start_Edge();

110
Tools/Stripe_u/free.c Normal file
View file

@ -0,0 +1,110 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: free.c
This file contains the code used to free the data structures.
*/
/*---------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "polverts.h"
void ParseAndFreeList( ListHead *pListHead )
{
PLISTINFO value;
register int c,num;
/* Freeing a linked list */
num = NumOnList(pListHead);
for (c = 0; c< num; c++)
value = RemHead(pListHead);
}
void FreePolygonNode( PF_VERTS pfVerts)
{
/* Free a vertex node */
if ( pfVerts->pPolygon )
free( pfVerts->pPolygon );
free( pfVerts );
}
void Free_Strips()
{
P_STRIPS temp = NULL;
/* Free strips data structure */
if (strips[0] == NULL)
return;
else
ParseAndFreeList(strips[0]);
}
void FreeFaceNode( PF_FACES pfFaces)
{
/* Free face node */
if ( pfFaces->pPolygon )
free( pfFaces->pPolygon );
free( pfFaces );
}
void FreeFaceTable(int nSize)
{
register int nIndex;
for ( nIndex=0; nIndex < nSize; nIndex++ )
{
if ( PolFaces[nIndex] != NULL )
ParseAndFreeList( PolFaces[nIndex] );
}
free( PolFaces );
}
void FreeEdgeTable(int nSize)
{
register int nIndex;
for ( nIndex=0; nIndex < nSize; nIndex++ )
{
if ( PolEdges[nIndex] != NULL )
ParseAndFreeList( PolEdges[nIndex] );
}
free( PolEdges );
}
void Free_All_Strips()
{
ListHead *pListHead;
register int y;
for (y =0; ; y++)
{
pListHead = all_strips[y];
if (pListHead == NULL)
return;
else
ParseAndFreeList(all_strips[y]);
}
}
void End_Face_Struct(int numfaces)
{
FreeFaceTable(numfaces);
}
void End_Edge_Struct(int numverts)
{
FreeEdgeTable(numverts);
}

22
Tools/Stripe_u/free.h Normal file
View file

@ -0,0 +1,22 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: free.h
-----------------------------------------------------------------------*/
void Free_All_Strips();
void ParseAndFreeList();
void FreePolygonNode();
void Free_Strips();
void FreeFaceTable();
void FreeEdgeTable();
void End_Face_Struct();
void End_Edge_Struct();

37
Tools/Stripe_u/global.h Normal file
View file

@ -0,0 +1,37 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: global.h
-----------------------------------------------------------------------*/
#define VRDATA double
#define MAX1 60
#define TRUE 1
#define FALSE 0
#ifndef PI
# define PI 3.1415926573
#endif /* PI */
#define ATOI(C) (C -'0')
#define X 0
#define Y 1
#define Z 2
#define EVEN(x) (((x) & 1) == 0)
#define MAX_BAND 10000
struct vert_struct {
VRDATA x, y, z; /* point coordinates */
};
int ids[MAX1];
int norms[MAX1];
int *vert_norms;
int *vert_texture;

151
Tools/Stripe_u/glove.h Normal file
View file

@ -0,0 +1,151 @@
/*
* dg2lib.h - header file for the DG2 library libdg2.a
*
* copyright 1988-92 VPL Research Inc.
*
*/
/******** error returns from the library */
extern int DG2_error; /* for error information */
extern float DG2_lib_version; /* for the library version */
extern int DG2_box_version; /* for the firmware version */
extern int DG2_glove_sensors; /* for the number of sensors in the glove */
/* defines for DG2_error values */
#define DG2_AOK 0
#define DG2_SETTINGS_FILE -1
#define DG2_SERIAL_OPEN -2
#define DG2_SERIAL_PORT -4
#define DG2_RESET -6
#define DG2_PARAMETER -7
#define DG2_FILE_IO -8
#define DG2_CALIBRATION_FILE -9
#define DG2_GESTURE_FILE -10
#define DG2_CAL_GEST_FILES -11
/* defines for DG2_response() */
#define DATAGLOVE 1
#define POLHEMUS 2
#define GESTURE 8
#define DG2_60Hz 1
#define DG2_30Hz 2
#define DG2_oneShot 3
/* defines for DG2_DataGlove_select() */
#define THUMB_INNER 0x1
#define THUMB_OUTER 0x2
#define INDEX_INNER 0x4
#define INDEX_OUTER 0x8
#define MIDDLE_INNER 0x10
#define MIDDLE_OUTER 0x20
#define RING_INNER 0x40
#define RING_OUTER 0x80
#define LITTLE_INNER 0x100
#define LITTLE_OUTER 0x200
#define NORMAL_JOINTS 0x3ff
#define FLEX11 0x400
#define FLEX12 0x800
#define FLEX13 0x1000
#define FLEX14 0x2000
#define FLEX15 0x4000
#define FLEX16 0x8000
/* defines for DG2_DataGlove_trans_select() */
#define DG2_TRANSLATED 5
#define DG2_RAW 6
/* defines for DG2_Polhemus_units() */
#define POL_RAW 0
#define POL_INCHES 1
#define POL_CM 2
/* defines for DG2_user_IRQ() */
#define IRQ_ON 1
#define IRQ_OFF 2
/* defines for DG2_get_data() */
#define DG2_report 1
#define DG2_userport 2
/* dg2 command codes*/
#define LEADINGBYTE 0x24
#define RPT60 0x41 /* repeat 60 */
#define RPT30 0x42 /* repeat 30 */
#define ONESHOT 0x43 /* one shot */
#define SYSID 0x44 /* system ID */
#define EPTBUF 0x45 /* empty buffer */
#define USRRD 0x46 /* user read */
#define USRIRQ 0x47 /* user IRQ */
#define QBRT 0x48 /* query bright */
#define CDRST 0x49 /* cold reset */
#define WMRST 0x4A /* warm reset */
#define MEMALLO 0x4B /* memory alloc */
#define DLTSND 0x4C /* delta send */
#define SETBRT 0x4D /* set bright */
#define SETDIM 0x4E /* set dim */
#define FILBUF 0x4F /* fill buffer */
#define LDTBL 0x50 /* load table */
#define LDPOL 0x51 /* send up to 63 bytes to Polhemus */
#define ANGLE 0x52 /* angles */
#define NSNSR 0x53 /* num sensors */
#define SETFB 0x54 /* set feedback */
#define QCUT 0X55 /* query cutoff*/
#define SETCUT 0X56 /* set cutoff */
#define FLXVAL 0X57 /* raw flex values */
#define USRWR 0X58 /* user write */
#define JNTMAP 0X59 /* joint map */
#define ERRMESS 0XFF /* error in command input */
#define TIMOUT 0XFE /* timed out during command */
/* response structure */
typedef struct DG2_data {
char gesture;
double location[3]; /* X,Y,Z */
double orientation[3]; /* yaw, pitch, roll */
short flex[16];
char gesture_name[20];
short reserved[16];
/* user port data: */
char user_nibble;
char user_analog[3];
} DG2_data;
/**************function prototypes*************/
/*NOTE: all DG2_ functions return -1 on error*/
extern int DG2_open(char *portname, int baud);
extern int DG2_close(int filedes);
extern int DG2_direct(int filedes,char *message,int count);
extern int DG2_response(int filedes,int devices,int rate);
extern int DG2_DataGlove_select(int filedes,int flex_sensors);
extern int DG2_DataGlove_translation(int filedes,int flex_sensors,char table[16][256]);
extern int DG2_DataGlove_trans_select(int filedes,int status);
extern int DG2_DataGlove_LED_set(int filedes,int LED);
extern int DG2_DataGlove_LED_read(int filedes);
extern int DG2_Polhemus_units(int filedes,char type);
extern int DG2_Polhemus_direct(int filedes,char *message,int count);
extern int DG2_user_write(int filedes,int nibble);
extern int DG2_user_IRQ(int filedes,int mode);
extern int DG2_user_read(int filedes,DG2_data *data);
extern int DG2_get_data(int filedes,DG2_data *data);
extern int DG2_gesture_load(int filedes,char *calib,char *gest);
/*use this with caution since it does not return until it gets a correct
*response from the DG2
*/
extern int DG2U_get_reply(int filedes,char *buff,int response,int size);

217
Tools/Stripe_u/init.c Normal file
View file

@ -0,0 +1,217 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: init.c
This file contains the initialization of data structures.
*/
/*---------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "global.h"
#include "polverts.h"
void init_vert_norms(int num_vert)
{
/* Initialize vertex/normal array to have all zeros to
start with.
*/
register int x;
for (x = 0; x < num_vert; x++)
*(vert_norms + x) = 0;
}
void init_vert_texture(int num_vert)
{
/* Initialize vertex/normal array to have all zeros to
start with.
*/
register int x;
for (x = 0; x < num_vert; x++)
*(vert_texture + x) = 0;
}
BOOL InitVertTable( int nSize )
{
register int nIndex;
/* Initialize the vertex table */
PolVerts = (ListHead**) malloc(sizeof(ListHead*) * nSize );
if ( PolVerts )
{
for ( nIndex=0; nIndex < nSize; nIndex++ )
{
PolVerts[nIndex] = NULL;
}
return( TRUE );
}
return( FALSE );
}
BOOL InitFaceTable( int nSize )
{
register int nIndex;
/* Initialize the face table */
PolFaces = (ListHead**) malloc(sizeof(ListHead*) * nSize );
if ( PolFaces )
{
for ( nIndex=0; nIndex < nSize; nIndex++ )
{
PolFaces[nIndex] = NULL;
}
return( TRUE );
}
return( FALSE );
}
BOOL InitEdgeTable( int nSize )
{
register int nIndex;
/* Initialize the edge table */
PolEdges = (ListHead**) malloc(sizeof(ListHead*) * nSize );
if ( PolEdges )
{
for ( nIndex=0; nIndex < nSize; nIndex++ )
{
PolEdges[nIndex] = NULL;
}
return( TRUE );
}
return( FALSE );
}
void InitStripTable( )
{
PLISTHEAD pListHead;
/* Initialize the strip table */
pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
if ( pListHead )
{
InitList( pListHead );
strips[0] = pListHead;
}
else
{
printf("Out of memory !\n");
exit(0);
}
}
void Init_Table_SGI()
{
PLISTHEAD pListHead;
int max_adj = 60;
register int x;
/* This routine will initialize the table that will
have the faces sorted by the number of adjacent polygons
to it.
*/
for (x=0; x< max_adj; x++)
{
/* We are allowing the max number of sides of a polygon
to be max_adj.
*/
pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
if ( pListHead )
{
InitList( pListHead );
array[x] = pListHead;
}
else
{
printf("Out of memory !\n");
exit(0);
}
}
}
void BuildVertTable( int nSize )
{
register int nIndex;
PLISTHEAD pListHead;
for ( nIndex=0; nIndex < nSize; nIndex++ )
{
pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
if ( pListHead )
{
InitList( pListHead );
PolVerts[nIndex] = pListHead;
}
else
return;
}
}
void BuildFaceTable( int nSize )
{
register int nIndex;
PLISTHEAD pListHead;
for ( nIndex=0; nIndex < nSize; nIndex++ )
{
pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
if ( pListHead )
{
InitList( pListHead );
PolFaces[nIndex] = pListHead;
}
else
return;
}
}
void BuildEdgeTable( int nSize )
{
register int nIndex;
PLISTHEAD pListHead;
for ( nIndex=0; nIndex < nSize; nIndex++ )
{
pListHead = ( PLISTHEAD ) malloc(sizeof(ListHead));
if ( pListHead )
{
InitList( pListHead );
PolEdges[nIndex] = pListHead;
}
else
return;
}
}
void Start_Face_Struct(int numfaces)
{
if (InitFaceTable(numfaces))
{
BuildFaceTable(numfaces);
}
}
void Start_Edge_Struct(int numverts)
{
if (InitEdgeTable(numverts))
{
BuildEdgeTable(numverts);
}
}

30
Tools/Stripe_u/init.h Normal file
View file

@ -0,0 +1,30 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: init.h
-----------------------------------------------------------------------*/
void init_vert_norms();
void init_vert_texture();
BOOL InitVertTable();
BOOL InitFaceTable();
BOOL InitEdgeTable();
void InitStripTable();
void Init_Table_SGI();
void BuildVertTable();
void BuildFaceTable();
void BuildEdgeTable();
void Start_Face_Struct();
void Start_Edge_Struct();

123
Tools/Stripe_u/local.c Normal file
View file

@ -0,0 +1,123 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: local.c
This file contains the code that initializes the data structures for
the local algorithm, and starts the local algorithm going.
*/
/*---------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "polverts.h"
#include "local.h"
#include "triangulatex.h"
#include "sturctsex.h"
#include "common.h"
#include "outputex.h"
#include "util.h"
#include "init.h"
void Find_StripsEx(FILE *output,FILE *strip,int *ties,
int tie, int triangulate,
int swaps,int *next_id)
{
/* This routine will peel off the strips from the model */
ListHead *pListHead;
P_ADJACENCIES temp = NULL;
register int max,bucket=0;
BOOL whole_flag = TRUE;
int dummy = 0;
/* Set the last known input edge to be null */
Last_Edge(&dummy,&dummy,&dummy,1);
/* Search for lowest adjacency polygon and output strips */
while (whole_flag)
{
bucket = -1;
/* Search for polygons in increasing number of adjacencies */
while (bucket < 59)
{
bucket++;
pListHead = array[bucket];
max = NumOnList(pListHead);
if (max > 0)
{
temp = (P_ADJACENCIES) PeekList(pListHead,LISTHEAD,0);
if (temp == NULL)
{
printf("Error in the buckets%d %d %d\n",bucket,max,0);
exit(0);
}
Polygon_OutputEx(temp,temp->face_id,bucket,pListHead,
output,strip,ties,tie,triangulate,swaps,next_id,1);
/* Try to extend backwards, if the starting polygon in the
strip had 2 or more adjacencies to begin with
*/
if (bucket >= 2)
Extend_BackwardsEx(temp->face_id,output,strip,ties,tie,triangulate,
swaps,next_id);
break;
}
}
/* Went through the whole structure, it is empty and we are done.
*/
if ((bucket == 59) && (max == 0))
whole_flag = FALSE;
/* We just finished a strip, send dummy data to signal the end
of the strip so that we can output it.
*/
else
{
Output_TriEx(-1,-2,-3,output,-1,-10,1);
Last_Edge(&dummy,&dummy,&dummy,1);
}
}
}
void SGI_Strip(int num_verts,int num_faces,FILE *output,
int ties,int triangulate)
{
FILE *strip;
int next_id = -1,t=0;
strip = fopen("output.d","w");
/* We are going to output and find triangle strips
according the the method that SGI uses, ie always
choosing as the next triangle in our strip the triangle
that has the least number of adjacencies. We do not have
all triangles and will be triangulating on the fly those
polygons that have more than 3 sides.
*/
/* Build a table that has all the polygons sorted by the number
of polygons adjacent to it.
*/
/* Initialize it */
Init_Table_SGI();
/* Build it */
Build_SGI_Table(num_verts,num_faces);
/* We will have a structure to hold all the strips, until
outputted.
*/
InitStripTable();
/* Now we have the structure built to find the polygons according
to the number of adjacencies. Now use the SGI Method to find
strips according to the adjacencies
*/
Find_StripsEx(output,strip,&t,ties,triangulate,ON,&next_id);
}

19
Tools/Stripe_u/local.h Normal file
View file

@ -0,0 +1,19 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE:local.h
-----------------------------------------------------------------------*/
void Local_Polygon_Output();
void Local_Output_Tri();
int Different();
void Local_Non_Blind_Triangulate();
void Local_Blind_Triangulate();
void Local_Triangulate_Polygon();
void SGI_Strip();

View file

@ -0,0 +1,3 @@
int change_in_stripEx = 0;
int change_in_strip = 0;

1667
Tools/Stripe_u/newpolve.c Normal file

File diff suppressed because it is too large Load diff

181
Tools/Stripe_u/options.c Normal file
View file

@ -0,0 +1,181 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: options.c
This file contains routines that are used to determine the options
that were specified by the user
*/
/*---------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "options.h"
#include "global.h"
int power_10(int power)
{
/* Raise 10 to the power */
register int i,p;
p = 1;
for (i = 1; i <= power; ++i)
p = p * 10;
return p;
}
float power_negative(int power)
{
/* Raise 10 to the negative power */
register int i;
float p;
p = (float)1;
for (i = 1; i<=power; i++)
p = p * (float).1;
return p;
}
float convert_array(int num[],int stack_size)
{
/* Convert an array of characters to an integer */
register int counter,c;
float temp =(float)0.0;
for (c=(stack_size-1), counter = 0; c>=0; c--, counter++)
{
if (num[c] == -1)
/* We are at the decimal point, convert to decimal
less than 1
*/
{
counter = -1;
temp = power_negative(stack_size - c - 1) * temp;
}
else
temp += power_10(counter) * num[c];
}
return(temp);
}
float get_options(int argc, char **argv, int *f, int *t, int *tr, int *group)
{
char c;
int count = 0;
int buffer[MAX1];
int next = 0;
/* tie variable */
enum tie_options tie = FIRST;
/* triangulation variable */
enum triangulation_options triangulate = WHOLE;
/* normal difference variable (in degrees) */
float norm_difference = (float)360.0;
/* file-type variable */
enum file_options file_type = ASCII;
/* User has the wrong number of options */
if ((argc > 5) || (argc < 2))
{
printf("Usage: bands -[file_option][ties_option][triangulation_option][normal_difference] file_name\n");
exit(0);
}
/* Interpret the options specified */
while (--argc > 0 && (*++argv)[0] == '-')
{
/* At the next option that was specified */
next = 1;
while (c = *++argv[0])
switch (c)
{
case 'f':
/* Use the first polygon we see. */
tie = FIRST;
break;
case 'r':
/* Randomly choose the next polygon */
tie = RANDOM;
break;
case 'a':
/* Alternate direction in choosing the next polygon */
tie = ALTERNATE;
break;
case 'l':
/* Use lookahead to choose the next polygon */
tie = LOOK;
break;
case 'q':
/* Try to reduce swaps */
tie = SEQUENTIAL;
break;
case 'p':
/* Use partial triangulation of polygons */
triangulate = PARTIAL;
break;
case 'w':
/* Use whole triangulation of polygons */
triangulate = WHOLE;
break;
case 'b':
/* Input file is in binary */
file_type = BINARY;
break;
case 'g':
/* Strips will be grouped according to the groups in
the data file. We will have to restrict strips to be
in the grouping of the data file.
*/
*group = 1;
/* Get each the value of the integer */
/* We have an integer */
default:
if ((c >= '0') && (c <= '9'))
{
/* More than one normal difference specified, use the last one */
if (next == 1)
{
count = 0;
next = 0;
}
buffer[count++] = ATOI(c);
}
/* At the decimal point */
else if (c == '.')
{
/* More than one normal difference specified, use the last one */
if (next == 1)
{
count = 0;
next = 0;
}
buffer[count++] = -1;
}
else
break;
}
}
/* Convert the buffer of characters to a floating pt integer */
if (count != 0)
norm_difference = convert_array(buffer,count);
*f = file_type;
*t = tie;
*tr = triangulate;
return norm_difference;
}

17
Tools/Stripe_u/options.h Normal file
View file

@ -0,0 +1,17 @@
/********************************************************************/
/* STRIPE: converting a polygonal model to triangle strips
Francine Evans, 1996.
SUNY @ Stony Brook
Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/
/*---------------------------------------------------------------------*/
/* STRIPE: options.h
-----------------------------------------------------------------------*/
float get_options();
enum file_options {ASCII,BINARY};
enum tie_options {FIRST, RANDOM, ALTERNATE, LOOK, SEQUENTIAL};
enum triangulation_options {PARTIAL,WHOLE};

Some files were not shown because too many files have changed in this diff Show more