diff --git a/configure.ac b/configure.ac index f103d0ca..9890e9be 100644 --- a/configure.ac +++ b/configure.ac @@ -110,6 +110,10 @@ AC_ARG_ENABLE(ogrdecode, AC_HELP_STRING([--disable-ogrdecode], [enable ogrdecode tool (default depending on OGR availability)])) +AC_ARG_ENABLE(poly2ogr, + AC_HELP_STRING([--disable-poly2ogr], + [enable poly2ogr tool (default depending on OGR availability)])) + if test "$with_gdal" != "no" ; then if test "`basename xx/$with_gdal`" = "gdal-config" ; then # gdal-config was specified @@ -159,7 +163,15 @@ if test x$have_ogr != xyes -a x$enable_ogrdecode = xyes; then using --with-gdal.]) fi +if test x$have_ogr != xyes -a x$enable_poly2ogr = xyes; then + AC_MSG_ERROR([poly2ogr was forcefully enabled but OGR was not found. + Please make sure that you have GDAL installed with OGR enabled + and gdal-config in your PATH resp. the path to gdal-config provided + using --with-gdal.]) +fi + AM_CONDITIONAL(WANT_OGRDECODE, test x$have_ogr = xyes -a x$enable_ogrdecode != xno) +AM_CONDITIONAL(WANT_POLY2OGR, test x$have_ogr = xyes -a x$enable_poly2ogr != xno) dnl Check for MS Windows environment AC_CHECK_HEADER(windows.h) @@ -486,6 +498,7 @@ AC_CONFIG_FILES([ \ src/Utils/Makefile \ src/Utils/cdrom/Makefile \ src/Utils/download-map/Makefile \ + src/Utils/poly2ogr/Makefile \ ]) AC_OUTPUT diff --git a/src/Lib/Polygon/polygon.cxx b/src/Lib/Polygon/polygon.cxx index 2190dd05..8d132d05 100644 --- a/src/Lib/Polygon/polygon.cxx +++ b/src/Lib/Polygon/polygon.cxx @@ -325,8 +325,8 @@ void make_gpc_poly( const TGPolygon& in, gpc_polygon *out ) { for ( int j = 0; j < in.contour_size( i ); ++j ) { p = in.get_pt( i, j ); - v_list.vertex[j].x = p.x(); - v_list.vertex[j].y = p.y(); + v_list.vertex[j].x = p.x()+2*SG_EPSILON; + v_list.vertex[j].y = p.y()+2*SG_EPSILON; } v_list.num_vertices = in.contour_size( i ); gpc_add_contour( out, &v_list, in.get_hole_flag( i ) ); diff --git a/src/Utils/Makefile.am b/src/Utils/Makefile.am index f80f74a4..804fe798 100644 --- a/src/Utils/Makefile.am +++ b/src/Utils/Makefile.am @@ -3,3 +3,8 @@ EXTRA_DIST = mirror-dem SUBDIRS = \ cdrom \ download-map + +if WANT_POLY2OGR +SUBDIRS+=poly2ogr +endif + diff --git a/src/Utils/poly2ogr/.gitignore b/src/Utils/poly2ogr/.gitignore new file mode 100644 index 00000000..5f4baf81 --- /dev/null +++ b/src/Utils/poly2ogr/.gitignore @@ -0,0 +1 @@ +poly2ogr diff --git a/src/Utils/poly2ogr/Makefile.am b/src/Utils/poly2ogr/Makefile.am new file mode 100644 index 00000000..c305528c --- /dev/null +++ b/src/Utils/poly2ogr/Makefile.am @@ -0,0 +1,12 @@ +bin_PROGRAMS = poly2ogr + +poly2ogr_SOURCES = poly2ogr.cxx + +poly2ogr_CXXFLAGS=$(GDAL_CFLAGS) + +poly2ogr_LDADD = \ + $(GDAL_LIBS) \ + $(top_builddir)/src/Lib/Polygon/libPolygon.a \ + -lsgstructure -lsgmisc -lsgdebug -lz + +INCLUDES = -I$(top_srcdir)/src/Lib diff --git a/src/Utils/poly2ogr/poly2ogr.cxx b/src/Utils/poly2ogr/poly2ogr.cxx new file mode 100644 index 00000000..c88dd1c5 --- /dev/null +++ b/src/Utils/poly2ogr/poly2ogr.cxx @@ -0,0 +1,337 @@ +// poly2ogr.cxx -- Translate the polygon definitions in a given TerraGear +// working directory to vector data, writing it out using +// the OGR library. +// +// Written by Ralf Gerlich, started December 2007. +// +// Copyright (C) 2007 Ralf Gerlich - ralf.gerlich@custom-scenery.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. + +#include + +#include STL_STRING +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +typedef std::map LayerMap; + +const char* format_name="ESRI Shapefile"; +bool do_split=false; + +OGRDataSource *datasource; +OGRLayer *defaultLayer; +LayerMap layerMap; + +bool endswith(const std::string& s, const std::string& suffix) { + size_t slen,sufflen; + slen=s.size(); + sufflen=suffix.size(); + if (slenCreateLayer(material.c_str(),&srs,wkbPolygon25D,NULL); + if (!layer) { + SG_LOG(SG_GENERAL, SG_ALERT, "Creation of layer '" << material << "' failed"); + return NULL; + } + + OGRFieldDefn materialField("Material", OFTString); + materialField.SetWidth(128); + + OGRFieldDefn fileField("File",OFTString); + fileField.SetWidth(256); + + if( layer->CreateField( &materialField ) != OGRERR_NONE ) { + SG_LOG(SG_GENERAL, SG_ALERT, "Creation of field 'Material' failed"); + } + + if( layer->CreateField( &fileField ) != OGRERR_NONE ) { + SG_LOG(SG_GENERAL, SG_ALERT, "Creation of field 'Material' failed"); + } + + return layer; +} + +OGRLayer* get_layer_for_material(const std::string& material) { + if (!do_split) { + if (!defaultLayer) { + defaultLayer=create_layer("default"); + } + return defaultLayer; + } + + OGRLayer* layer; + LayerMap::iterator it=layerMap.find(material); + if (it==layerMap.end()) { + layer=create_layer(material); + if (!layer) + return NULL; + layerMap[material]=layer; + } else { + layer=(*it).second; + } + return layer; +} + +void process_polygon_file(const std::string& path) { + SG_LOG(SG_GENERAL, SG_INFO, "Loading polygon file " << path); + + sg_gzifstream in( path ); + + while (!in.eof()) { + string first_line,material; + bool poly3d=false; + in >> first_line; + if ( first_line == "#2D" ) { + poly3d = false; + in >> material; + } else if ( first_line == "#3D" ) { + poly3d = true; + in >> material; + } else { + // support old format (default to 2d) + poly3d = false; + material=first_line; + } + + int contours; + in >> contours; + + OGRPolygon* polygon=new OGRPolygon(); + + for (int contour=0;contour> count; + + if (count<3) { + SG_LOG(SG_GENERAL, SG_ALERT, "Polygon with less than 3 points"); + skip_ring=true; + } + + in >> hole_flag; + + // FIXME: Current we ignore the hole-flag and instead assume + // that the first ring is not a hole and the rest + // are holes + + OGRLinearRing *ring=new OGRLinearRing(); + + for (int pt=0;pt> x >> y; + point->setX(x); + point->setY(y); + if (poly3d) { + in >> z; + point->setZ(z); + } else { + point->setZ(0.0); + } + + ring->addPoint(point); + } + + ring->closeRings(); + + if (!skip_ring) + polygon->addRingDirectly(ring); + } + + OGRLayer* layer=get_layer_for_material(material); + OGRFeature* feature; + + feature = new OGRFeature( layer->GetLayerDefn() ); + feature->SetField("Material", material.c_str()); + feature->SetField("File", path.c_str()); + feature->SetGeometry(polygon); + + if( layer->CreateFeature( feature ) != OGRERR_NONE ) + { + SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create feature in shapefile"); + } + + OGRFeature::DestroyFeature(feature); + } +} + +void process_file(const std::string& path) { + struct stat sbuf; + + if ( stat(path.c_str(),&sbuf) != 0 ) { + SG_LOG(SG_GENERAL, SG_ALERT, "Unable to stat path '" << path << "'"); + return; + } + + if (S_ISDIR(sbuf.st_mode)) { + DIR* dir; + + dir=opendir(path.c_str()); + if (!dir) { + SG_LOG(SG_GENERAL, SG_ALERT, "Unable to open directory '" << path << "'"); + return; + } + + struct dirent *de; + + while ((de=readdir(dir))) { + if (!strcmp(de->d_name,".") || !strcmp(de->d_name,"..")) { + continue; + } + + std::string subpath=path+"/"+de->d_name; + process_file(subpath); + } + + closedir(dir); + } else if (!endswith(path,".gz") && + !endswith(path,".arr") && + !endswith(path,".fit") && + !endswith(path,".btg") && + !endswith(path,".stg") && + !endswith(path,".ind")) { + // should be a polygon file + process_polygon_file(path); + } +} + +void usage(const char* progname, const std::string& msg) { + if (msg.size()!=0) + SG_LOG(SG_GENERAL,SG_ALERT, msg); + SG_LOG(SG_GENERAL, SG_INFO, "Usage: " << progname << " [options] dst_datasource path..."); + SG_LOG(SG_GENERAL, SG_INFO, ""); + SG_LOG(SG_GENERAL, SG_INFO, "Options:"); + SG_LOG(SG_GENERAL, SG_INFO, "\t-h"); + SG_LOG(SG_GENERAL, SG_INFO, "\t--help"); + SG_LOG(SG_GENERAL, SG_INFO, "\t\tShow this help screen"); + SG_LOG(SG_GENERAL, SG_INFO, ""); + SG_LOG(SG_GENERAL, SG_INFO, "\t-v"); + SG_LOG(SG_GENERAL, SG_INFO, "\t--version"); + SG_LOG(SG_GENERAL, SG_INFO, "\t\tShow the version"); + SG_LOG(SG_GENERAL, SG_INFO, ""); + SG_LOG(SG_GENERAL, SG_INFO, "\t-s"); + SG_LOG(SG_GENERAL, SG_INFO, "\t--split"); + SG_LOG(SG_GENERAL, SG_INFO, "\t\tCreate one layer per material"); + SG_LOG(SG_GENERAL, SG_INFO, ""); + SG_LOG(SG_GENERAL, SG_INFO, "\t-f format"); + SG_LOG(SG_GENERAL, SG_INFO, "\t--format format"); + SG_LOG(SG_GENERAL, SG_INFO, "\t\tSpecify the output format"); + SG_LOG(SG_GENERAL, SG_INFO, "\t\tAvailable formats:"); + OGRSFDriverRegistrar* registrar=OGRSFDriverRegistrar::GetRegistrar(); + for (int i=0;iGetDriverCount();i++) { + SG_LOG(SG_GENERAL, SG_INFO, "\t\t\t-f \"" << registrar->GetDriver(i)->GetName() << "\""); + } + SG_LOG(SG_GENERAL, SG_INFO, "\t\tDefault: ESRI Shapefile"); + SG_LOG(SG_GENERAL, SG_INFO, ""); + SG_LOG(SG_GENERAL, SG_INFO, "The polygons from the given paths are read and transferred"); + SG_LOG(SG_GENERAL, SG_INFO, "to layers in the given destination datasource."); + SG_LOG(SG_GENERAL, SG_INFO, ""); + SG_LOG(SG_GENERAL, SG_INFO, "If one of the paths is a directory, the files in this directory"); + SG_LOG(SG_GENERAL, SG_INFO, "and its subdirectories are read."); +} + +struct option options[]={ + {"help",no_argument,NULL,'h'}, + {"version",no_argument,NULL,'v'}, + {"split",no_argument,NULL,'s'}, + {"format",required_argument,NULL,'f'}, + {NULL,0,NULL,0} +}; + +int main(int argc, char** argv) { + sglog().setLogLevels( SG_ALL, SG_DEBUG ); + + OGRRegisterAll(); + + int option; + + while ((option=getopt_long(argc,argv,"hvsf:",options,NULL))!=-1) { + switch (option) { + case 'h': + usage(argv[0],""); + break; + case 'f': + format_name=optarg; + break; + case 's': + do_split=true; + break; + case 'v': + SG_LOG(SG_GENERAL,SG_INFO,argv[0] << " Version 1.0"); + exit(0); + break; + case '?': + usage(argv[0],std::string("Unknown option:")+(char)optopt); + exit(1); + } + } + + if (optind+1>argc) { + usage(argv[0],"A datasource must be specified"); + exit(1); + } + + if (optind+2>argc) { + usage(argv[0],"At least one input file must be specified"); + exit(1); + } + + const char* dst_datasource=argv[optind++]; + OGRSFDriver *ogrdriver; + + ogrdriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(format_name); + if (!ogrdriver) { + usage(argv[0],std::string("Unknown datasource format driver:")+format_name); + exit(1); + } + + datasource = ogrdriver->CreateDataSource(dst_datasource,NULL); + if (!datasource) { + usage(argv[0],std::string("Unable to create datasource:")+dst_datasource); + exit(1); + } + + for (int i=optind;i