]> git.mxchange.org Git - flightgear.git/blobdiff - DEM/dem.cxx
Minor tweaks related to FGBucket usage.
[flightgear.git] / DEM / dem.cxx
index 3a20abea9a4641e009001cbd8dc3d924a96c0f8d..e4661a3c70b7896816700732797e08c243a752da 100644 (file)
@@ -1,10 +1,8 @@
-// -*- Mode: C++ -*-
-//
-// dem.c -- DEM management class
+// dem.cxx -- DEM management class
 //
 // Written by Curtis Olson, started March 1998.
 //
-// Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
+// 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
 #  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>
-#include <sys/stat.h> // stat()
-#include <errno.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 <string>
 
-// #include <zlib/zlib.h>
 #include <Misc/fgstream.hxx>
 #include <Misc/strutils.hxx>
-#include <Include/compiler.h>
-FG_USING_NAMESPACE(std);
+#include <Include/fg_constants.h>
 
 #include "dem.hxx"
-#include "leastsqs.hxx"
-
-#include <Include/fg_constants.h>
 
 
 #define MAX_EX_NODES 10000
 
+#if 0
 #ifdef WIN32
 # ifdef __BORLANDC__
 #  include <dir.h>
@@ -62,62 +66,28 @@ FG_USING_NAMESPACE(std);
 #  define MKDIR(a) mkdir(a,S_IRWXU)  // I am just guessing at this flag (NHV)
 # endif // __BORLANDC__
 #endif // WIN32
+#endif //0
 
 
-fgDEM::fgDEM( void ) {
-    // printf("class fgDEM CONstructor called.\n");
+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];
 }
 
 
-#ifdef WIN32
-
-// return the file path name ( foo/bar/file.ext = foo/bar )
-static void extract_path ( const 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';
-}
-
-
-// Make a subdirectory
-static int my_mkdir (const char *dir) {
-    struct stat stat_buf;
-    int result;
-
-    printf ("mk_dir() ");
-
-    result = stat (dir, &stat_buf);
-
-    if (result != 0) {
-       MKDIR (dir);
-       result = stat (dir, &stat_buf);
-       if (result != 0) {
-           printf ("problem creating %s\n", dir);
-       } else {
-           printf ("%s created\n", dir);
-       }
-    } else {
-       printf ("%s already exists\n", dir);
-    }
+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];
 
-    return (result);
+    FGDem::open(file);
 }
 
-#endif // WIN32
-
 
 // open a DEM file
