/* * *************************************************************** * * * * MODULE: v.out.ogr * * * * AUTHOR(S): Radim Blazek * * Some extensions: Markus Neteler * * * * PURPOSE: Category manipulations * * * * COPYRIGHT: (C) 2001 by the GRASS Development Team * * * * This program is free software under the * * GNU General Public License (>=v2). * * Read the file COPYING that comes with GRASS * * for details. * * * **************************************************************/ #include #include #include #include #include #include "ogr_api.h" #include "cpl_string.h" #include #include #include int fout, fskip; /* features written/ skip */ int nocat, noatt, nocatskip; /* number of features without cats/atts written/skip */ int mk_att ( int cat, struct field_info *Fi, dbDriver *Driver, int ncol, int keycol, int doatt, OGRFeatureH Ogr_feature); char *OGR_list_write_drivers(); char OGRdrivers[2000]; int main (int argc, char *argv[]) { int i, j, k, centroid, otype, donocat; char *mapset; int field; struct GModule *module; struct Option *in_opt, *dsn_opt, *layer_opt, *type_opt, *frmt_opt, *field_opt, *dsco, *lco; struct Flag *cat_flag, *esristyle, *poly_flag; char buf[2000]; char key1[200], key2[200]; struct Key_Value *projinfo, *projunits; struct Cell_head cellhd; /* Vector */ struct Map_info In; struct line_pnts *Points; struct line_cats *Cats; int type, cat; /* Attributes */ int doatt=0, ncol=0, colsqltype, colctype, keycol=-1; struct field_info *Fi=NULL; dbDriver *Driver=NULL; dbHandle handle; dbTable *Table; dbString dbstring; dbColumn *Column; /* OGR */ int drn, ogr_ftype=OFTInteger; OGRDataSourceH Ogr_ds; OGRSFDriverH Ogr_driver; OGRLayerH Ogr_layer; OGRFieldDefnH Ogr_field; OGRFeatureH Ogr_feature; OGRFeatureDefnH Ogr_featuredefn; OGRGeometryH Ogr_geometry; unsigned int wkbtype=wkbUnknown; /* ?? */ OGRSpatialReferenceH Ogr_projection; char **papszDSCO = NULL, **papszLCO = NULL; G_gisinit(argv[0]); /* Module options */ module = G_define_module(); module->keywords = _("vector"); module->description = _("Convert to one of the supported OGR vector formats."); in_opt = G_define_standard_option(G_OPT_V_INPUT); type_opt = G_define_standard_option(G_OPT_V_TYPE) ; type_opt->options = "point,kernel,centroid,line,boundary,area,face"; type_opt->answer = "line,boundary"; type_opt->description = _("Feature type. Combination of types is not supported" " by all formats."); dsn_opt = G_define_option(); dsn_opt->key = "dsn"; dsn_opt->type = TYPE_STRING; dsn_opt->required = YES; dsn_opt->description = _("OGR output datasource name. For example:\n" "\t\tESRI Shapefile: filename or directory for storage\n" "\t\tMapInfo File: filename or directory for storage"); layer_opt = G_define_option(); layer_opt->key = "olayer"; layer_opt->type = TYPE_STRING; layer_opt->required = YES; layer_opt->description = _("OGR layer name.\n" "\t\tESRI Shapefile: shapefile name\n" "\t\tMapInfo File: mapinfo file name"); field_opt = G_define_standard_option(G_OPT_V_FIELD); field_opt->answer = "1"; frmt_opt = G_define_option(); frmt_opt->key = "format"; frmt_opt->type = TYPE_STRING; frmt_opt->required = NO; frmt_opt->multiple = NO; frmt_opt->answer = "ESRI_Shapefile"; frmt_opt->options = OGR_list_write_drivers(); frmt_opt->description = _("OGR format."); dsco = G_define_option(); dsco->key = "dsco"; dsco->type = TYPE_STRING; dsco->required = NO; dsco->multiple = NO; dsco->answer = ""; dsco->description = _("OGR dataset creation option (format specific, NAME=VALUE)"); lco = G_define_option(); lco->key = "lco"; lco->type = TYPE_STRING; lco->required = NO; lco->multiple = NO; lco->answer = ""; lco->description = _("OGR layer creation option (format specific, NAME=VALUE)"); cat_flag = G_define_flag (); cat_flag->key = 'c'; cat_flag->description = _("Export features with category (labeled) only. " "Otherwise all features are exported"); esristyle = G_define_flag(); esristyle->key = 'e'; esristyle->description = _("Use ESRI-style .prj file format (applies to SHAPE output only)"); poly_flag = G_define_flag(); poly_flag->key = 'p'; poly_flag->description = _("Export lines as polygons"); if (G_parser (argc, argv)) exit(EXIT_FAILURE); /* read options */ field = atoi( field_opt->answer ); /* Check output type */ otype = Vect_option_to_types ( type_opt ); if ( otype & GV_POINTS ) wkbtype = wkbPoint; else if ( otype & GV_LINES ) wkbtype = wkbLineString; else if ( otype & GV_AREA ) wkbtype = wkbPolygon; else if ( otype & GV_FACE ) wkbtype = wkbPolygon25D; if ( poly_flag->answer ) wkbtype = wkbPolygon; if ( ((GV_POINTS & otype) && (GV_LINES & otype)) || ((GV_POINTS & otype) && (GV_AREA & otype)) || ((GV_POINTS & otype) && (GV_FACE & otype)) || ((GV_LINES & otype) && (GV_AREA & otype)) || ((GV_LINES & otype) && (GV_FACE & otype)) ) { G_warning (_("The combination of types is not supported " " by all formats.")); wkbtype=wkbUnknown; } if ( cat_flag->answer ) donocat = 0; else donocat = 1; Points = Vect_new_line_struct (); Cats = Vect_new_cats_struct (); /* open input vector */ if ((mapset = G_find_vector2 (in_opt->answer, "")) == NULL) { G_fatal_error (_("Could not find input vector map <%s>"), in_opt->answer); } Vect_set_open_level (2); Vect_open_old (&In, in_opt->answer, mapset); /* fetch PROJ info */ G_get_default_window(&cellhd); if( cellhd.proj == PROJECTION_XY ) Ogr_projection = NULL; else { projinfo = G_get_projinfo(); projunits = G_get_projunits(); Ogr_projection = GPJ_grass_to_osr(projinfo, projunits); if (esristyle->answer && (strcmp(frmt_opt->answer, "ESRI_Shapefile") == 0)) OSRMorphToESRI(Ogr_projection); } /* Open OGR DSN */ OGRRegisterAll(); G_debug (2, "driver count = %d", OGRGetDriverCount() ); drn = -1; for ( i = 0; i < OGRGetDriverCount(); i++ ) { Ogr_driver = OGRGetDriver( i ); G_debug (2, "driver %d : %s", i, OGR_Dr_GetName ( Ogr_driver) ); /* chg white space to underscore in OGR driver names */ sprintf (buf, "%s", OGR_Dr_GetName ( Ogr_driver) ); G_strchg(buf,' ','_'); if ( strcmp ( buf , frmt_opt->answer ) == 0 ) { drn = i; G_debug (2, " -> driver = %d" ); } } if ( drn == -1 ) G_fatal_error ( _("Driver %s not found"), frmt_opt->answer ); Ogr_driver = OGRGetDriver( drn ); papszDSCO = CSLSetNameValue( papszDSCO, dsco->answer,"YES"); Ogr_ds = OGR_Dr_CreateDataSource( Ogr_driver, dsn_opt->answer, papszDSCO ); CSLDestroy( papszDSCO ); if ( Ogr_ds == NULL ) G_fatal_error (_("Cannot open OGR data source '%s'"), dsn_opt->answer); papszLCO = CSLSetNameValue( papszLCO, lco->answer,"YES"); Ogr_layer = OGR_DS_CreateLayer( Ogr_ds, layer_opt->answer, Ogr_projection, wkbtype, papszLCO ); CSLDestroy( papszLCO ); if ( Ogr_layer == NULL ) G_fatal_error (_("Cannot create layer")); db_init_string(&dbstring); /* Vector attributes -> OGR fields */ if ( field > 0 ) { doatt = 1; /* do attributes */ Fi = Vect_get_field( &In, field); if ( Fi == NULL ) { G_warning (_("No attribute table found -> using only category numbers as attributes")); Ogr_field = OGR_Fld_Create( "cat", OFTInteger ); OGR_L_CreateField( Ogr_layer, Ogr_field, 0 ); doatt = 0; } else { Driver = db_start_driver(Fi->driver); if (Driver == NULL) G_fatal_error(_("Cannot open driver %s"), Fi->driver); db_init_handle (&handle); db_set_handle (&handle, Fi->database, NULL); if (db_open_database(Driver, &handle) != DB_OK) G_fatal_error(_("Cannot open database %s"), Fi->database); db_set_string(&dbstring, Fi->table); if(db_describe_table (Driver, &dbstring, &Table) != DB_OK) G_fatal_error(_("Cannot describe table %s"), Fi->table); ncol = db_get_table_number_of_columns(Table); G_debug (2, "ncol = %d", ncol ); keycol = -1; for (i = 0; i < ncol; i++) { Column = db_get_table_column (Table, i); colsqltype = db_get_column_sqltype(Column); G_debug (2, "col %d: %s (%s)", i, db_get_column_name(Column), db_sqltype_name(colsqltype) ); colctype = db_sqltype_to_Ctype ( colsqltype ); switch ( colctype ) { case DB_C_TYPE_INT: ogr_ftype = OFTInteger; break; case DB_C_TYPE_DOUBLE: ogr_ftype = OFTReal; break; case DB_C_TYPE_STRING: ogr_ftype = OFTString; break; case DB_C_TYPE_DATETIME: ogr_ftype = OFTString; break; } G_debug (2, "ogr_ftype = %d", ogr_ftype ); strcpy ( key1, Fi->key ); G_tolcase ( key1 ); strcpy ( key2, db_get_column_name(Column) ); G_tolcase ( key2 ); if ( strcmp(key1, key2) == 0 ) keycol = i; G_debug (2, "%s x %s -> %s x %s -> keycol = %d", Fi->key, db_get_column_name(Column), key1, key2, keycol ); Ogr_field = OGR_Fld_Create( db_get_column_name(Column), ogr_ftype ); OGR_L_CreateField( Ogr_layer, Ogr_field, 0 ); } if ( keycol == -1 ) G_fatal_error (_("Key column '%s' not found"), Fi->key ); } } Ogr_featuredefn = OGR_L_GetLayerDefn( Ogr_layer ); Ogr_feature = OGR_F_Create( Ogr_featuredefn ); fout = fskip = nocat = noatt = nocatskip = 0; /* check what users wants to export and what's present in the map */ if ( Vect_get_num_primitives(&In, GV_POINT) > 0 && !(otype & GV_POINTS) ) G_warning(_("%d Point(s) found, but not requested to be exported. Verify 'type' parameter."),Vect_get_num_primitives(&In, GV_POINT)); if ( Vect_get_num_primitives(&In, GV_LINE) > 0 && !(otype & GV_LINES) ) G_warning(_("%d Line(s) found, but not requested to be exported. Verify 'type' parameter."),Vect_get_num_primitives(&In, GV_LINE)); if ( Vect_get_num_primitives(&In, GV_BOUNDARY) > 0 && !(otype & GV_BOUNDARY) && !(otype & GV_AREA) ) G_warning(_("%d Boundary(ies) found, but not requested to be exported. Verify 'type' parameter."),Vect_get_num_primitives(&In, GV_BOUNDARY)); if ( Vect_get_num_primitives(&In, GV_CENTROID) > 0 && !(otype & GV_CENTROID) && !(otype & GV_AREA) ) G_warning(_("%d Centroid(s) found, but not requested to be exported. Verify 'type' parameter."),Vect_get_num_primitives(&In, GV_CENTROID)); if ( Vect_get_num_primitives(&In, GV_AREA) > 0 && !(otype & GV_AREA) ) G_warning(_("%d Areas found, but not requested to be exported. Verify 'type' parameter."),Vect_get_num_primitives(&In, GV_AREA)); if ( Vect_get_num_primitives(&In, GV_FACE) > 0 && !(otype & GV_FACE) ) G_warning(_("%d Faces found, but not requested to be exported. Verify 'type' parameter."),Vect_get_num_primitives(&In, GV_FACE)); /* add? GV_KERNEL */ /* Lines (run always to count features of different type) */ if ( (otype & GV_POINTS) || (otype & GV_LINES) ) { fprintf(stderr,"Exporting %i points/lines...\n", Vect_get_num_lines(&In) ); for ( i = 1; i <= Vect_get_num_lines(&In) ; i++ ) { G_percent(i,Vect_get_num_lines(&In),1); type = Vect_read_line (&In, Points, Cats, i); G_debug (2, "line = %d type = %d", i, type ); if ( !(otype & type ) ) { G_debug (2, "type %d not specified -> skip", type ); fskip++; continue; } Vect_cat_get (Cats, field, &cat); if ( cat < 0 && !donocat ) { /* Do not export not labeled */ nocatskip++; continue; } /* Geometry */ if ( type == GV_LINE && poly_flag->answer ) { OGRGeometryH ring; ring = OGR_G_CreateGeometry( wkbLinearRing ); Ogr_geometry = OGR_G_CreateGeometry( wkbPolygon ); /* Area */ for ( j = 0; j < Points->n_points; j++ ) { OGR_G_AddPoint( ring, Points->x[j], Points->y[j], Points->z[j] ); } if ( Points->x[Points->n_points-1] != Points->x[0] || Points->y[Points->n_points-1] != Points->y[0] || Points->z[Points->n_points-1] != Points->z[0] ) { OGR_G_AddPoint( ring, Points->x[0], Points->y[0], Points->z[0] ); } OGR_G_AddGeometryDirectly ( Ogr_geometry, ring ); } else if ( type == GV_POINT ) { Ogr_geometry = OGR_G_CreateGeometry( wkbPoint ); OGR_G_AddPoint( Ogr_geometry, Points->x[0], Points->y[0], Points->z[0] ); } else /* GV_LINE or GV_BOUNDARY */ { Ogr_geometry = OGR_G_CreateGeometry( wkbLineString ); for ( j = 0; j < Points->n_points; j++ ) { OGR_G_AddPoint( Ogr_geometry, Points->x[j], Points->y[j], Points->z[j] ); } } OGR_F_SetGeometry( Ogr_feature, Ogr_geometry ); /* Output one feature for each category */ for ( j = -1; j < Cats->n_cats; j++ ) { if ( j == -1 ) { if ( cat >= 0 ) continue; /* cat(s) exists */ } else { if ( Cats->field[j] == field ) cat = Cats->cat[j]; else continue; } mk_att ( cat, Fi, Driver, ncol, keycol, doatt, Ogr_feature); OGR_L_CreateFeature( Ogr_layer, Ogr_feature ); } OGR_G_DestroyGeometry( Ogr_geometry ); } } /* Areas (run always to count features of different type) */ if ( otype & GV_AREA ) { fprintf(stderr,"Exporting %i areas (may take some time) ...\n", Vect_get_num_areas(&In) ); for ( i = 1; i <= Vect_get_num_areas(&In) ; i++ ) { OGRGeometryH ring; G_percent(i,Vect_get_num_areas(&In),1); centroid = Vect_get_area_centroid ( &In, i ); cat = -1; if ( centroid > 0 ) { Vect_read_line (&In, NULL, Cats, centroid ); Vect_cat_get (Cats, field, &cat); } G_debug (3, "area = %d centroid = %d ncats = %d", i, centroid, Cats->n_cats ); if ( cat < 0 && !donocat ) { /* Do not export not labeled */ nocatskip++; continue; } Vect_get_area_points ( &In, i, Points ); /* Geometry */ Ogr_geometry = OGR_G_CreateGeometry( wkbPolygon ); ring = OGR_G_CreateGeometry( wkbLinearRing ); /* Area */ for ( j = 0; j < Points->n_points; j++ ) { OGR_G_AddPoint( ring, Points->x[j], Points->y[j], Points->z[j] ); } OGR_G_AddGeometryDirectly ( Ogr_geometry, ring ); /* Isles */ for ( k = 0; k < Vect_get_area_num_isles (&In, i); k++ ) { Vect_get_isle_points ( &In, Vect_get_area_isle (&In, i, k), Points ); ring = OGR_G_CreateGeometry( wkbLinearRing ); for ( j = 0; j < Points->n_points; j++ ) { OGR_G_AddPoint( ring, Points->x[j], Points->y[j], Points->z[j] ); } OGR_G_AddGeometryDirectly ( Ogr_geometry, ring ); } OGR_F_SetGeometry( Ogr_feature, Ogr_geometry ); /* Output one feature for each category */ for ( j = -1; j < Cats->n_cats; j++ ) { if ( j == -1 ) { if ( cat >= 0 ) continue; /* cat(s) exists */ } else { if ( Cats->field[j] == field ) cat = Cats->cat[j]; else continue; } mk_att ( cat, Fi, Driver, ncol, keycol, doatt, Ogr_feature); OGR_L_CreateFeature( Ogr_layer, Ogr_feature ); } OGR_G_DestroyGeometry( Ogr_geometry ); } } /* Faces (run always to count features of different type) - Faces are similar to lines */ if ( otype & GV_FACE ) { fprintf(stderr,"Exporting %i faces (may take some time) ...\n", Vect_get_num_faces(&In) ); for ( i = 1; i <= Vect_get_num_faces(&In) ; i++ ) { OGRGeometryH ring; G_percent(i,Vect_get_num_faces(&In),1); type = Vect_read_line(&In, Points, Cats, i); G_debug(3, "line type = %d", type); cat = -1; Vect_cat_get (Cats, field, &cat); G_debug (3, "face = %d ncats = %d", i, Cats->n_cats ); if ( cat < 0 && !donocat ) { /* Do not export not labeled */ nocatskip++; continue; } if ( type & GV_FACE ) { /* Geometry */ Ogr_geometry = OGR_G_CreateGeometry( wkbPolygon25D ); ring = OGR_G_CreateGeometry( wkbLinearRing ); /* Face */ for ( j = 0; j < Points->n_points; j++ ) { OGR_G_AddPoint( ring, Points->x[j], Points->y[j], Points->z[j] ); } OGR_G_AddGeometryDirectly ( Ogr_geometry, ring ); /* Output one feature for each category */ for ( j = -1; j < Cats->n_cats; j++ ) { if ( j == -1 ) { if ( cat >= 0 ) continue; /* cat(s) exists */ } else { if ( Cats->field[j] == field ) cat = Cats->cat[j]; else continue; } mk_att ( cat, Fi, Driver, ncol, keycol, doatt, Ogr_feature); OGR_L_CreateFeature( Ogr_layer, Ogr_feature ); } OGR_F_SetGeometry( Ogr_feature, Ogr_geometry ); OGR_G_DestroyGeometry( Ogr_geometry ); } /* if type & GV_FACE */ } /* for */ } OGR_F_Destroy( Ogr_feature ); OGR_DS_Destroy( Ogr_ds ); Vect_close (&In); if ( doatt ) { db_close_database(Driver); db_shutdown_driver(Driver); } /* Summary */ fprintf (stderr, "%d features written\n", fout); if ( nocat > 0 ) G_warning ( "%d features without category written", nocat); if ( noatt > 0 ) G_warning ( "%d features without attributes written", noatt); if ( nocatskip > 0 ) G_warning ( "%d features found without category skip", nocatskip); /* Enable this? May be confusing that for area type are not reported all boundaries/centroids. * OTOH why should be reported? */ /* if ( ((otype & GV_POINTS) || (otype & GV_LINES)) && fskip > 0 ) G_warning ( "%d features of different type skip", fskip); */ exit(EXIT_SUCCESS) ; } int mk_att ( int cat, struct field_info *Fi, dbDriver *Driver, int ncol, int keycol, int doatt, OGRFeatureH Ogr_feature) { int j; char buf[2000]; int colsqltype, colctype, more; dbTable *Table; dbString dbstring; dbColumn *Column; dbCursor cursor; dbValue *Value; G_debug (2, "mk_att() cat = %d, doatt = %d", cat, doatt ); db_init_string(&dbstring); /* Attributes */ /* Reset */ if ( doatt ) { for (j = 0; j < ncol; j++) OGR_F_UnsetField(Ogr_feature, j); } else { OGR_F_UnsetField(Ogr_feature, 0); } /* Read & set attributes */ if( cat >= 0 ) { /* Line with category */ if ( doatt ) { sprintf ( buf, "SELECT * FROM %s WHERE %s = %d", Fi->table, Fi->key, cat); G_debug (2, "SQL: %s", buf); db_set_string(&dbstring, buf); if ( db_open_select_cursor(Driver, &dbstring, &cursor, DB_SEQUENTIAL) != DB_OK ) { G_fatal_error ( _("Cannot select attributes for cat = %d"), cat); } else { if(db_fetch (&cursor, DB_NEXT, &more) != DB_OK) G_fatal_error (_("Cannot fetch data")); if (!more) { /* G_warning ("No database record for cat = %d", cat); */ /* Set at least key column to category */ OGR_F_SetFieldInteger ( Ogr_feature, keycol, cat ); noatt++; } else { Table = db_get_cursor_table (&cursor); for (j = 0; j < ncol; j++) { Column = db_get_table_column (Table, j); Value = db_get_column_value(Column); db_convert_column_value_to_string (Column, &dbstring); /* for debug only */ G_debug (2, "col %d : val = %s", j, db_get_string (&dbstring) ); colsqltype = db_get_column_sqltype(Column); colctype = db_sqltype_to_Ctype ( colsqltype ); G_debug (2, " colctype = %d", colctype ); switch ( colctype ) { case DB_C_TYPE_INT: OGR_F_SetFieldInteger( Ogr_feature, j, db_get_value_int(Value) ); break; case DB_C_TYPE_DOUBLE: OGR_F_SetFieldDouble( Ogr_feature, j, db_get_value_double(Value) ); break; case DB_C_TYPE_STRING: OGR_F_SetFieldString( Ogr_feature, j, db_get_value_string(Value) ); break; case DB_C_TYPE_DATETIME: db_convert_column_value_to_string (Column, &dbstring); OGR_F_SetFieldString( Ogr_feature, j, db_get_string (&dbstring) ); break; } } } } } else { /* Use cat only */ OGR_F_SetFieldInteger( Ogr_feature, 0, cat ); } } else { /* G_warning ( "Line without cat of layer %d", field); */ nocat++; } fout++; return 1; } /* to print available drivers in help text */ char * OGR_list_write_drivers(void) { int drn, i; OGRSFDriverH Ogr_driver; char buf[2000]; /* Open OGR DSN */ OGRRegisterAll(); G_debug (2, "driver count = %d", OGRGetDriverCount() ); drn = -1; for ( i = 0; i < OGRGetDriverCount(); i++ ) { /* only fetch read/write drivers */ if (OGR_Dr_TestCapability( OGRGetDriver(i),ODrCCreateDataSource) ) { Ogr_driver = OGRGetDriver( i ); G_debug (2, "driver %d/%d : %s", i, OGRGetDriverCount(), OGR_Dr_GetName ( Ogr_driver) ); /* chg white space to underscore in OGR driver names */ sprintf (buf, "%s", OGR_Dr_GetName ( Ogr_driver) ); G_strchg(buf,' ','_'); strcat (OGRdrivers, buf); if (i < OGRGetDriverCount() - 1 ) strcat (OGRdrivers, ","); } } G_debug (2, "all drivers: %s",OGRdrivers); return OGRdrivers; }