// 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$ // Include Geographic Foundation Classes library // libgfc.a includes need this bit o' strangeness #if defined ( linux ) # define _LINUX_ #endif #include #include #include #undef E #undef DEG_TO_RAD #undef RAD_TO_DEG // include Generic Polygon Clipping Library extern "C" { #include } #include #include STL_STRING #include #include #include #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] << " [ area_string ]" ); 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() ); // allow us to override the area type from the command line. All // polygons in the processed shape file will be assigned this area // type string force_area_type = ""; if ( argc == 4 ) { force_area_type = argv[3]; } // 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; if ( force_area_type.length() == 0 ) { 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 ( force_area_type.length() > 0 ) { // interior of polygon is assigned to force_area_type, // holes are maintained area = get_area_type( force_area_type ); 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 == 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; }