/*! \brief Get information about link to database (by layer number or layer name) Note: if <em>field</em> is -1 then the function returns the first dblink or NULL \param Map pointer to Map_info structure \param field layer number or name \return pointer to new field_info structure \return NULL if not found */ struct field_info *Vect_get_field2(const struct Map_info *Map, const char *field) { int ifield; struct field_info *fi; G_debug(1, "Vect_get_field2(): field = %s", field); fi = NULL; ifield = atoi(field); if (ifield > 0) { fi = Vect_get_field(Map, ifield); if (fi) return fi; } else if (ifield == -1) { if (Vect_get_num_dblinks(Map) > 0) return Vect_get_dblink(Map, 0); /* return first */ else return NULL; } else if (ifield == 0) return Vect_get_field_by_name(Map, field); return NULL; }
/*! \brief Get information about link to database (by layer name) \param Map pointer to Map_info structure \param field layer name \return pointer to new field_info structure \return NULL if not found */ struct field_info *Vect_get_field_by_name(const struct Map_info *Map, const char *field) { int i; struct field_info *fi = NULL; G_debug(1, "Vect_get_field_by_name(): field = %s", field); for (i = 0; i < Map->dblnk->n_fields; i++) { if (strcmp(Map->dblnk->field[i].name, field) == 0) { fi = Vect_get_dblink(Map, i); break; } } return fi; }
/*! \brief Get information about link to database (by layer number) Variables are substituted by values, field is number of requested field. \param Map pointer to Map_info structure \param field layer number \return pointer to new field_info structure \return NULL if not found */ struct field_info *Vect_get_field(const struct Map_info *Map, int field) { int i; struct field_info *fi = NULL; G_debug(1, "Vect_get_field(): field = %d", field); for (i = 0; i < Map->dblnk->n_fields; i++) { if (Map->dblnk->field[i].number == field) { fi = Vect_get_dblink(Map, i); break; } } return fi; }
/*! \brief Copy DB links from input vector map to output vector map \param In pointer to Map_info structure (input) \param Out pointer to Map_info structure (output) \param first_only TRUE to copy only first link otherwise all DB links are copied */ void Vect_copy_map_dblinks(const struct Map_info *In, struct Map_info *Out, int first_only) { int i, ndblinks; struct field_info *Fi; ndblinks = Vect_get_num_dblinks(In); for (i = 0; i < ndblinks; i++) { Fi = Vect_get_dblink(In, 0); if (!Fi) { G_warning(_("Database connection not defined. Skipping.")); continue; } Vect_map_add_dblink(Out, Fi->number, Fi->name, Fi->table, Fi->key, Fi->database, Fi->driver); if (first_only && ndblinks > 1) G_warning(_("More DB links defined for input vector map. " "Using only first DB link for output.")); } }
int main(int argc, char *argv[]) { int i, cat, with_z, more, ctype, nrows; char buf[DB_SQL_MAX]; int count; double coor[3]; int ncoor; struct Option *driver_opt, *database_opt, *table_opt; struct Option *xcol_opt, *ycol_opt, *zcol_opt, *keycol_opt, *where_opt, *outvect; struct Flag *same_table_flag; struct GModule *module; struct Map_info Map; struct line_pnts *Points; struct line_cats *Cats; dbString sql; dbDriver *driver; dbCursor cursor; dbTable *table; dbColumn *column; dbValue *value; struct field_info *fi; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("import")); G_add_keyword(_("database")); G_add_keyword(_("points")); module->description = _("Creates new vector (points) map from database table containing coordinates."); table_opt = G_define_standard_option(G_OPT_DB_TABLE); table_opt->required = YES; table_opt->description = _("Input table name"); driver_opt = G_define_standard_option(G_OPT_DB_DRIVER); driver_opt->options = db_list_drivers(); driver_opt->answer = (char *)db_get_default_driver_name(); driver_opt->guisection = _("Input DB"); database_opt = G_define_standard_option(G_OPT_DB_DATABASE); database_opt->answer = (char *)db_get_default_database_name(); database_opt->guisection = _("Input DB"); xcol_opt = G_define_standard_option(G_OPT_DB_COLUMN); xcol_opt->key = "x"; xcol_opt->required = YES; xcol_opt->description = _("Name of column containing x coordinate"); ycol_opt = G_define_standard_option(G_OPT_DB_COLUMN); ycol_opt->key = "y"; ycol_opt->required = YES; ycol_opt->description = _("Name of column containing y coordinate"); zcol_opt = G_define_standard_option(G_OPT_DB_COLUMN); zcol_opt->key = "z"; zcol_opt->description = _("Name of column containing z coordinate"); zcol_opt->guisection = _("3D output"); keycol_opt = G_define_standard_option(G_OPT_DB_COLUMN); keycol_opt->key = "key"; keycol_opt->required = NO; keycol_opt->label = _("Name of column containing category number"); keycol_opt->description = _("Must refer to an integer column"); where_opt = G_define_standard_option(G_OPT_DB_WHERE); where_opt->guisection = _("Selection"); outvect = G_define_standard_option(G_OPT_V_OUTPUT); same_table_flag = G_define_flag(); same_table_flag->key = 't'; same_table_flag->description = _("Use imported table as attribute table for new map"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); if (zcol_opt->answer) { with_z = WITH_Z; ncoor = 3; } else { with_z = WITHOUT_Z; ncoor = 2; } Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); db_init_string(&sql); if (G_get_overwrite()) { /* We don't want to delete the input table when overwriting the output * vector. */ char name[GNAME_MAX], mapset[GMAPSET_MAX]; if (!G_name_is_fully_qualified(outvect->answer, name, mapset)) { strcpy(name, outvect->answer); strcpy(mapset, G_mapset()); } Vect_set_open_level(1); /* no topo needed */ if (strcmp(mapset, G_mapset()) == 0 && G_find_vector2(name, mapset) && Vect_open_old(&Map, name, mapset) >= 0) { int num_dblinks; num_dblinks = Vect_get_num_dblinks(&Map); for (i = 0; i < num_dblinks; i++) { if ((fi = Vect_get_dblink(&Map, i)) != NULL && strcmp(fi->driver, driver_opt->answer) == 0 && strcmp(fi->database, database_opt->answer) == 0 && strcmp(fi->table, table_opt->answer) == 0) G_fatal_error(_("Vector map <%s> cannot be overwritten " "because input table <%s> is linked to " "this map."), outvect->answer, table_opt->answer); } Vect_close(&Map); } } if (Vect_open_new(&Map, outvect->answer, with_z) < 0) G_fatal_error(_("Unable to create vector map <%s>"), outvect->answer); Vect_set_error_handler_io(NULL, &Map); Vect_hist_command(&Map); fi = Vect_default_field_info(&Map, 1, NULL, GV_1TABLE); /* Open driver */ driver = db_start_driver_open_database(driver_opt->answer, database_opt->answer); if (driver == NULL) { G_fatal_error(_("Unable to open database <%s> by driver <%s>"), fi->database, fi->driver); } db_set_error_handler_driver(driver); /* check if target table already exists */ G_debug(3, "Output vector table <%s>, driver: <%s>, database: <%s>", outvect->answer, db_get_default_driver_name(), db_get_default_database_name()); if (!same_table_flag->answer && db_table_exists(db_get_default_driver_name(), db_get_default_database_name(), outvect->answer) == 1) G_fatal_error(_("Output vector map, table <%s> (driver: <%s>, database: <%s>) " "already exists"), outvect->answer, db_get_default_driver_name(), db_get_default_database_name()); if (keycol_opt->answer) { int coltype; coltype = db_column_Ctype(driver, table_opt->answer, keycol_opt->answer); if (coltype == -1) G_fatal_error(_("Column <%s> not found in table <%s>"), keycol_opt->answer, table_opt->answer); if (coltype != DB_C_TYPE_INT) G_fatal_error(_("Data type of key column must be integer")); } else { if (same_table_flag->answer) { G_fatal_error(_("Option <%s> must be specified when -%c flag is given"), keycol_opt->key, same_table_flag->key); } if (strcmp(db_get_default_driver_name(), "sqlite") != 0) G_fatal_error(_("Unable to define key column. This operation is not supported " "by <%s> driver. You need to define <%s> option."), fi->driver, keycol_opt->key); } /* Open select cursor */ sprintf(buf, "SELECT %s, %s", xcol_opt->answer, ycol_opt->answer); db_set_string(&sql, buf); if (with_z) { sprintf(buf, ", %s", zcol_opt->answer); db_append_string(&sql, buf); } if (keycol_opt->answer) { sprintf(buf, ", %s", keycol_opt->answer); db_append_string(&sql, buf); } sprintf(buf, " FROM %s", table_opt->answer); db_append_string(&sql, buf); if (where_opt->answer) { sprintf(buf, " WHERE %s", where_opt->answer); db_append_string(&sql, buf); } G_debug(2, "SQL: %s", db_get_string(&sql)); if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) { G_fatal_error(_("Unable to open select cursor: '%s'"), db_get_string(&sql)); } table = db_get_cursor_table(&cursor); nrows = db_get_num_rows(&cursor); G_debug(2, "%d points selected", nrows); count = cat = 0; G_message(_("Writing features...")); while (db_fetch(&cursor, DB_NEXT, &more) == DB_OK && more) { G_percent(count, nrows, 2); /* key column */ if (keycol_opt->answer) { column = db_get_table_column(table, with_z ? 3 : 2); ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column)); if (ctype != DB_C_TYPE_INT) G_fatal_error(_("Key column must be integer")); value = db_get_column_value(column); cat = db_get_value_int(value); } else { cat++; } /* coordinates */ for (i = 0; i < ncoor; i++) { column = db_get_table_column(table, i); ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column)); if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE) G_fatal_error(_("x/y/z column must be integer or double")); value = db_get_column_value(column); if (ctype == DB_C_TYPE_INT) coor[i] = (double)db_get_value_int(value); else coor[i] = db_get_value_double(value); } Vect_reset_line(Points); Vect_reset_cats(Cats); Vect_append_point(Points, coor[0], coor[1], coor[2]); Vect_cat_set(Cats, 1, cat); Vect_write_line(&Map, GV_POINT, Points, Cats); count++; } G_percent(1, 1, 1); /* close connection to input DB before copying attributes */ db_close_database_shutdown_driver(driver); /* Copy table */ if (!same_table_flag->answer) { G_message(_("Copying attributes...")); if (DB_FAILED == db_copy_table_where(driver_opt->answer, database_opt->answer, table_opt->answer, fi->driver, fi->database, fi->table, where_opt->answer)) { /* where can be NULL */ G_warning(_("Unable to copy table")); } else { Vect_map_add_dblink(&Map, 1, NULL, fi->table, keycol_opt->answer ? keycol_opt->answer : GV_KEY_COLUMN, fi->database, fi->driver); } if (!keycol_opt->answer) { /* TODO: implement for all DB drivers in generic way if * possible */ driver = db_start_driver_open_database(fi->driver, fi->database); if (driver == NULL) { G_fatal_error(_("Unable to open database <%s> by driver <%s>"), fi->database, fi->driver); } db_set_error_handler_driver(driver); /* add key column */ sprintf(buf, "ALTER TABLE %s ADD COLUMN %s INTEGER", fi->table, GV_KEY_COLUMN); db_set_string(&sql, buf); if (db_execute_immediate(driver, &sql) != DB_OK) { G_fatal_error(_("Unable to add key column <%s>: " "SERIAL type is not supported by <%s>"), GV_KEY_COLUMN, fi->driver); } /* update key column */ sprintf(buf, "UPDATE %s SET %s = _ROWID_", fi->table, GV_KEY_COLUMN); db_set_string(&sql, buf); if (db_execute_immediate(driver, &sql) != DB_OK) { G_fatal_error(_("Failed to update key column <%s>"), GV_KEY_COLUMN); } } } else { /* do not copy attributes, link original table */ Vect_map_add_dblink(&Map, 1, NULL, table_opt->answer, keycol_opt->answer ? keycol_opt->answer : GV_KEY_COLUMN, database_opt->answer, driver_opt->answer); } Vect_build(&Map); Vect_close(&Map); G_done_msg(_n("%d point written to vector map.", "%d points written to vector map.", count), count); return (EXIT_SUCCESS); }
/*! \brief Writes feature on level 1 (OGR interface) \param Map pointer to Map_info structure \param type feature type \param points pointer to line_pnts structure (feature geometry) \param cats pointer to line_cats structure (feature categories) \return feature offset into file \return -1 on error */ off_t V1_write_line_ogr(struct Map_info *Map, int type, const struct line_pnts *points, const struct line_cats *cats) { int i, cat, ret; struct field_info *Fi; struct Format_info_ogr *fInfo; OGRGeometryH Ogr_geometry; OGRFeatureH Ogr_feature; OGRFeatureDefnH Ogr_featuredefn; OGRwkbGeometryType Ogr_geom_type; if (!Map->fInfo.ogr.layer) { if (V2_open_new_ogr(Map, type) < 0) return -1; } cat = -1; /* no attributes to be written */ if (cats->n_cats > 0) { /* check for attributes */ Fi = Vect_get_dblink(Map, 0); if (Fi) { if (!Vect_cat_get(cats, Fi->number, &cat)) G_warning(_("No category defined for layer %d"), Fi->number); if (cats->n_cats > 1) { G_warning(_("Feature has more categories, using " "category %d (from layer %d)"), cat, cats->field[0]); } } } fInfo = &(Map->fInfo.ogr); Ogr_featuredefn = OGR_L_GetLayerDefn(fInfo->layer); Ogr_geom_type = OGR_FD_GetGeomType(Ogr_featuredefn); /* determine matching OGR feature geometry type */ /* NOTE: centroids are not supported in OGR, * pseudotopo holds virtual centroids */ /* NOTE: boundaries are not supported in OGR, * pseudotopo treats polygons as boundaries */ if (type & (GV_POINT | GV_KERNEL)) { if (Ogr_geom_type != wkbPoint && Ogr_geom_type != wkbPoint25D) { G_warning(_("Feature is not a point. Skipping.")); return -1; } Ogr_geometry = OGR_G_CreateGeometry(wkbPoint); } else if (type & GV_LINE) { if (Ogr_geom_type != wkbLineString && Ogr_geom_type != wkbLineString25D) { G_warning(_("Feature is not a line. Skipping.")); return -1; } Ogr_geometry = OGR_G_CreateGeometry(wkbLineString); } else if (type & GV_BOUNDARY) { if (Ogr_geom_type != wkbPolygon) { G_warning(_("Feature is not a polygon. Skipping.")); return -1; } Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon); } else if (type & GV_FACE) { if (Ogr_geom_type != wkbPolygon25D) { G_warning(_("Feature is not a face. Skipping.")); return -1; } Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon25D); } else { G_warning(_("Unsupported feature type (%d)"), type); return -1; } G_debug(3, "V1_write_line_ogr(): type = %d", type); if (Ogr_geom_type == wkbPolygon || Ogr_geom_type == wkbPolygon25D) { /* create exterior ring */ OGRGeometryH Ogr_ring; int npoints; npoints = points->n_points - 1; Ogr_ring = OGR_G_CreateGeometry(wkbLinearRing); if (points->x[0] != points->x[npoints] || points->y[0] != points->y[npoints] || points->z[0] != points->z[npoints]) { G_warning(_("Boundary is not closed. Skipping.")); return -1; } /* add points */ for (i = 0; i < points->n_points; i++) { OGR_G_AddPoint(Ogr_ring, points->x[i], points->y[i], points->z[i]); } OGR_G_AddGeometry(Ogr_geometry, Ogr_ring); } else { for (i = 0; i < points->n_points; i++) { OGR_G_AddPoint(Ogr_geometry, points->x[i], points->y[i], points->z[i]); } } G_debug(4, " n_points = %d", points->n_points); /* create feature & set geometry */ Ogr_feature = OGR_F_Create(Ogr_featuredefn); OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); /* write attributes */ if (cat > -1 && fInfo->dbdriver) { write_attributes(fInfo->dbdriver, cat, Fi, fInfo->layer, Ogr_feature); G_free(Fi); } /* write feature into layer */ ret = OGR_L_CreateFeature(fInfo->layer, Ogr_feature); /* update offset array */ if (fInfo->offset_num >= fInfo->offset_alloc) { fInfo->offset_alloc += 1000; fInfo->offset = (int *) G_realloc(fInfo->offset, fInfo->offset_alloc * sizeof(int)); } /* how to deal with OGRNullFID ? */ fInfo->offset[fInfo->offset_num] = (int)OGR_F_GetFID(Ogr_feature); /* destroy */ OGR_G_DestroyGeometry(Ogr_geometry); OGR_F_Destroy(Ogr_feature); if (ret != OGRERR_NONE) return -1; return fInfo->offset_num++; }
/*! \brief Copy tables linked to vector map. All if field = 0, or table defined by given field if field > 0 Notice, that if input map has no tables defined, it will copy nothing and return 0 (success). \param In input vector map \param[out] Out output vector map \param field layer number \return 0 on success \return -1 on error */ int Vect_copy_tables(const struct Map_info *In, struct Map_info *Out, int field) { int i, n, ret, type; struct field_info *Fi, *Fin; dbDriver *driver; n = Vect_get_num_dblinks(In); G_debug(2, "Vect_copy_tables(): copying %d tables", n); type = GV_1TABLE; if (n > 1) type = GV_MTABLE; for (i = 0; i < n; i++) { Fi = Vect_get_dblink(In, i); if (Fi == NULL) { G_warning(_("Database connection not defined for layer %d"), In->dblnk->field[i].number); return -1; } if (field > 0 && Fi->number != field) continue; Fin = Vect_default_field_info(Out, Fi->number, Fi->name, type); G_debug(2, "Copy drv:db:table '%s:%s:%s' to '%s:%s:%s'", Fi->driver, Fi->database, Fi->table, Fin->driver, Fin->database, Fin->table); ret = Vect_map_add_dblink(Out, Fi->number, Fi->name, Fin->table, Fi->key, Fin->database, Fin->driver); if (ret == -1) { G_warning(_("Unable to add database link for vector map <%s>"), Out->name); return -1; } ret = db_copy_table(Fi->driver, Fi->database, Fi->table, Fin->driver, Vect_subst_var(Fin->database, Out), Fin->table); if (ret == DB_FAILED) { G_warning(_("Unable to copy table <%s>"), Fin->table); return -1; } driver = db_start_driver_open_database(Fin->driver, Vect_subst_var(Fin->database, Out)); if (driver == NULL) { G_warning(_("Unable to open database <%s> by driver <%s>"), Fin->database, Fin->driver); } else { if (db_create_index2(driver, Fin->table, Fi->key) != DB_OK) G_warning(_("Unable to create index for table <%s>, key <%s>"), Fin->table, Fin->key); db_close_database_shutdown_driver(driver); } } return 0; }
/*! \brief Delete vector map including attribute tables \param map vector map name \return -1 error \return 0 success */ int Vect_delete(const char *map) { int i, n, ret; struct Map_info Map; struct field_info *Fi; char buf[GPATH_MAX]; DIR *dir; struct dirent *ent; const char *tmp; char xname[GNAME_MAX], xmapset[GMAPSET_MAX]; G_debug(3, "Delete vector '%s'", map); /* remove mapset from fully qualified name */ if (G_name_is_fully_qualified(map, xname, xmapset)) { map = xname; } if (map == NULL || strlen(map) == 0) { G_warning(_("Invalid vector map name <%s>"), map ? map : "null"); return -1; } sprintf(buf, "%s/%s/%s/%s/%s/%s", G_gisdbase(), G_location(), G_mapset(), GV_DIRECTORY, map, GV_DBLN_ELEMENT); G_debug(1, "dbln file: %s", buf); if (access(buf, F_OK) == 0) { /* Open input */ Vect_set_open_level(1); /* Topo not needed */ ret = Vect_open_old_head(&Map, map, G_mapset()); if (ret < 1) { G_warning(_("Unable to open header file for vector map <%s>"), map); return -1; } /* Delete all tables, NOT external (OGR) */ if (Map.format == GV_FORMAT_NATIVE) { n = Vect_get_num_dblinks(&Map); for (i = 0; i < n; i++) { Fi = Vect_get_dblink(&Map, i); if (Fi == NULL) { G_warning(_("Database connection not defined for layer %d"), Map.dblnk->field[i].number); Vect_close(&Map); return -1; } G_debug(3, "Delete drv:db:table '%s:%s:%s'", Fi->driver, Fi->database, Fi->table); ret = db_table_exists(Fi->driver, Fi->database, Fi->table); if (ret == -1) { G_warning(_("Unable to find table <%s> linked to vector map <%s>"), Fi->table, map); Vect_close(&Map); return -1; } if (ret == 1) { ret = db_delete_table(Fi->driver, Fi->database, Fi->table); if (ret == DB_FAILED) { G_warning(_("Unable to delete table <%s>"), Fi->table); Vect_close(&Map); return -1; } } else { G_warning(_("Table <%s> linked to vector map <%s> does not exist"), Fi->table, map); } } } Vect_close(&Map); } /* Delete all files from vector/name directory */ sprintf(buf, "%s/%s/vector/%s", G_location_path(), G_mapset(), map); G_debug(3, "opendir '%s'", buf); dir = opendir(buf); if (dir == NULL) { G_warning(_("Unable to open directory '%s'"), buf); return -1; } while ((ent = readdir(dir))) { G_debug(3, "file = '%s'", ent->d_name); if ((strcmp(ent->d_name, ".") == 0) || (strcmp(ent->d_name, "..") == 0)) continue; sprintf(buf, "%s/%s/vector/%s/%s", G_location_path(), G_mapset(), map, ent->d_name); G_debug(3, "delete file '%s'", buf); ret = unlink(buf); if (ret == -1) { G_warning(_("Unable to delete file '%s'"), buf); closedir(dir); return -1; } } closedir(dir); /* NFS can create .nfsxxxxxxxx files for those deleted * -> we have to move the directory to ./tmp before it is deleted */ sprintf(buf, "%s/%s/vector/%s", G_location_path(), G_mapset(), map); tmp = G_tempfile(); G_debug(3, "rename '%s' to '%s'", buf, tmp); ret = rename(buf, tmp); if (ret == -1) { G_warning(_("Unable to rename directory '%s' to '%s'"), buf, tmp); return -1; } G_debug(3, "remove directory '%s'", tmp); /* Warning: remove() fails on Windows */ ret = rmdir(tmp); if (ret == -1) { G_warning(_("Unable to remove directory '%s'"), tmp); return -1; } return 0; }
/*! \brief Rename a map. Attribute tables are created in the same database where input tables were stored. The original format (native/OGR) is used. Old map ('out') is deleted!!! \param in input vector map name \param out output vector map name \return -1 error \return 0 success */ int Vect_rename(const char *in, const char *out) { int i, n, ret, type; struct Map_info Map; struct field_info *Fin, *Fout; int *fields; dbDriver *driver; char xname[GNAME_MAX], xmapset[GMAPSET_MAX]; G_debug(2, "Rename vector '%s' to '%s'", in, out); /* check for [A-Za-z][A-Za-z0-9_]* in name */ if (Vect_legal_filename(out) < 0) G_fatal_error(_("Vector map name is not SQL compliant")); /* Delete old vector if it exists */ if (G_find_vector2(out, G_mapset())) { G_warning(_("Vector map <%s> already exists and will be overwritten"), out); Vect_delete(out); } /* remove mapset from fully qualified name */ if (G_name_is_fully_qualified(in, xname, xmapset)) { in = xname; } /* Move the directory */ ret = G_rename(GV_DIRECTORY, in, out); if (ret == 0) { G_warning(_("Vector map <%s> not found"), in); return -1; } else if (ret == -1) { G_warning(_("Unable to copy vector map <%s> to <%s>"), in, out); return -1; } /* Rename all tables if the format is native */ Vect_set_open_level(1); Vect_open_update_head(&Map, out, G_mapset()); if (Map.format != GV_FORMAT_NATIVE) { /* Done */ Vect_close(&Map); return 0; } /* Copy tables */ n = Vect_get_num_dblinks(&Map); type = GV_1TABLE; if (n > 1) type = GV_MTABLE; /* Make the list of fields */ fields = (int *)G_malloc(n * sizeof(int)); for (i = 0; i < n; i++) { Fin = Vect_get_dblink(&Map, i); fields[i] = Fin->number; } for (i = 0; i < n; i++) { G_debug(3, "field[%d] = %d", i, fields[i]); Fin = Vect_get_field(&Map, fields[i]); if (Fin == NULL) { G_warning(_("Database connection not defined for layer %d"), fields[i]); Vect_close(&Map); return -1; } Fout = Vect_default_field_info(&Map, Fin->number, Fin->name, type); G_debug(3, "Copy drv:db:table '%s:%s:%s' to '%s:%s:%s'", Fin->driver, Fin->database, Fin->table, Fout->driver, Fout->database, Fout->table); /* TODO: db_rename_table instead of db_copy_table */ ret = db_copy_table(Fin->driver, Fin->database, Fin->table, Fout->driver, Vect_subst_var(Fout->database, &Map), Fout->table); if (ret == DB_FAILED) { G_warning(_("Unable to copy table <%s>"), Fin->table); Vect_close(&Map); return -1; } /* Change the link */ Vect_map_del_dblink(&Map, Fin->number); Vect_map_add_dblink(&Map, Fout->number, Fout->name, Fout->table, Fin->key, Fout->database, Fout->driver); /* Delete old table */ ret = db_delete_table(Fin->driver, Fin->database, Fin->table); if (ret == DB_FAILED) { G_warning(_("Unable to delete table <%s>"), Fin->table); Vect_close(&Map); return -1; } driver = db_start_driver_open_database(Fout->driver, Vect_subst_var(Fout->database, &Map)); if (driver == NULL) { G_warning(_("Unable to open database <%s> by driver <%s>"), Fout->database, Fout->driver); } else { if (db_create_index2(driver, Fout->table, Fin->key) != DB_OK) G_warning(_("Unable to create index for table <%s>, key <%s>"), Fout->table, Fout->key); db_close_database_shutdown_driver(driver); } } Vect_close(&Map); free(fields); return 0; }
/*! \brief Copy a map including attribute tables Old vector is deleted \param in input vector map name \param mapset mapset name \param out output vector map name \return -1 error \return 0 success */ int Vect_copy(const char *in, const char *mapset, const char *out) { int i, n, ret, type; struct Map_info In, Out; struct field_info *Fi, *Fin; char old_path[GPATH_MAX], new_path[GPATH_MAX], buf[GPATH_MAX]; const char *files[] = { GV_FRMT_ELEMENT, GV_COOR_ELEMENT, GV_HEAD_ELEMENT, GV_HIST_ELEMENT, GV_TOPO_ELEMENT, GV_SIDX_ELEMENT, GV_CIDX_ELEMENT, NULL }; const char *inmapset; char xname[GNAME_MAX], xmapset[GMAPSET_MAX]; dbDriver *driver; G_debug(2, "Copy vector '%s' in '%s' to '%s'", in, mapset, out); /* check for [A-Za-z][A-Za-z0-9_]* in name */ if (Vect_legal_filename(out) < 0) G_fatal_error(_("Vector map name is not SQL compliant")); inmapset = G_find_vector2(in, mapset); if (!inmapset) { G_warning(_("Unable to find vector map <%s> in <%s>"), in, mapset); return -1; } mapset = inmapset; /* remove mapset from fully qualified name, confuses G_file_name() */ if (G_name_is_fully_qualified(in, xname, xmapset)) { in = xname; } /* Delete old vector if it exists */ if (G_find_vector2(out, G_mapset())) { G_warning(_("Vector map <%s> already exists and will be overwritten"), out); ret = Vect_delete(out); if (ret != 0) { G_warning(_("Unable to delete vector map <%s>"), out); return -1; } } /* Copy the directory */ G__make_mapset_element(GV_DIRECTORY); sprintf(buf, "%s/%s", GV_DIRECTORY, out); G__make_mapset_element(buf); i = 0; while (files[i]) { sprintf(buf, "%s/%s", in, files[i]); G_file_name(old_path, GV_DIRECTORY, buf, mapset); sprintf(buf, "%s/%s", out, files[i]); G_file_name(new_path, GV_DIRECTORY, buf, G_mapset()); if (access(old_path, F_OK) == 0) { /* file exists? */ G_debug(2, "copy %s to %s", old_path, new_path); if (copy_file(old_path, new_path)) { G_warning(_("Unable to copy vector map <%s> to <%s>"), old_path, new_path); } } i++; } G_file_name(old_path, GV_DIRECTORY, in, mapset); G_file_name(new_path, GV_DIRECTORY, out, G_mapset()); /* Open input */ Vect_set_open_level(1); Vect_open_old_head(&In, in, mapset); if (In.format != GV_FORMAT_NATIVE) { /* Done */ Vect_close(&In); return 0; } /* Open output */ Vect_set_open_level(1); Vect_open_update_head(&Out, out, G_mapset()); /* Copy tables */ n = Vect_get_num_dblinks(&In); type = GV_1TABLE; if (n > 1) type = GV_MTABLE; for (i = 0; i < n; i++) { Fi = Vect_get_dblink(&In, i); if (Fi == NULL) { G_warning(_("Database connection not defined for layer %d"), In.dblnk->field[i].number); Vect_close(&In); Vect_close(&Out); return -1; } Fin = Vect_default_field_info(&Out, Fi->number, Fi->name, type); G_debug(3, "Copy drv:db:table '%s:%s:%s' to '%s:%s:%s'", Fi->driver, Fi->database, Fi->table, Fin->driver, Fin->database, Fin->table); Vect_map_add_dblink(&Out, Fi->number, Fi->name, Fin->table, Fi->key, Fin->database, Fin->driver); ret = db_copy_table(Fi->driver, Fi->database, Fi->table, Fin->driver, Vect_subst_var(Fin->database, &Out), Fin->table); if (ret == DB_FAILED) { G_warning(_("Unable to copy table <%s>"), Fin->table); Vect_close(&In); Vect_close(&Out); return -1; } driver = db_start_driver_open_database(Fin->driver, Vect_subst_var(Fin->database, &Out)); if (driver == NULL) { G_warning(_("Unable to open database <%s> by driver <%s>"), Fin->database, Fin->driver); } else { if (db_create_index2(driver, Fin->table, Fi->key) != DB_OK) G_warning(_("Unable to create index for table <%s>, key <%s>"), Fi->table, Fi->key); db_close_database_shutdown_driver(driver); } } Vect_close(&In); Vect_close(&Out); return 0; }
/*! \brief Write OGR feature \param Map pointer to Map_info structure \param type feature type (GV_POINT, GV_LINE, ...) \param bpoints feature geometry \param cats feature categories \param ipoints isle geometry for polygons on NULL \param nisles number of isles \return feature offset into file \return -1 on error */ off_t write_feature(struct Map_info *Map, int type, const struct line_pnts **p_points, int nparts, const struct line_cats *cats) { int i, cat, ret; struct field_info *Fi; const struct line_pnts *points; struct Format_info_ogr *ogr_info; struct Format_info_offset *offset_info; off_t offset; OGRGeometryH Ogr_geometry; OGRFeatureH Ogr_feature; OGRFeatureDefnH Ogr_featuredefn; OGRwkbGeometryType Ogr_geom_type; ogr_info = &(Map->fInfo.ogr); offset_info = &(ogr_info->offset); if (nparts < 1) return -1; points = p_points[0]; /* feature geometry */ if (!ogr_info->layer) { /* create OGR layer if doesn't exist */ if (create_ogr_layer(Map, type) < 0) return -1; } if (!points) return 0; cat = -1; /* no attributes to be written */ if (cats->n_cats > 0 && Vect_get_num_dblinks(Map) > 0) { /* check for attributes */ Fi = Vect_get_dblink(Map, 0); if (Fi) { if (!Vect_cat_get(cats, Fi->number, &cat)) G_warning(_("No category defined for layer %d"), Fi->number); if (cats->n_cats > 1) { G_warning(_("Feature has more categories, using " "category %d (from layer %d)"), cat, cats->field[0]); } } } Ogr_featuredefn = OGR_L_GetLayerDefn(ogr_info->layer); Ogr_geom_type = OGR_FD_GetGeomType(Ogr_featuredefn); /* determine matching OGR feature geometry type */ if (type & (GV_POINT | GV_KERNEL)) { if (Ogr_geom_type != wkbPoint && Ogr_geom_type != wkbPoint25D) { G_warning(_("Feature is not a point. Skipping.")); return -1; } Ogr_geometry = OGR_G_CreateGeometry(wkbPoint); } else if (type & GV_LINE) { if (Ogr_geom_type != wkbLineString && Ogr_geom_type != wkbLineString25D) { G_warning(_("Feature is not a line. Skipping.")); return -1; } Ogr_geometry = OGR_G_CreateGeometry(wkbLineString); } else if (type & GV_BOUNDARY) { if (Ogr_geom_type != wkbPolygon) { G_warning(_("Feature is not a polygon. Skipping.")); return -1; } Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon); } else if (type & GV_FACE) { if (Ogr_geom_type != wkbPolygon25D) { G_warning(_("Feature is not a face. Skipping.")); return -1; } Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon25D); } else { G_warning(_("Unsupported feature type (%d)"), type); return -1; } G_debug(3, "V1_write_line_ogr(): type = %d", type); if (Ogr_geom_type == wkbPolygon || Ogr_geom_type == wkbPolygon25D) { int iring, npoints; /* add rings (first is exterior ring) */ for (iring = 0; iring < nparts; iring++) { OGRGeometryH Ogr_ring; points = p_points[iring]; npoints = points->n_points - 1; Ogr_ring = OGR_G_CreateGeometry(wkbLinearRing); if (points->x[0] != points->x[npoints] || points->y[0] != points->y[npoints] || points->z[0] != points->z[npoints]) { G_warning(_("Boundary is not closed. Feature skipped.")); return -1; } /* add points */ for (i = 0; i < npoints; i++) { OGR_G_AddPoint(Ogr_ring, points->x[i], points->y[i], points->z[i]); } G_debug(4, " ring(%d): n_points = %d", iring, npoints); OGR_G_AddGeometry(Ogr_geometry, Ogr_ring); } } else { for (i = 0; i < points->n_points; i++) { OGR_G_AddPoint(Ogr_geometry, points->x[i], points->y[i], points->z[i]); } G_debug(4, " n_points = %d", points->n_points); } /* create feature & set geometry */ Ogr_feature = OGR_F_Create(Ogr_featuredefn); OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); /* write attributes */ if (cat > -1 && ogr_info->dbdriver) { if (0 > write_attributes(ogr_info->dbdriver, cat, Fi, ogr_info->layer, Ogr_feature)) G_warning(_("Unable to writes feature attributes")); G_free(Fi); } /* write feature into layer */ ret = OGR_L_CreateFeature(ogr_info->layer, Ogr_feature); /* update offset array */ if (offset_info->array_num >= offset_info->array_alloc) { offset_info->array_alloc += 1000; offset_info->array = (int *) G_realloc(offset_info->array, offset_info->array_alloc * sizeof(int)); } offset = offset_info->array_num; offset_info->array[offset_info->array_num++] = (int) OGR_F_GetFID(Ogr_feature); if (Ogr_geom_type == wkbPolygon || Ogr_geom_type == wkbPolygon25D) { /* register exterior ring in offset array */ offset_info->array[offset_info->array_num++] = 0; } /* destroy */ OGR_G_DestroyGeometry(Ogr_geometry); OGR_F_Destroy(Ogr_feature); if (ret != OGRERR_NONE) return -1; G_debug(3, "write_feature(): -> offset = %lu offset_num = %d cat = %d", (unsigned long) offset, offset_info->array_num, cat); return offset; }
/*! \brief Create new OGR layer in given OGR datasource (internal use only) V1_open_new_ogr() is required to be called before this function. List of currently supported types: - GV_POINT (wkbPoint) - GV_LINE (wkbLineString) - GV_BOUNDARY (wkb_Polygon) \param[in,out] Map pointer to Map_info structure \param type feature type (GV_POINT, GV_LINE, ...) \return 0 success \return -1 error */ int create_ogr_layer(struct Map_info *Map, int type) { int ndblinks; OGRLayerH Ogr_layer; OGRSpatialReferenceH Ogr_spatial_ref; struct field_info *Fi; struct Key_Value *projinfo, *projunits; struct Format_info_ogr *ogr_info; OGRwkbGeometryType Ogr_geom_type; char **Ogr_layer_options; ogr_info = &(Map->fInfo.ogr); if (!ogr_info->driver_name || !ogr_info->layer_name || !ogr_info->ds) return -1; /* get spatial reference */ projinfo = G_get_projinfo(); projunits = G_get_projunits(); Ogr_spatial_ref = GPJ_grass_to_osr(projinfo, projunits); G_free_key_value(projinfo); G_free_key_value(projunits); /* determine geometry type */ switch(type) { case GV_POINT: Ogr_geom_type = wkbPoint; break; case GV_LINE: Ogr_geom_type = wkbLineString; break; case GV_BOUNDARY: Ogr_geom_type = wkbPolygon; break; default: G_warning(_("Unsupported geometry type (%d)"), type); return -1; } /* check creation options */ Ogr_layer_options = ogr_info->layer_options; if (Vect_is_3d(Map)) { if (strcmp(ogr_info->driver_name, "PostgreSQL") == 0) { Ogr_layer_options = CSLSetNameValue(Ogr_layer_options, "DIM", "3"); } } else { if (strcmp(ogr_info->driver_name, "PostgreSQL") == 0) { Ogr_layer_options = CSLSetNameValue(Ogr_layer_options, "DIM", "2"); } } /* create new OGR layer */ Ogr_layer = OGR_DS_CreateLayer(ogr_info->ds, ogr_info->layer_name, Ogr_spatial_ref, Ogr_geom_type, Ogr_layer_options); CSLDestroy(Ogr_layer_options); if (!Ogr_layer) { G_warning(_("Unable to create OGR layer <%s> in '%s'"), ogr_info->layer_name, ogr_info->dsn); return -1; } ogr_info->layer = Ogr_layer; ndblinks = Vect_get_num_dblinks(Map); if (ndblinks > 0) { /* write also attributes */ Fi = Vect_get_dblink(Map, 0); if (Fi) { if (ndblinks > 1) G_warning(_("More layers defined, using driver <%s> and " "database <%s>"), Fi->driver, Fi->database); ogr_info->dbdriver = create_table(ogr_info->layer, Fi); G_free(Fi); } else G_warning(_("Database connection not defined. " "Unable to write attributes.")); } if (OGR_L_TestCapability(ogr_info->layer, OLCTransactions)) OGR_L_StartTransaction(ogr_info->layer); return 0; }
int main(int argc, char **argv) { int i; int **cats, *ncats, nfields, *fields; struct Flag *line_flag; /* struct Flag *all_flag; */ struct Option *in_opt, *out_opt; struct Flag *table_flag; struct GModule *module; struct line_pnts *Points; struct line_cats *Cats; int node, nnodes; COOR *coor; int ncoor, acoor; int line, nlines, type, ctype, area, nareas; int err_boundaries, err_centr_out, err_centr_dupl, err_nocentr; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("geometry")); G_add_keyword(_("triangulation")); module->description = _("Creates a Voronoi diagram from an input vector " "map containing points or centroids."); in_opt = G_define_standard_option(G_OPT_V_INPUT); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); /* all_flag = G_define_flag (); all_flag->key = 'a'; all_flag->description = _("Use all points (do not limit to current region)"); */ line_flag = G_define_flag(); line_flag->key = 'l'; line_flag->description = _("Output tessellation as a graph (lines), not areas"); table_flag = G_define_flag(); table_flag->key = 't'; table_flag->description = _("Do not create attribute table"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); if (line_flag->answer) Type = GV_LINE; else Type = GV_BOUNDARY; All = 0; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); /* open files */ Vect_set_open_level(2); Vect_open_old(&In, in_opt->answer, ""); if (Vect_open_new(&Out, out_opt->answer, 0) < 0) G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); /* initialize working region */ G_get_window(&Window); Vect_region_box(&Window, &Box); Box.T = 0.5; Box.B = -0.5; freeinit(&sfl, sizeof(struct Site)); G_message(_("Reading sites...")); readsites(); siteidx = 0; geominit(); triangulate = 0; plot = 0; debug = 0; G_message(_("Voronoi triangulation...")); voronoi(triangulate, nextone); /* Close free ends by current region */ Vect_build_partial(&Out, GV_BUILD_BASE); ncoor = 0; acoor = 100; coor = (COOR *) G_malloc(sizeof(COOR) * acoor); nnodes = Vect_get_num_nodes(&Out); for (node = 1; node <= nnodes; node++) { double x, y; if (Vect_get_node_n_lines(&Out, node) < 2) { /* add coordinates */ Vect_get_node_coor(&Out, node, &x, &y, NULL); if (ncoor == acoor - 5) { /* always space for 5 region corners */ acoor += 100; coor = (COOR *) G_realloc(coor, sizeof(COOR) * acoor); } coor[ncoor].x = x; coor[ncoor].y = y; ncoor++; } } /* Add region corners */ coor[ncoor].x = Box.W; coor[ncoor].y = Box.S; ncoor++; coor[ncoor].x = Box.E; coor[ncoor].y = Box.S; ncoor++; coor[ncoor].x = Box.E; coor[ncoor].y = Box.N; ncoor++; coor[ncoor].x = Box.W; coor[ncoor].y = Box.N; ncoor++; /* Sort */ qsort(coor, ncoor, sizeof(COOR), (void *)cmp); /* add last (first corner) */ coor[ncoor].x = Box.W; coor[ncoor].y = Box.S; ncoor++; for (i = 1; i < ncoor; i++) { if (coor[i].x == coor[i - 1].x && coor[i].y == coor[i - 1].y) continue; /* duplicate */ Vect_reset_line(Points); Vect_append_point(Points, coor[i].x, coor[i].y, 0.0); Vect_append_point(Points, coor[i - 1].x, coor[i - 1].y, 0.0); Vect_write_line(&Out, Type, Points, Cats); } G_free(coor); /* Copy input points as centroids */ nfields = Vect_cidx_get_num_fields(&In); cats = (int **)G_malloc(nfields * sizeof(int *)); ncats = (int *)G_malloc(nfields * sizeof(int)); fields = (int *)G_malloc(nfields * sizeof(int)); for (i = 0; i < nfields; i++) { ncats[i] = 0; cats[i] = (int *)G_malloc(Vect_cidx_get_num_cats_by_index(&In, i) * sizeof(int)); fields[i] = Vect_cidx_get_field_number(&In, i); } if (line_flag->answer) ctype = GV_POINT; else ctype = GV_CENTROID; nlines = Vect_get_num_lines(&In); G_message(_("Writing sites to output...")); for (line = 1; line <= nlines; line++) { G_percent(line, nlines, 2); type = Vect_read_line(&In, Points, Cats, line); if (!(type & GV_POINTS)) continue; if (!Vect_point_in_box(Points->x[0], Points->y[0], 0.0, &Box)) continue; Vect_write_line(&Out, ctype, Points, Cats); for (i = 0; i < Cats->n_cats; i++) { int f, j; f = -1; for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == Cats->field[i]) { f = j; break; } } if (f > -1) { cats[f][ncats[f]] = Cats->cat[i]; ncats[f]++; } } } /* Copy tables */ if (!(table_flag->answer)) { int ttype, ntabs = 0; struct field_info *IFi, *OFi; /* Number of output tabs */ for (i = 0; i < Vect_get_num_dblinks(&In); i++) { int f, j; IFi = Vect_get_dblink(&In, i); f = -1; for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == IFi->number) { f = j; break; } } if (f > -1) { if (ncats[f] > 0) ntabs++; } } if (ntabs > 1) ttype = GV_MTABLE; else ttype = GV_1TABLE; for (i = 0; i < nfields; i++) { int ret; if (fields[i] == 0) continue; G_message(_("Layer %d"), fields[i]); /* Make a list of categories */ IFi = Vect_get_field(&In, fields[i]); if (!IFi) { /* no table */ G_message(_("No table")); continue; } OFi = Vect_default_field_info(&Out, IFi->number, IFi->name, ttype); ret = db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table, OFi->driver, Vect_subst_var(OFi->database, &Out), OFi->table, IFi->key, cats[i], ncats[i]); if (ret == DB_FAILED) { G_warning(_("Cannot copy table")); } else { Vect_map_add_dblink(&Out, OFi->number, OFi->name, OFi->table, IFi->key, OFi->database, OFi->driver); } } } Vect_close(&In); /* cleaning part 1: count errors */ Vect_build_partial(&Out, GV_BUILD_CENTROIDS); err_boundaries = err_centr_out = err_centr_dupl = err_nocentr = 0; nlines = Vect_get_num_lines(&Out); for (line = 1; line <= nlines; line++) { if (!Vect_line_alive(&Out, line)) continue; type = Vect_get_line_type(&Out, line); if (type == GV_BOUNDARY) { int left, right; Vect_get_line_areas(&Out, line, &left, &right); if (left == 0 || right == 0) { G_debug(3, "line = %d left = %d right = %d", line, left, right); err_boundaries++; } } if (type == GV_CENTROID) { area = Vect_get_centroid_area(&Out, line); if (area == 0) err_centr_out++; else if (area < 0) err_centr_dupl++; } } err_nocentr = 0; nareas = Vect_get_num_areas(&Out); for (area = 1; area <= nareas; area++) { if (!Vect_area_alive(&Out, area)) continue; line = Vect_get_area_centroid(&Out, area); if (line == 0) err_nocentr++; } /* cleaning part 2: snap */ if (err_nocentr || err_centr_dupl || err_centr_out) { int nmod; G_important_message(_("Output needs topological cleaning")); Vect_snap_lines(&Out, GV_BOUNDARY, 1e-7, NULL); do { Vect_break_lines(&Out, GV_BOUNDARY, NULL); Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL); nmod = Vect_clean_small_angles_at_nodes(&Out, GV_BOUNDARY, NULL); } while (nmod > 0); err_boundaries = 0; nlines = Vect_get_num_lines(&Out); for (line = 1; line <= nlines; line++) { if (!Vect_line_alive(&Out, line)) continue; type = Vect_get_line_type(&Out, line); if (type == GV_BOUNDARY) { int left, right; Vect_get_line_areas(&Out, line, &left, &right); if (left == 0 || right == 0) { G_debug(3, "line = %d left = %d right = %d", line, left, right); err_boundaries++; } } } } /* cleaning part 3: remove remaining incorrect boundaries */ if (err_boundaries) { G_important_message(_("Removing incorrect boundaries from output")); nlines = Vect_get_num_lines(&Out); for (line = 1; line <= nlines; line++) { if (!Vect_line_alive(&Out, line)) continue; type = Vect_get_line_type(&Out, line); if (type == GV_BOUNDARY) { int left, right; Vect_get_line_areas(&Out, line, &left, &right); /* &&, not ||, no typo */ if (left == 0 && right == 0) { G_debug(3, "line = %d left = %d right = %d", line, left, right); Vect_delete_line(&Out, line); } } } } /* build clean topology */ Vect_build_partial(&Out, GV_BUILD_NONE); Vect_build(&Out); Vect_close(&Out); G_done_msg(" "); exit(EXIT_SUCCESS); }
/* TODO: The collection of categories is horrible in current version! * Everything repeats many times. We need some data structure * implementing set! */ int copy_tables_by_cats(struct Map_info *In, struct Map_info *Out) { /* this is the (mostly) code from v.extract, it should be moved to * some vector library (probably) */ int nlines, line, nfields; int ttype, ntabs = 0; struct field_info *IFi, *OFi; struct line_cats *Cats; int **ocats, *nocats, *fields; int i; /* Collect list of output cats */ Cats = Vect_new_cats_struct(); nfields = Vect_cidx_get_num_fields(In); ocats = (int **)G_malloc(nfields * sizeof(int *)); nocats = (int *)G_malloc(nfields * sizeof(int)); fields = (int *)G_malloc(nfields * sizeof(int)); for (i = 0; i < nfields; i++) { nocats[i] = 0; ocats[i] = (int *)G_malloc(Vect_cidx_get_num_cats_by_index(In, i) * sizeof(int)); fields[i] = Vect_cidx_get_field_number(In, i); } nlines = Vect_get_num_lines(Out); for (line = 1; line <= nlines; line++) { Vect_read_line(Out, NULL, Cats, line); for (i = 0; i < Cats->n_cats; i++) { int f = 0, j; for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == Cats->field[i]) { f = j; break; } } ocats[f][nocats[f]] = Cats->cat[i]; nocats[f]++; } } /* Copy tables */ G_message(_("Writing attributes...")); /* Number of output tabs */ for (i = 0; i < Vect_get_num_dblinks(In); i++) { int j, f = -1; IFi = Vect_get_dblink(In, i); for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == IFi->number) { f = j; break; } } if (f >= 0 && nocats[f] > 0) ntabs++; } if (ntabs > 1) ttype = GV_MTABLE; else ttype = GV_1TABLE; for (i = 0; i < nfields; i++) { int ret; if (fields[i] == 0) continue; if (nocats[i] == 0) continue; /* if ( fields[i] == field && new_cat != -1 ) continue; */ G_message(_("Layer %d"), fields[i]); /* Make a list of categories */ IFi = Vect_get_field(In, fields[i]); if (!IFi) { /* no table */ G_warning(_("Database connection not defined for layer %d"), fields[i]); continue; } OFi = Vect_default_field_info(Out, IFi->number, IFi->name, ttype); ret = db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table, OFi->driver, Vect_subst_var(OFi->database, Out), OFi->table, IFi->key, ocats[i], nocats[i]); if (ret == DB_FAILED) { G_warning(_("Unable to copy table <%s>"), IFi->table); } else { Vect_map_add_dblink(Out, OFi->number, OFi->name, OFi->table, IFi->key, OFi->database, OFi->driver); } } for (i = 0; i < nfields; i++) G_free(ocats[i]); G_free(ocats); G_free(nocats); G_free(fields); return 1; }
int main(int argc, char *argv[]) { int i, iopt; int operator; int aline, nalines, nskipped; int ltype, itype[2], ifield[2]; int **cats, *ncats, nfields, *fields; char *mapset[2], *pre[2]; struct GModule *module; struct GParm parm; struct GFlag flag; struct Map_info In[2], Out; struct field_info *IFi, *OFi; struct line_pnts *APoints, *BPoints; struct line_cats *ACats, *BCats; int *ALines; /* List of lines: 0 do not output, 1 - write to output */ struct ilist *List, *TmpList, *BoundList; G_gisinit(argv[0]); pre[0] = "a"; pre[1] = "b"; module = G_define_module(); module->keywords = _("vector, spatial query"); module->description = _("Selects features from vector map (A) by features from other vector map (B)."); parse_options(&parm, &flag); if (G_parser(argc, argv)) exit(EXIT_FAILURE); if (parm.operator->answer[0] == 'e') operator = OP_EQUALS; else if (parm.operator->answer[0] == 'd') { /* operator = OP_DISJOINT; */ operator = OP_INTERSECTS; flag.reverse->answer = YES; } else if (parm.operator->answer[0] == 'i') operator = OP_INTERSECTS; else if (parm.operator->answer[0] == 't') operator = OP_TOUCHES; else if (parm.operator->answer[0] == 'c' && parm.operator->answer[1] == 'r') operator = OP_CROSSES; else if (parm.operator->answer[0] == 'w') operator = OP_WITHIN; else if (parm.operator->answer[0] == 'c' && parm.operator->answer[1] == 'o') operator = OP_CONTAINS; else if (parm.operator->answer[0] == 'o') { if (strcmp(parm.operator->answer, "overlaps") == 0) operator = OP_OVERLAPS; else operator = OP_OVERLAP; } else if (parm.operator->answer[0] == 'r') operator = OP_RELATE; else G_fatal_error(_("Unknown operator")); if (operator == OP_RELATE && !parm.relate->answer) { G_fatal_error(_("Required parameter <%s> not set"), parm.relate->key); } for (iopt = 0; iopt < 2; iopt++) { itype[iopt] = Vect_option_to_types(parm.type[iopt]); ifield[iopt] = atoi(parm.field[iopt]->answer); Vect_check_input_output_name(parm.input[iopt]->answer, parm.output->answer, GV_FATAL_EXIT); if ((mapset[iopt] = G_find_vector2(parm.input[iopt]->answer, NULL)) == NULL) { G_fatal_error(_("Vector map <%s> not found"), parm.input[iopt]->answer); } Vect_set_open_level(2); Vect_open_old(&(In[iopt]), parm.input[iopt]->answer, mapset[iopt]); } /* Read field info */ IFi = Vect_get_field(&(In[0]), ifield[0]); APoints = Vect_new_line_struct(); BPoints = Vect_new_line_struct(); ACats = Vect_new_cats_struct(); BCats = Vect_new_cats_struct(); List = Vect_new_list(); TmpList = Vect_new_list(); BoundList = Vect_new_list(); /* Open output */ Vect_open_new(&Out, parm.output->answer, Vect_is_3d(&(In[0]))); Vect_set_map_name(&Out, _("Output from v.select")); Vect_set_person(&Out, G_whoami()); Vect_copy_head_data(&(In[0]), &Out); Vect_hist_copy(&(In[0]), &Out); Vect_hist_command(&Out); nskipped = 0; nalines = Vect_get_num_lines(&(In[0])); #ifdef HAVE_GEOS initGEOS(G_message, G_fatal_error); GEOSGeometry *AGeom = NULL; #else void *AGeom = NULL; #endif /* Alloc space for input lines array */ ALines = (int *)G_calloc(nalines + 1, sizeof(int)); G_message(_("Building spatial index...")); Vect_build_spatial_index(&In[0]); Vect_build_spatial_index(&In[1]); /* Lines in A. Go through all lines and mark those that meets condition */ if (itype[0] & (GV_POINTS | GV_LINES)) { G_message(_("Processing features...")); for (aline = 1; aline <= nalines; aline++) { BOUND_BOX abox; G_debug(3, "aline = %d", aline); G_percent(aline, nalines, 2); /* must be before any continue */ /* Check category */ if (!flag.cat->answer && Vect_get_line_cat(&(In[0]), aline, ifield[0]) < 0) { nskipped++; continue; } /* Read line and check type */ if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS AGeom = Vect_read_line_geos(&(In[0]), aline, <ype); #endif if (!(ltype & (GV_POINT | GV_LINE))) continue; if (!AGeom) G_fatal_error(_("Unable to read line id %d from vector map <%s>"), aline, Vect_get_full_name(&(In[0]))); } else { ltype = Vect_read_line(&(In[0]), APoints, NULL, aline); } if (!(ltype & itype[0])) continue; Vect_get_line_box(&(In[0]), aline, &abox); abox.T = PORT_DOUBLE_MAX; abox.B = -PORT_DOUBLE_MAX; /* Check if this line overlaps any feature in B */ /* x Lines in B */ if (itype[1] & (GV_POINTS | GV_LINES)) { int i; int found = 0; /* Lines */ Vect_select_lines_by_box(&(In[1]), &abox, itype[1], List); for (i = 0; i < List->n_values; i++) { int bline; bline = List->value[i]; G_debug(3, " bline = %d", bline); /* Check category */ if (!flag.cat->answer && Vect_get_line_cat(&(In[1]), bline, ifield[1]) < 0) { nskipped++; continue; } if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS if(line_relate_geos(&(In[1]), AGeom, bline, operator, parm.relate->answer)) { found = 1; break; } #endif } else { Vect_read_line(&(In[1]), BPoints, NULL, bline); if (Vect_line_check_intersection(APoints, BPoints, 0)) { found = 1; break; } } } if (found) { ALines[aline] = 1; continue; /* Go to next A line */ } } /* x Areas in B. */ if (itype[1] & GV_AREA) { int i; Vect_select_areas_by_box(&(In[1]), &abox, List); for (i = 0; i < List->n_values; i++) { int barea; barea = List->value[i]; G_debug(3, " barea = %d", barea); if (Vect_get_area_cat(&(In[1]), barea, ifield[1]) < 0) { nskipped++; continue; } if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS if(area_relate_geos(&(In[1]), AGeom, barea, operator, parm.relate->answer)) { ALines[aline] = 1; break; } #endif } else { if (line_overlap_area(&(In[0]), aline, &(In[1]), barea)) { ALines[aline] = 1; break; } } } } if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS GEOSGeom_destroy(AGeom); #endif AGeom = NULL; } } } /* Areas in A. */ if (itype[0] & GV_AREA) { int aarea, naareas; G_message(_("Processing areas...")); naareas = Vect_get_num_areas(&(In[0])); for (aarea = 1; aarea <= naareas; aarea++) { BOUND_BOX abox; G_percent(aarea, naareas, 2); /* must be before any continue */ if (Vect_get_area_cat(&(In[0]), aarea, ifield[0]) < 0) { nskipped++; continue; } Vect_get_area_box(&(In[0]), aarea, &abox); abox.T = PORT_DOUBLE_MAX; abox.B = -PORT_DOUBLE_MAX; if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS AGeom = Vect_read_area_geos(&(In[0]), aarea); #endif if (!AGeom) G_fatal_error(_("Unable to read area id %d from vector map <%s>"), aline, Vect_get_full_name(&(In[0]))); } /* x Lines in B */ if (itype[1] & (GV_POINTS | GV_LINES)) { Vect_select_lines_by_box(&(In[1]), &abox, itype[1], List); for (i = 0; i < List->n_values; i++) { int bline; bline = List->value[i]; if (!flag.cat->answer && Vect_get_line_cat(&(In[1]), bline, ifield[1]) < 0) { nskipped++; continue; } if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS if(line_relate_geos(&(In[1]), AGeom, bline, operator, parm.relate->answer)) { add_aarea(&(In[0]), aarea, ALines); break; } #endif } else { if (line_overlap_area(&(In[1]), bline, &(In[0]), aarea)) { add_aarea(&(In[0]), aarea, ALines); continue; } } } } /* x Areas in B */ if (itype[1] & GV_AREA) { int naisles; int found = 0; /* List of areas B */ /* Make a list of features forming area A */ Vect_reset_list(List); Vect_get_area_boundaries(&(In[0]), aarea, BoundList); for (i = 0; i < BoundList->n_values; i++) { Vect_list_append(List, abs(BoundList->value[i])); } naisles = Vect_get_area_num_isles(&(In[0]), aarea); for (i = 0; i < naisles; i++) { int j, aisle; aisle = Vect_get_area_isle(&(In[0]), aarea, i); Vect_get_isle_boundaries(&(In[0]), aisle, BoundList); for (j = 0; j < BoundList->n_values; j++) { Vect_list_append(List, BoundList->value[j]); } } Vect_select_areas_by_box(&(In[1]), &abox, TmpList); for (i = 0; i < List->n_values; i++) { int j, aline; aline = abs(List->value[i]); for (j = 0; j < TmpList->n_values; j++) { int barea, bcentroid; barea = TmpList->value[j]; G_debug(3, " barea = %d", barea); if (Vect_get_area_cat(&(In[1]), barea, ifield[1]) < 0) { nskipped++; continue; } /* Check if any centroid of area B is in area A. * This test is important in if area B is completely within area A */ bcentroid = Vect_get_area_centroid(&(In[1]), barea); Vect_read_line(&(In[1]), BPoints, NULL, bcentroid); if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS if(area_relate_geos(&(In[1]), AGeom, barea, operator, parm.relate->answer)) { found = 1; break; } #endif } else { if (Vect_point_in_area(&(In[0]), aarea, BPoints->x[0], BPoints->y[0])) { found = 1; break; } /* Check intersectin of lines from List with area B */ if (line_overlap_area(&(In[0]), aline, &(In[1]), barea)) { found = 1; break; } } } if (found) { add_aarea(&(In[0]), aarea, ALines); break; } } } if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS GEOSGeom_destroy(AGeom); #endif AGeom = NULL; } } } Vect_close(&(In[1])); #ifdef HAVE_GEOS finishGEOS(); #endif /* Write lines */ nfields = Vect_cidx_get_num_fields(&(In[0])); cats = (int **)G_malloc(nfields * sizeof(int *)); ncats = (int *)G_malloc(nfields * sizeof(int)); fields = (int *)G_malloc(nfields * sizeof(int)); for (i = 0; i < nfields; i++) { ncats[i] = 0; cats[i] = (int *)G_malloc(Vect_cidx_get_num_cats_by_index(&(In[0]), i) * sizeof(int)); fields[i] = Vect_cidx_get_field_number(&(In[0]), i); } G_message(_("Writing selected features...")); for (aline = 1; aline <= nalines; aline++) { int atype; G_debug(4, "aline = %d ALines[aline] = %d", aline, ALines[aline]); G_percent(aline, nalines, 2); if ((!flag.reverse->answer && !(ALines[aline])) || (flag.reverse->answer && ALines[aline])) continue; atype = Vect_read_line(&(In[0]), APoints, ACats, aline); Vect_write_line(&Out, atype, APoints, ACats); if (!(flag.table->answer) && (IFi != NULL)) { for (i = 0; i < ACats->n_cats; i++) { int f, j; for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == ACats->field[i]) { f = j; break; } } cats[f][ncats[f]] = ACats->cat[i]; ncats[f]++; } } } /* Copy tables */ if (!(flag.table->answer)) { int ttype, ntabs = 0; G_message(_("Writing attributes...")); /* Number of output tabs */ for (i = 0; i < Vect_get_num_dblinks(&(In[0])); i++) { int f, j; IFi = Vect_get_dblink(&(In[0]), i); for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == IFi->number) { f = j; break; } } if (ncats[f] > 0) ntabs++; } if (ntabs > 1) ttype = GV_MTABLE; else ttype = GV_1TABLE; for (i = 0; i < nfields; i++) { int ret; if (fields[i] == 0) continue; /* Make a list of categories */ IFi = Vect_get_field(&(In[0]), fields[i]); if (!IFi) { /* no table */ G_warning(_("Layer %d - no table"), fields[i]); continue; } OFi = Vect_default_field_info(&Out, IFi->number, IFi->name, ttype); ret = db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table, OFi->driver, Vect_subst_var(OFi->database, &Out), OFi->table, IFi->key, cats[i], ncats[i]); if (ret == DB_FAILED) { G_warning(_("Layer %d - unable to copy table"), fields[i]); } else { Vect_map_add_dblink(&Out, OFi->number, OFi->name, OFi->table, IFi->key, OFi->database, OFi->driver); } } } Vect_close(&(In[0])); Vect_build(&Out); Vect_close(&Out); if (nskipped > 0) { G_warning(_("%d features without category skipped"), nskipped); } G_done_msg(_("%d features written to output."), Vect_get_num_lines(&Out)); exit(EXIT_SUCCESS); }
void copy_tabs(struct Map_info *In, struct Map_info *Out, int nfields, int *fields, int *ncats, int **cats) { int i, ttype, ntabs; struct field_info *IFi, *OFi; ntabs = 0; G_message(_("Writing attributes...")); /* Number of output tabs */ for (i = 0; i < Vect_get_num_dblinks(In); i++) { int f, j; IFi = Vect_get_dblink(In, i); for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == IFi->number) { f = j; break; } } if (ncats[f] > 0) ntabs++; } if (ntabs > 1) ttype = GV_MTABLE; else ttype = GV_1TABLE; for (i = 0; i < nfields; i++) { int ret; if (fields[i] == 0) continue; /* Make a list of categories */ IFi = Vect_get_field(In, fields[i]); if (!IFi) { /* no table */ G_warning(_("No table for layer %d"), fields[i]); continue; } OFi = Vect_default_field_info(Out, IFi->number, IFi->name, ttype); ret = db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table, OFi->driver, Vect_subst_var(OFi->database, Out), OFi->table, IFi->key, cats[i], ncats[i]); if (ret == DB_FAILED) { G_warning(_("Unable to copy table for layer %d"), fields[i]); } else { Vect_map_add_dblink(Out, OFi->number, OFi->name, OFi->table, IFi->key, OFi->database, OFi->driver); } } }