-int fgDEM::open ( const string& file ) {
+int
+FGDem::open ( const string& file ) {
     // open input file (or read from stdin)
     if ( file ==  "-" ) {
        printf("Loading DEM data file: stdin\n");
@@ -139,7 +109,8 @@ int fgDEM::open ( const string& file ) {
 
 
 // close a DEM file
-int fgDEM::close () {
+int
+FGDem::close () {
     // the fg_gzifstream doesn't seem to have a close()
 
     delete in;
@@ -149,10 +120,11 @@ int fgDEM::close () {
 
 
 // return next token from input stream
-string fgDEM::next_token() {
+string
+FGDem::next_token() {
     string token;
 
-    in->stream() >> token;
+    *in >> token;
 
     // cout << "    returning " + token + "\n";
 
@@ -161,35 +133,34 @@ string fgDEM::next_token() {
 
 
 // return next integer from input stream
-int fgDEM::next_int() {
+int
+FGDem::next_int() {
     int result;
-
-    in->stream() >> result;
+    
+    *in >> result;
 
     return result;
 }
 
 
 // return next double from input stream
-double fgDEM::next_double() {
+double
+FGDem::next_double() {
     double result;
 
-    in->stream() >> result;
+    *in >> result;
 
     return result;
 }
 
 
 // return next exponential num from input stream
-double fgDEM::next_exp() {
+double
+FGDem::next_exp() {
     string token;
-    double mantissa;
-    int exp, acc;
-    int i;
 
     token = next_token();
 
-#if 1
     const char* p = token.c_str();
     char buf[64];
     char* bp = buf;
@@ -203,34 +174,16 @@ double fgDEM::next_exp() {
     }
     *bp = 0;
     return ::atof( buf );
-#else
-    sscanf(token.c_str(), "%lfD%d", &mantissa, &exp);
-
-    // cout << "    Mantissa = " << mantissa << "  Exp = " << exp << "\n";
-
-    acc = 1;
-    if ( exp > 0 ) {
-       for ( i = 1; i <= exp; i++ ) {
-           acc *= 10;
-       }
-    } else if ( exp < 0 ) {
-       for ( i = -1; i >= exp; i-- ) {
-           acc /= 10;
-       }
-    }
-
-    return( (int)rint(mantissa * (double)acc) );
-#endif
 }
 
 
 // read and parse DEM "A" record
-int fgDEM::read_a_record() {
+int
+FGDem::read_a_record() {
     int i, inum;
     double dnum;
     string name, token;
     char c;
-    char *ptr;
 
     // get the name field (144 characters)
     for ( i = 0; i < 144; i++ ) {
@@ -330,32 +283,10 @@ int fgDEM::read_a_record() {
     i = token.length();
     cout << "    length = " << i << "\n";
 
-#if 1
     inum = atoi( token.substr( 0, i - 36 ) );
-    row_step = atof( token.substr( i - 36, 12 ) );
-    col_step = atof( token.substr( i - 24, 12 ) );
-    //token.substr( 25, 12 )
-#else
-    ptr = token.c_str() + i - 12;
-    cout << "    last field = " << ptr << " = " << atof(ptr) << "\n";
-    ptr[0] = '\0';
-
-    ptr = ptr - 12;
-    col_step = atof(ptr);
-    cout << "    last field = " << ptr << " = " << col_step << "\n";
-    ptr[0] = '\0';
-
-    ptr = ptr - 12;
-    row_step = atof(ptr);
-    cout << "    last field = " << ptr << " = " << row_step << "\n";
-    ptr[0] = '\0';
-
-    // accuracy code = atod(token)
-    ptr = ptr - 12;
-    inum = atoi(ptr);
-#endif
+    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";
 
@@ -371,7 +302,8 @@ int fgDEM::read_a_record() {
 
 
 // read and parse DEM "B" record
-void fgDEM::read_b_record( ) {
+void
+FGDem::read_b_record( ) {
     string token;
     int i;
 
@@ -408,7 +340,8 @@ void fgDEM::read_b_record( ) {
 
 
 // parse dem file
-int fgDEM::parse( ) {
+int
+FGDem::parse( ) {
     int i;
 
     cur_col = 0;
@@ -433,9 +366,85 @@ int fgDEM::parse( ) {
 }
 
 
-// return the current altitude based on mesh data.  We should rewrite
+// 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 ) {
+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;
@@ -548,7 +557,7 @@ double fgDEM::interpolate_altitude( double lon, double lat ) {
 
 
 // Use least squares to fit a simpler data set to dem data
-void fgDEM::fit( double error, fgBUCKET *p ) {
+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;
@@ -561,9 +570,9 @@ void fgDEM::fit( double error, fgBUCKET *p ) {
     outputmesh_init();
 
     // determine dimensions
-    colmin = p->x * ( (cols - 1) / 8);
+    colmin = p.get_x() * ( (cols - 1) / 8);
     colmax = colmin + ( (cols - 1) / 8);
-    rowmin = p->y * ( (rows - 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);
     
@@ -684,7 +693,7 @@ void fgDEM::fit( double error, fgBUCKET *p ) {
 
 
 // Initialize output mesh structure
-void fgDEM::outputmesh_init( void ) {
+void FGDem::outputmesh_init( void ) {
     int i, j;
     
     for ( j = 0; j < DEM_SIZE_1; j++ ) {
@@ -696,13 +705,13 @@ void fgDEM::outputmesh_init( void ) {
 
 
 // Get the value of a mesh node
-double fgDEM::outputmesh_get_pt( int i, int j ) {
+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 ) {
+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;
 }
@@ -712,11 +721,12 @@ void fgDEM::outputmesh_set_pt( int i, int j, double value ) {
 // 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 ) {
+void FGDem::outputmesh_output_nodes( const string& fg_root, FGBucket& p )
+{
     double exnodes[MAX_EX_NODES][3];
     struct stat stat_buf;
     string dir;
-    char base_path[256], file[256], exfile[256];
+    char file[256], exfile[256];
 #ifdef WIN32
     char tmp_path[256];
 #endif
@@ -727,15 +737,15 @@ void fgDEM::outputmesh_output_nodes( const string& fg_root, fgBUCKET *p ) {
     int i, j, count, excount, result;
 
     // determine dimensions
-    colmin = p->x * ( (cols - 1) / 8);
+    colmin = p.get_x() * ( (cols - 1) / 8);
     colmax = colmin + ( (cols - 1) / 8);
-    rowmin = p->y * ( (rows - 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
-    fgBucketGenBasePath(p, base_path);
+    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;
@@ -746,12 +756,13 @@ void fgDEM::outputmesh_output_nodes( const string& fg_root, fgBUCKET *p ) {
     if ( result != 0 && errno == ENOENT ) {
        cout << "Creating directory\n";
 
-#ifndef WIN32
+// #ifndef WIN32
 
        command = "mkdir -p " + dir + "\n";
        system( command.c_str() );
 
-#else // WIN32
+#if 0
+// #else // WIN32
 
        // Cygwin crashes when trying to output to node file
        // explicitly making directory structure seems OK on Win95
@@ -767,14 +778,15 @@ void fgDEM::outputmesh_output_nodes( const string& fg_root, fgBUCKET *p ) {
        dir = fg_root + "/Scenery/" + base_path;
        if (my_mkdir ( dir.c_str() )) { exit (-1); }
 
-#endif // WIN32
+// #endif // WIN32
+#endif //0
 
     } else {
        // assume directory exists
     }
 
     // get index and generate output file name
-    index = fgBucketGenIndex(p);
+    index = p.gen_index();
     sprintf(file, "%s/%ld.node", dir.c_str(), index);
 
     // get (optional) extra node file name (in case there is matching
@@ -842,16 +854,45 @@ void fgDEM::outputmesh_output_nodes( const string& fg_root, fgBUCKET *p ) {
 
     fclose(fd);
 }
+#endif
 
 
-fgDEM::~fgDEM( void ) {
-    // printf("class fgDEM DEstructor called.\n");
+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