1999-02-15 19:10:23 +00:00
|
|
|
// 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 <gfc/gadt_polygon.h>
|
|
|
|
#include <gfc/gdbf.h>
|
|
|
|
#include <gfc/gshapefile.h>
|
1999-02-19 19:05:17 +00:00
|
|
|
#undef E
|
|
|
|
#undef DEG_TO_RAD
|
|
|
|
#undef RAD_TO_DEG
|
1999-02-15 19:10:23 +00:00
|
|
|
|
1999-02-19 19:05:17 +00:00
|
|
|
// include Generic Polygon Clipping Library
|
1999-02-15 19:10:23 +00:00
|
|
|
extern "C" {
|
|
|
|
#include <gpc.h>
|
|
|
|
}
|
|
|
|
|
1999-02-23 01:29:03 +00:00
|
|
|
#include <Include/compiler.h>
|
1999-02-15 19:10:23 +00:00
|
|
|
|
1999-02-23 01:29:03 +00:00
|
|
|
#include STL_STRING
|
1999-02-15 19:10:23 +00:00
|
|
|
|
1999-02-23 01:29:03 +00:00
|
|
|
#include <Debug/logstream.hxx>
|
1999-02-19 19:05:17 +00:00
|
|
|
|
1999-02-25 21:31:04 +00:00
|
|
|
#include <Polygon/index.hxx>
|
|
|
|
#include <Polygon/names.hxx>
|
1999-02-23 01:29:03 +00:00
|
|
|
#include "shape.hxx"
|
1999-02-19 19:05:17 +00:00
|
|
|
|
|
|
|
|
1999-03-22 23:49:29 +00:00
|
|
|
// 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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-02-15 19:10:23 +00:00
|
|
|
int main( int argc, char **argv ) {
|
1999-02-23 01:29:03 +00:00
|
|
|
gpc_polygon gpc_shape;
|
|
|
|
int i, j;
|
1999-02-19 19:05:17 +00:00
|
|
|
|
1999-02-15 19:10:23 +00:00
|
|
|
fglog().setLogLevels( FG_ALL, FG_DEBUG );
|
|
|
|
|
1999-05-12 01:12:47 +00:00
|
|
|
if ( argc < 3 ) {
|
1999-02-23 01:29:03 +00:00
|
|
|
FG_LOG( FG_GENERAL, FG_ALERT, "Usage: " << argv[0]
|
1999-05-12 01:12:47 +00:00
|
|
|
<< " <shape_file> <work_dir> [ area_string ]" );
|
1999-02-15 19:10:23 +00:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
FG_LOG( FG_GENERAL, FG_DEBUG, "Opening " << argv[1] << " for reading." );
|
|
|
|
|
1999-03-02 01:04:28 +00:00
|
|
|
// make work directory
|
|
|
|
string work_dir = argv[2];
|
|
|
|
string command = "mkdir -p " + work_dir;
|
|
|
|
system( command.c_str() );
|
|
|
|
|
1999-05-12 01:12:47 +00:00
|
|
|
// 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];
|
|
|
|
}
|
|
|
|
|
1999-02-25 21:31:04 +00:00
|
|
|
// initialize persistant polygon counter
|
1999-03-17 23:51:25 +00:00
|
|
|
string counter_file = work_dir + "/../work.counter";
|
1999-02-25 21:31:04 +00:00
|
|
|
poly_index_init( counter_file );
|
|
|
|
|
1999-02-23 01:29:03 +00:00
|
|
|
// initialize structure for building gpc polygons
|
|
|
|
shape_utils_init();
|
|
|
|
|
1999-02-15 19:10:23 +00:00
|
|
|
GShapeFile * sf = new GShapeFile( argv[1] );
|
1999-02-23 01:29:03 +00:00
|
|
|
GDBFile *dbf = new GDBFile( argv[1] );
|
|
|
|
string path = argv[2];
|
1999-02-15 19:10:23 +00:00
|
|
|
|
|
|
|
GPolygon shape;
|
|
|
|
double *coords; // in decimal degrees
|
|
|
|
int n_vertices;
|
|
|
|
|
1999-02-23 01:29:03 +00:00
|
|
|
FG_LOG( FG_GENERAL, FG_INFO, "shape file records = " << sf->numRecords() );
|
1999-02-15 19:10:23 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
1999-02-25 21:31:04 +00:00
|
|
|
for ( i = 0; i < sf->numRecords(); i++ ) {
|
1999-02-15 19:10:23 +00:00
|
|
|
//fetch i-th record (shape)
|
|
|
|
sf->getShapeRec(i, &shape);
|
|
|
|
FG_LOG( FG_GENERAL, FG_DEBUG, "Record = " << i << " rings = "
|
|
|
|
<< shape.numRings() );
|
|
|
|
|
1999-05-12 01:12:47 +00:00
|
|
|
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 << ")" );
|
|
|
|
}
|
1999-02-23 01:29:03 +00:00
|
|
|
|
|
|
|
FG_LOG( FG_GENERAL, FG_INFO, " record = " << i
|
|
|
|
<< " ring = " << 0 );
|
|
|
|
|
1999-05-12 01:12:47 +00:00
|
|
|
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 ) {
|
1999-02-23 01:29:03 +00:00
|
|
|
// 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);
|
1999-02-19 19:05:17 +00:00
|
|
|
}
|
1999-02-23 01:29:03 +00:00
|
|
|
|
|
|
|
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);
|
1999-02-19 19:05:17 +00:00
|
|
|
}
|
1999-02-23 01:29:03 +00:00
|
|
|
// process_shape(path, area, &gpc_shape);
|
|
|
|
free_shape(&gpc_shape);
|
|
|
|
} else if ( area == NullArea ) {
|
|
|
|
// interior is ????
|
1999-02-19 19:05:17 +00:00
|
|
|
|
1999-02-23 01:29:03 +00:00
|
|
|
// 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);
|
1999-02-15 19:10:23 +00:00
|
|
|
}
|
1999-02-23 01:29:03 +00:00
|
|
|
|
|
|
|
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);
|
1999-02-15 19:10:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1999-02-23 01:29:03 +00:00
|
|
|
|