static void create_table(struct Map_info *flowline_vec, struct field_info **f_info, dbDriver ** driver, int write_scalar, int use_sampled_map) { dbString sql; char buf[200]; dbDriver *drvr; struct field_info *fi; db_init_string(&sql); fi = Vect_default_field_info(flowline_vec, 1, NULL, GV_1TABLE); *f_info = fi; Vect_map_add_dblink(flowline_vec, 1, NULL, fi->table, GV_KEY_COLUMN, fi->database, fi->driver); drvr = db_start_driver_open_database(fi->driver, Vect_subst_var(fi->database, flowline_vec)); if (drvr == NULL) { G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Vect_subst_var(fi->database, flowline_vec), fi->driver); } db_set_error_handler_driver(drvr); *driver = drvr; sprintf(buf, "create table %s (cat integer, velocity double precision", fi->table); db_set_string(&sql, buf); if (write_scalar) db_append_string(&sql, ", input double precision"); if (use_sampled_map) db_append_string(&sql, ", sampled double precision"); db_append_string(&sql, ")"); db_begin_transaction(drvr); /* Create table */ if (db_execute_immediate(drvr, &sql) != DB_OK) { G_fatal_error(_("Unable to create table: %s"), db_get_string(&sql)); } if (db_create_index2(drvr, fi->table, fi->key) != DB_OK) G_warning(_("Unable to create index for table <%s>, key <%s>"), fi->table, fi->key); /* Grant */ if (db_grant_on_table (drvr, fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) { G_fatal_error(_("Unable to grant privileges on table <%s>"), fi->table); } }
int close_streamvect(char *stream_vect) { int r, c, r_nbr, c_nbr, done; GW_LARGE_INT i; CELL stream_id, stream_nbr; ASP_FLAG af; int next_node; struct sstack { int stream_id; int next_trib; } *nodestack; int top = 0, stack_step = 1000; int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 }; int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 }; struct Map_info Out; static struct line_pnts *Points; struct line_cats *Cats; dbDriver *driver; dbHandle handle; dbString table_name, dbsql, valstr; struct field_info *Fi; char *cat_col_name = "cat", buf[2000]; struct Cell_head window; double north_offset, west_offset, ns_res, ew_res; int next_cat; G_message(_("Writing vector map <%s>..."), stream_vect); if (Vect_open_new(&Out, stream_vect, 0) < 0) G_fatal_error(_("Unable to create vector map <%s>"), stream_vect); nodestack = (struct sstack *)G_malloc(stack_step * sizeof(struct sstack)); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); G_get_set_window(&window); ns_res = window.ns_res; ew_res = window.ew_res; north_offset = window.north - 0.5 * ns_res; west_offset = window.west + 0.5 * ew_res; next_cat = n_stream_nodes + 1; for (i = 0; i < n_outlets; i++, next_cat++) { G_percent(i, n_outlets, 2); r = outlets[i].r; c = outlets[i].c; cseg_get(&stream, &stream_id, r, c); if (!stream_id) continue; Vect_reset_line(Points); Vect_reset_cats(Cats); /* outlet */ Vect_cat_set(Cats, 1, stream_id); Vect_cat_set(Cats, 2, 2); Vect_append_point(Points, west_offset + c * ew_res, north_offset - r * ns_res, 0); Vect_write_line(&Out, GV_POINT, Points, Cats); /* add root node to stack */ G_debug(3, "add root node"); top = 0; nodestack[top].stream_id = stream_id; nodestack[top].next_trib = 0; /* depth first post order traversal */ G_debug(3, "traverse"); while (top >= 0) { done = 1; stream_id = nodestack[top].stream_id; G_debug(3, "stream_id %d", stream_id); if (nodestack[top].next_trib < stream_node[stream_id].n_trib) { /* add to stack */ next_node = stream_node[stream_id].trib[nodestack[top].next_trib]; G_debug(3, "add to stack: next %d, trib %d, n trib %d", next_node, nodestack[top].next_trib, stream_node[stream_id].n_trib); nodestack[top].next_trib++; top++; if (top >= stack_step) { /* need more space */ stack_step += 1000; nodestack = (struct sstack *)G_realloc(nodestack, stack_step * sizeof(struct sstack)); } nodestack[top].next_trib = 0; nodestack[top].stream_id = next_node; done = 0; G_debug(3, "go further down"); } if (done) { G_debug(3, "write stream segment"); Vect_reset_line(Points); Vect_reset_cats(Cats); r_nbr = stream_node[stream_id].r; c_nbr = stream_node[stream_id].c; cseg_get(&stream, &stream_nbr, r_nbr, c_nbr); if (stream_nbr <= 0) G_fatal_error(_("Stream id %d not set, top is %d, parent is %d"), stream_id, top, nodestack[top - 1].stream_id); Vect_cat_set(Cats, 1, stream_id); if (stream_node[stream_id].n_trib == 0) Vect_cat_set(Cats, 2, 0); else Vect_cat_set(Cats, 2, 1); Vect_append_point(Points, west_offset + c_nbr * ew_res, north_offset - r_nbr * ns_res, 0); Vect_write_line(&Out, GV_POINT, Points, Cats); seg_get(&aspflag, (char *)&af, r_nbr, c_nbr); while (af.asp > 0) { r_nbr = r_nbr + asp_r[(int)af.asp]; c_nbr = c_nbr + asp_c[(int)af.asp]; cseg_get(&stream, &stream_nbr, r_nbr, c_nbr); if (stream_nbr <= 0) G_fatal_error(_("Stream id not set while tracing")); Vect_append_point(Points, west_offset + c_nbr * ew_res, north_offset - r_nbr * ns_res, 0); if (stream_nbr != stream_id) { /* first point of parent stream */ break; } seg_get(&aspflag, (char *)&af, r_nbr, c_nbr); } Vect_write_line(&Out, GV_LINE, Points, Cats); top--; } } } G_percent(n_outlets, n_outlets, 1); /* finish it */ G_message(_("Writing attribute data...")); /* Prepeare strings for use in db_* calls */ db_init_string(&dbsql); db_init_string(&valstr); db_init_string(&table_name); db_init_handle(&handle); /* Preparing database for use */ /* Create database for new vector map */ Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE); driver = db_start_driver_open_database(Fi->driver, Vect_subst_var(Fi->database, &Out)); if (driver == NULL) { G_fatal_error(_("Unable to start driver <%s>"), Fi->driver); } db_set_error_handler_driver(driver); G_debug(1, "table: %s", Fi->table); G_debug(1, "driver: %s", Fi->driver); G_debug(1, "database: %s", Fi->database); sprintf(buf, "create table %s (%s integer, stream_type varchar(20), type_code integer)", Fi->table, cat_col_name); db_set_string(&dbsql, buf); if (db_execute_immediate(driver, &dbsql) != DB_OK) { db_close_database(driver); db_shutdown_driver(driver); G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&dbsql)); } if (db_create_index2(driver, Fi->table, cat_col_name) != DB_OK) G_warning(_("Unable to create index on table <%s>"), Fi->table); if (db_grant_on_table(driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Unable to grant privileges on table <%s>"), Fi->table); db_begin_transaction(driver); /* stream nodes */ for (i = 1; i <= n_stream_nodes; i++) { sprintf(buf, "insert into %s values ( %lld, \'%s\', %d )", Fi->table, i, (stream_node[i].n_trib > 0 ? "intermediate" : "start"), (stream_node[i].n_trib > 0)); db_set_string(&dbsql, buf); if (db_execute_immediate(driver, &dbsql) != DB_OK) { db_close_database(driver); db_shutdown_driver(driver); G_fatal_error(_("Unable to insert new row: '%s'"), db_get_string(&dbsql)); } } db_commit_transaction(driver); db_close_database_shutdown_driver(driver); Vect_map_add_dblink(&Out, 1, NULL, Fi->table, cat_col_name, Fi->database, Fi->driver); G_debug(1, "close vector"); Vect_hist_command(&Out); Vect_build(&Out); Vect_close(&Out); G_free(nodestack); return 1; }
int main(int argc, char *argv[]) { struct Map_info In, Out; static struct line_pnts *Points; struct line_cats *Cats; struct GModule *module; /* GRASS module for parsing arguments */ struct Option *map_in, *map_out; struct Option *cat_opt, *field_opt, *where_opt, *abcol, *afcol; struct Option *iter_opt, *error_opt; struct Flag *geo_f, *add_f; int chcat, with_z; int layer, mask_type; struct varray *varray; dglGraph_s *graph; int i, geo, nnodes, nlines, j, max_cat; char buf[2000], *covered; /* initialize GIS environment */ G_gisinit(argv[0]); /* reads grass env, stores program name to G_program_name() */ /* initialize module */ module = G_define_module(); module->keywords = _("vector, network, centrality measures"); module->description = _("Computes degree, centrality, betweeness, closeness and eigenvector " "centrality measures in the network."); /* Define the different options as defined in gis.h */ map_in = G_define_standard_option(G_OPT_V_INPUT); field_opt = G_define_standard_option(G_OPT_V_FIELD); map_out = G_define_standard_option(G_OPT_V_OUTPUT); cat_opt = G_define_standard_option(G_OPT_V_CATS); cat_opt->guisection = _("Selection"); where_opt = G_define_standard_option(G_OPT_WHERE); where_opt->guisection = _("Selection"); afcol = G_define_standard_option(G_OPT_COLUMN); afcol->key = "afcolumn"; afcol->required = NO; afcol->description = _("Name of arc forward/both direction(s) cost column"); afcol->guisection = _("Cost"); abcol = G_define_standard_option(G_OPT_COLUMN); abcol->key = "abcolumn"; abcol->required = NO; abcol->description = _("Name of arc backward direction cost column"); abcol->guisection = _("Cost"); deg_opt = G_define_standard_option(G_OPT_COLUMN); deg_opt->key = "degree"; deg_opt->required = NO; deg_opt->description = _("Name of degree centrality column"); deg_opt->guisection = _("Columns"); close_opt = G_define_standard_option(G_OPT_COLUMN); close_opt->key = "closeness"; close_opt->required = NO; close_opt->description = _("Name of closeness centrality column"); close_opt->guisection = _("Columns"); betw_opt = G_define_standard_option(G_OPT_COLUMN); betw_opt->key = "betweenness"; betw_opt->required = NO; betw_opt->description = _("Name of betweenness centrality column"); betw_opt->guisection = _("Columns"); eigen_opt = G_define_standard_option(G_OPT_COLUMN); eigen_opt->key = "eigenvector"; eigen_opt->required = NO; eigen_opt->description = _("Name of eigenvector centrality column"); eigen_opt->guisection = _("Columns"); iter_opt = G_define_option(); iter_opt->key = "iterations"; iter_opt->answer = "1000"; iter_opt->type = TYPE_INTEGER; iter_opt->required = NO; iter_opt->description = _("Maximum number of iterations to compute eigenvector centrality"); error_opt = G_define_option(); error_opt->key = "error"; error_opt->answer = "0.1"; error_opt->type = TYPE_DOUBLE; error_opt->required = NO; error_opt->description = _("Cummulative error tolerance for eigenvector centrality"); geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = _("Use geodesic calculation for longitude-latitude locations"); add_f = G_define_flag(); add_f->key = 'a'; add_f->description = _("Add points on nodes"); /* options and flags parser */ if (G_parser(argc, argv)) exit(EXIT_FAILURE); /* TODO: make an option for this */ mask_type = GV_LINE | GV_BOUNDARY; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); Vect_check_input_output_name(map_in->answer, map_out->answer, GV_FATAL_EXIT); Vect_set_open_level(2); if (1 > Vect_open_old(&In, map_in->answer, "")) G_fatal_error(_("Unable to open vector map <%s>"), map_in->answer); with_z = Vect_is_3d(&In); if (0 > Vect_open_new(&Out, map_out->answer, with_z)) { Vect_close(&In); G_fatal_error(_("Unable to create vector map <%s>"), map_out->answer); } if (geo_f->answer) { geo = 1; if (G_projection() != PROJECTION_LL) G_warning(_("The current projection is not longitude-latitude")); } else geo = 0; /* parse filter option and select appropriate lines */ layer = atoi(field_opt->answer); chcat = (NetA_initialise_varray (&In, layer, mask_type, where_opt->answer, cat_opt->answer, &varray) == 1); /* Create table */ Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE); Vect_map_add_dblink(&Out, 1, NULL, Fi->table, "cat", Fi->database, Fi->driver); db_init_string(&sql); 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_init_string(&tmp); if (deg_opt->answer) append_string(&tmp, deg_opt->answer); if (close_opt->answer) append_string(&tmp, close_opt->answer); if (betw_opt->answer) append_string(&tmp, betw_opt->answer); if (eigen_opt->answer) append_string(&tmp, eigen_opt->answer); sprintf(buf, "create table %s(cat integer%s)", Fi->table, db_get_string(&tmp)); db_set_string(&sql, buf); G_debug(2, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { db_close_database_shutdown_driver(driver); G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&sql)); } if (db_create_index2(driver, Fi->table, "cat") != DB_OK) G_warning(_("Cannot create index")); if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Cannot grant privileges on table <%s>"), Fi->table); db_begin_transaction(driver); Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); Vect_net_build_graph(&In, mask_type, atoi(field_opt->answer), 0, afcol->answer, abcol->answer, NULL, geo, 0); graph = &(In.graph); nnodes = dglGet_NodeCount(graph); deg = closeness = betw = eigen = NULL; covered = (char *)G_calloc(nnodes + 1, sizeof(char)); if (!covered) G_fatal_error(_("Out of memory")); if (deg_opt->answer) { deg = (double *)G_calloc(nnodes + 1, sizeof(double)); if (!deg) G_fatal_error(_("Out of memory")); } if (close_opt->answer) { closeness = (double *)G_calloc(nnodes + 1, sizeof(double)); if (!closeness) G_fatal_error(_("Out of memory")); } if (betw_opt->answer) { betw = (double *)G_calloc(nnodes + 1, sizeof(double)); if (!betw) G_fatal_error(_("Out of memory")); } if (eigen_opt->answer) { eigen = (double *)G_calloc(nnodes + 1, sizeof(double)); if (!eigen) G_fatal_error(_("Out of memory")); } if (deg_opt->answer) { G_message(_("Computing degree centrality measure")); NetA_degree_centrality(graph, deg); } if (betw_opt->answer || close_opt->answer) { G_message(_("Computing betweenness and/or closeness centrality measure")); NetA_betweenness_closeness(graph, betw, closeness); if (closeness) for (i = 1; i <= nnodes; i++) closeness[i] /= (double)In.cost_multip; } if (eigen_opt->answer) { G_message(_("Computing eigenvector centrality measure")); NetA_eigenvector_centrality(graph, atoi(iter_opt->answer), atof(error_opt->answer), eigen); } nlines = Vect_get_num_lines(&In); G_message(_("Writing data into the table...")); G_percent_reset(); for (i = 1; i <= nlines; i++) { G_percent(i, nlines, 1); int type = Vect_read_line(&In, Points, Cats, i); if (type == GV_POINT && (!chcat || varray->c[i])) { int cat, node; if (!Vect_cat_get(Cats, layer, &cat)) continue; Vect_reset_cats(Cats); Vect_cat_set(Cats, 1, cat); Vect_write_line(&Out, type, Points, Cats); Vect_get_line_nodes(&In, i, &node, NULL); process_node(node, cat); covered[node] = 1; } } if (add_f->answer && !chcat) { max_cat = 0; for (i = 1; i <= nlines; i++) { Vect_read_line(&In, NULL, Cats, i); for (j = 0; j < Cats->n_cats; j++) if (Cats->cat[j] > max_cat) max_cat = Cats->cat[j]; } max_cat++; for (i = 1; i <= nnodes; i++) if (!covered[i]) { Vect_reset_cats(Cats); Vect_cat_set(Cats, 1, max_cat); NetA_add_point_on_node(&In, &Out, i, Cats); process_node(i, max_cat); max_cat++; } } db_commit_transaction(driver); db_close_database_shutdown_driver(driver); G_free(covered); if (deg) G_free(deg); if (closeness) G_free(closeness); if (betw) G_free(betw); if (eigen) G_free(eigen); Vect_build(&Out); Vect_close(&In); Vect_close(&Out); exit(EXIT_SUCCESS); }
int main(int argc, char *argv[]) { struct GModule *module; struct _param { struct Option *dsn, *out, *layer, *spat, *where, *min_area; struct Option *snap, *type, *outloc, *cnames; } param; struct _flag { struct Flag *list, *tlist, *no_clean, *z, *notab, *region; struct Flag *over, *extend, *formats, *tolower, *no_import; } flag; int i, j, layer, arg_s_num, nogeom, ncnames; float xmin, ymin, xmax, ymax; int ncols = 0, type; double min_area, snap; char buf[2000], namebuf[2000], tempvect[GNAME_MAX]; char *separator; struct Key_Value *loc_proj_info, *loc_proj_units; struct Key_Value *proj_info, *proj_units; struct Cell_head cellhd, loc_wind, cur_wind; char error_msg[8192]; /* Vector */ struct Map_info Map, Tmp, *Out; int cat; /* Attributes */ struct field_info *Fi; dbDriver *driver; dbString sql, strval; int dim, with_z; /* OGR */ OGRDataSourceH Ogr_ds; OGRLayerH Ogr_layer; OGRFieldDefnH Ogr_field; char *Ogr_fieldname; OGRFieldType Ogr_ftype; OGRFeatureH Ogr_feature; OGRFeatureDefnH Ogr_featuredefn; OGRGeometryH Ogr_geometry, Ogr_oRing, poSpatialFilter; OGRSpatialReferenceH Ogr_projection; OGREnvelope oExt; OGRwkbGeometryType Ogr_geom_type; int OFTIntegerListlength; char *output; char **layer_names; /* names of layers to be imported */ int *layers; /* layer indexes */ int nlayers; /* number of layers to import */ char **available_layer_names; /* names of layers to be imported */ int navailable_layers; int layer_id; unsigned int n_features, feature_count; int overwrite; double area_size; int use_tmp_vect; xmin = ymin = xmax = ymax = 0.0; loc_proj_info = loc_proj_units = NULL; Ogr_ds = Ogr_oRing = poSpatialFilter = NULL; OFTIntegerListlength = 40; /* hack due to limitation in OGR */ area_size = 0.0; use_tmp_vect = FALSE; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("import")); module->description = _("Converts vector data into a GRASS vector map using OGR library."); param.dsn = G_define_option(); param.dsn->key = "dsn"; param.dsn->type = TYPE_STRING; param.dsn->required =YES; param.dsn->label = _("OGR datasource name"); param.dsn->description = _("Examples:\n" "\t\tESRI Shapefile: directory containing shapefiles\n" "\t\tMapInfo File: directory containing mapinfo files"); param.layer = G_define_option(); param.layer->key = "layer"; param.layer->type = TYPE_STRING; param.layer->required = NO; param.layer->multiple = YES; param.layer->label = _("OGR layer name. If not given, all available layers are imported"); param.layer->description = _("Examples:\n" "\t\tESRI Shapefile: shapefile name\n" "\t\tMapInfo File: mapinfo file name"); param.layer->guisection = _("Selection"); param.out = G_define_standard_option(G_OPT_V_OUTPUT); param.out->required = NO; param.out->guisection = _("Output"); param.spat = G_define_option(); param.spat->key = "spatial"; param.spat->type = TYPE_DOUBLE; param.spat->multiple = YES; param.spat->required = NO; param.spat->key_desc = "xmin,ymin,xmax,ymax"; param.spat->label = _("Import subregion only"); param.spat->guisection = _("Selection"); param.spat->description = _("Format: xmin,ymin,xmax,ymax - usually W,S,E,N"); param.where = G_define_standard_option(G_OPT_DB_WHERE); param.where->guisection = _("Selection"); param.min_area = G_define_option(); param.min_area->key = "min_area"; param.min_area->type = TYPE_DOUBLE; param.min_area->required = NO; param.min_area->answer = "0.0001"; param.min_area->label = _("Minimum size of area to be imported (square units)"); param.min_area->guisection = _("Selection"); param.min_area->description = _("Smaller areas and " "islands are ignored. Should be greater than snap^2"); param.type = G_define_standard_option(G_OPT_V_TYPE); param.type->options = "point,line,boundary,centroid"; param.type->answer = ""; param.type->description = _("Optionally change default input type"); param.type->descriptions = _("point;import area centroids as points;" "line;import area boundaries as lines;" "boundary;import lines as area boundaries;" "centroid;import points as centroids"); param.type->guisection = _("Selection"); param.snap = G_define_option(); param.snap->key = "snap"; param.snap->type = TYPE_DOUBLE; param.snap->required = NO; param.snap->answer = "-1"; param.snap->label = _("Snapping threshold for boundaries"); param.snap->description = _("'-1' for no snap"); param.outloc = G_define_option(); param.outloc->key = "location"; param.outloc->type = TYPE_STRING; param.outloc->required = NO; param.outloc->description = _("Name for new location to create"); param.outloc->key_desc = "name"; param.cnames = G_define_option(); param.cnames->key = "cnames"; param.cnames->type = TYPE_STRING; param.cnames->required = NO; param.cnames->multiple = YES; param.cnames->description = _("List of column names to be used instead of original names, " "first is used for category column"); param.cnames->guisection = _("Attributes"); flag.list = G_define_flag(); flag.list->key = 'l'; flag.list->description = _("List available OGR layers in data source and exit"); flag.list->suppress_required = YES; flag.list->guisection = _("Print"); flag.tlist = G_define_flag(); flag.tlist->key = 'a'; flag.tlist->description = _("List available OGR layers including feature types " "in data source and exit"); flag.tlist->suppress_required = YES; flag.tlist->guisection = _("Print"); flag.formats = G_define_flag(); flag.formats->key = 'f'; flag.formats->description = _("List supported formats and exit"); flag.formats->suppress_required = YES; flag.formats->guisection = _("Print"); /* if using -c, you lose topological information ! */ flag.no_clean = G_define_flag(); flag.no_clean->key = 'c'; flag.no_clean->description = _("Do not clean polygons (not recommended)"); flag.no_clean->guisection = _("Output"); flag.z = G_define_flag(); flag.z->key = 'z'; flag.z->description = _("Create 3D output"); flag.z->guisection = _("Output"); flag.notab = G_define_flag(); flag.notab->key = 't'; flag.notab->description = _("Do not create attribute table"); flag.notab->guisection = _("Attributes"); flag.over = G_define_flag(); flag.over->key = 'o'; flag.over->description = _("Override dataset projection (use location's projection)"); flag.region = G_define_flag(); flag.region->key = 'r'; flag.region->guisection = _("Selection"); flag.region->description = _("Limit import to the current region"); flag.extend = G_define_flag(); flag.extend->key = 'e'; flag.extend->description = _("Extend location extents based on new dataset"); flag.tolower = G_define_flag(); flag.tolower->key = 'w'; flag.tolower->description = _("Change column names to lowercase characters"); flag.tolower->guisection = _("Attributes"); flag.no_import = G_define_flag(); flag.no_import->key = 'i'; flag.no_import->description = _("Create the location specified by the \"location\" parameter and exit." " Do not import the vector data."); /* The parser checks if the map already exists in current mapset, this is * wrong if location options is used, so we switch out the check and do it * in the module after the parser */ overwrite = G_check_overwrite(argc, argv); if (G_parser(argc, argv)) exit(EXIT_FAILURE); G_begin_polygon_area_calculations(); /* Used in geom() */ OGRRegisterAll(); /* list supported formats */ if (flag.formats->answer) { int iDriver; G_message(_("Available OGR Drivers:")); for (iDriver = 0; iDriver < OGRGetDriverCount(); iDriver++) { OGRSFDriverH poDriver = OGRGetDriver(iDriver); const char *pszRWFlag; if (OGR_Dr_TestCapability(poDriver, ODrCCreateDataSource)) pszRWFlag = "rw"; else pszRWFlag = "ro"; fprintf(stdout, " %s (%s): %s\n", OGR_Dr_GetName(poDriver), pszRWFlag, OGR_Dr_GetName(poDriver)); } exit(EXIT_SUCCESS); } if (param.dsn->answer == NULL) { G_fatal_error(_("Required parameter <%s> not set"), param.dsn->key); } min_area = atof(param.min_area->answer); snap = atof(param.snap->answer); type = Vect_option_to_types(param.type); ncnames = 0; if (param.cnames->answers) { i = 0; while (param.cnames->answers[i++]) { ncnames++; } } /* Open OGR DSN */ Ogr_ds = NULL; if (strlen(param.dsn->answer) > 0) Ogr_ds = OGROpen(param.dsn->answer, FALSE, NULL); if (Ogr_ds == NULL) G_fatal_error(_("Unable to open data source <%s>"), param.dsn->answer); /* Make a list of available layers */ navailable_layers = OGR_DS_GetLayerCount(Ogr_ds); available_layer_names = (char **)G_malloc(navailable_layers * sizeof(char *)); if (flag.list->answer || flag.tlist->answer) G_message(_("Data source <%s> (format '%s') contains %d layers:"), param.dsn->answer, OGR_Dr_GetName(OGR_DS_GetDriver(Ogr_ds)), navailable_layers); for (i = 0; i < navailable_layers; i++) { Ogr_layer = OGR_DS_GetLayer(Ogr_ds, i); Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer); Ogr_geom_type = OGR_FD_GetGeomType(Ogr_featuredefn); available_layer_names[i] = G_store((char *)OGR_FD_GetName(Ogr_featuredefn)); if (flag.tlist->answer) fprintf(stdout, "%s (%s)\n", available_layer_names[i], OGRGeometryTypeToName(Ogr_geom_type)); else if (flag.list->answer) fprintf(stdout, "%s\n", available_layer_names[i]); } if (flag.list->answer || flag.tlist->answer) { fflush(stdout); exit(EXIT_SUCCESS); } /* Make a list of layers to be imported */ if (param.layer->answer) { /* From option */ nlayers = 0; while (param.layer->answers[nlayers]) nlayers++; layer_names = (char **)G_malloc(nlayers * sizeof(char *)); layers = (int *)G_malloc(nlayers * sizeof(int)); for (i = 0; i < nlayers; i++) { layer_names[i] = G_store(param.layer->answers[i]); /* Find it in the source */ layers[i] = -1; for (j = 0; j < navailable_layers; j++) { if (strcmp(available_layer_names[j], layer_names[i]) == 0) { layers[i] = j; break; } } if (layers[i] == -1) G_fatal_error(_("Layer <%s> not available"), layer_names[i]); } } else { /* use list of all layers */ nlayers = navailable_layers; layer_names = available_layer_names; layers = (int *)G_malloc(nlayers * sizeof(int)); for (i = 0; i < nlayers; i++) layers[i] = i; } if (param.out->answer) { output = G_store(param.out->answer); } else { if (nlayers < 1) G_fatal_error(_("No OGR layers available")); output = G_store(layer_names[0]); G_message(_("All available OGR layers will be imported into vector map <%s>"), output); } if (!param.outloc->answer) { /* Check if the map exists */ if (G_find_vector2(output, G_mapset()) && !overwrite) G_fatal_error(_("Vector map <%s> already exists"), output); } /* Get first imported layer to use for extents and projection check */ Ogr_layer = OGR_DS_GetLayer(Ogr_ds, layers[0]); if (flag.region->answer) { if (param.spat->answer) G_fatal_error(_("Select either the current region flag or the spatial option, not both")); G_get_window(&cur_wind); xmin = cur_wind.west; xmax = cur_wind.east; ymin = cur_wind.south; ymax = cur_wind.north; } if (param.spat->answer) { /* See as reference: gdal/ogr/ogr_capi_test.c */ /* cut out a piece of the map */ /* order: xmin,ymin,xmax,ymax */ arg_s_num = 0; i = 0; while (param.spat->answers[i]) { if (i == 0) xmin = atof(param.spat->answers[i]); if (i == 1) ymin = atof(param.spat->answers[i]); if (i == 2) xmax = atof(param.spat->answers[i]); if (i == 3) ymax = atof(param.spat->answers[i]); arg_s_num++; i++; } if (arg_s_num != 4) G_fatal_error(_("4 parameters required for 'spatial' parameter")); } if (param.spat->answer || flag.region->answer) { G_debug(2, "cut out with boundaries: xmin:%f ymin:%f xmax:%f ymax:%f", xmin, ymin, xmax, ymax); /* in theory this could be an irregular polygon */ poSpatialFilter = OGR_G_CreateGeometry(wkbPolygon); Ogr_oRing = OGR_G_CreateGeometry(wkbLinearRing); OGR_G_AddPoint(Ogr_oRing, xmin, ymin, 0.0); OGR_G_AddPoint(Ogr_oRing, xmin, ymax, 0.0); OGR_G_AddPoint(Ogr_oRing, xmax, ymax, 0.0); OGR_G_AddPoint(Ogr_oRing, xmax, ymin, 0.0); OGR_G_AddPoint(Ogr_oRing, xmin, ymin, 0.0); OGR_G_AddGeometryDirectly(poSpatialFilter, Ogr_oRing); OGR_L_SetSpatialFilter(Ogr_layer, poSpatialFilter); } if (param.where->answer) { /* select by attribute */ OGR_L_SetAttributeFilter(Ogr_layer, param.where->answer); } /* fetch boundaries */ if ((OGR_L_GetExtent(Ogr_layer, &oExt, 1)) == OGRERR_NONE) { G_get_window(&cellhd); cellhd.north = oExt.MaxY; cellhd.south = oExt.MinY; cellhd.west = oExt.MinX; cellhd.east = oExt.MaxX; cellhd.rows = 20; /* TODO - calculate useful values */ cellhd.cols = 20; cellhd.ns_res = (cellhd.north - cellhd.south) / cellhd.rows; cellhd.ew_res = (cellhd.east - cellhd.west) / cellhd.cols; } else { cellhd.north = 1.; cellhd.south = 0.; cellhd.west = 0.; cellhd.east = 1.; cellhd.top = 1.; cellhd.bottom = 1.; cellhd.rows = 1; cellhd.rows3 = 1; cellhd.cols = 1; cellhd.cols3 = 1; cellhd.depths = 1; cellhd.ns_res = 1.; cellhd.ns_res3 = 1.; cellhd.ew_res = 1.; cellhd.ew_res3 = 1.; cellhd.tb_res = 1.; } /* suppress boundary splitting ? */ if (flag.no_clean->answer) { split_distance = -1.; } else { split_distance = 0.; area_size = sqrt((cellhd.east - cellhd.west) * (cellhd.north - cellhd.south)); } /* Fetch input map projection in GRASS form. */ proj_info = NULL; proj_units = NULL; Ogr_projection = OGR_L_GetSpatialRef(Ogr_layer); /* should not be freed later */ /* Do we need to create a new location? */ if (param.outloc->answer != NULL) { /* Convert projection information non-interactively as we can't * assume the user has a terminal open */ if (GPJ_osr_to_grass(&cellhd, &proj_info, &proj_units, Ogr_projection, 0) < 0) { G_fatal_error(_("Unable to convert input map projection to GRASS " "format; cannot create new location.")); } else { G_make_location(param.outloc->answer, &cellhd, proj_info, proj_units, NULL); G_message(_("Location <%s> created"), param.outloc->answer); } /* If the i flag is set, clean up? and exit here */ if(flag.no_import->answer) { exit(EXIT_SUCCESS); } } else { int err = 0; /* Projection only required for checking so convert non-interactively */ if (GPJ_osr_to_grass(&cellhd, &proj_info, &proj_units, Ogr_projection, 0) < 0) G_warning(_("Unable to convert input map projection information to " "GRASS format for checking")); /* Does the projection of the current location match the dataset? */ /* G_get_window seems to be unreliable if the location has been changed */ G__get_window(&loc_wind, "", "DEFAULT_WIND", "PERMANENT"); /* fetch LOCATION PROJ info */ if (loc_wind.proj != PROJECTION_XY) { loc_proj_info = G_get_projinfo(); loc_proj_units = G_get_projunits(); } if (flag.over->answer) { cellhd.proj = loc_wind.proj; cellhd.zone = loc_wind.zone; G_message(_("Over-riding projection check")); } else if (loc_wind.proj != cellhd.proj || (err = G_compare_projections(loc_proj_info, loc_proj_units, proj_info, proj_units)) != TRUE) { int i_value; strcpy(error_msg, _("Projection of dataset does not" " appear to match current location.\n\n")); /* TODO: output this info sorted by key: */ if (loc_wind.proj != cellhd.proj || err != -2) { if (loc_proj_info != NULL) { strcat(error_msg, _("GRASS LOCATION PROJ_INFO is:\n")); for (i_value = 0; i_value < loc_proj_info->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", loc_proj_info->key[i_value], loc_proj_info->value[i_value]); strcat(error_msg, "\n"); } if (proj_info != NULL) { strcat(error_msg, _("Import dataset PROJ_INFO is:\n")); for (i_value = 0; i_value < proj_info->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", proj_info->key[i_value], proj_info->value[i_value]); } else { strcat(error_msg, _("Import dataset PROJ_INFO is:\n")); if (cellhd.proj == PROJECTION_XY) sprintf(error_msg + strlen(error_msg), "Dataset proj = %d (unreferenced/unknown)\n", cellhd.proj); else if (cellhd.proj == PROJECTION_LL) sprintf(error_msg + strlen(error_msg), "Dataset proj = %d (lat/long)\n", cellhd.proj); else if (cellhd.proj == PROJECTION_UTM) sprintf(error_msg + strlen(error_msg), "Dataset proj = %d (UTM), zone = %d\n", cellhd.proj, cellhd.zone); else if (cellhd.proj == PROJECTION_SP) sprintf(error_msg + strlen(error_msg), "Dataset proj = %d (State Plane), zone = %d\n", cellhd.proj, cellhd.zone); else sprintf(error_msg + strlen(error_msg), "Dataset proj = %d (unknown), zone = %d\n", cellhd.proj, cellhd.zone); } } else { if (loc_proj_units != NULL) { strcat(error_msg, "GRASS LOCATION PROJ_UNITS is:\n"); for (i_value = 0; i_value < loc_proj_units->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", loc_proj_units->key[i_value], loc_proj_units->value[i_value]); strcat(error_msg, "\n"); } if (proj_units != NULL) { strcat(error_msg, "Import dataset PROJ_UNITS is:\n"); for (i_value = 0; i_value < proj_units->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", proj_units->key[i_value], proj_units->value[i_value]); } } sprintf(error_msg + strlen(error_msg), _("\nYou can use the -o flag to %s to override this projection check.\n"), G_program_name()); strcat(error_msg, _("Consider generating a new location with 'location' parameter" " from input data set.\n")); G_fatal_error(error_msg); } else { G_message(_("Projection of input dataset and current location " "appear to match")); } } db_init_string(&sql); db_init_string(&strval); /* open output vector */ /* strip any @mapset from vector output name */ G_find_vector(output, G_mapset()); Vect_open_new(&Map, output, flag.z->answer != 0); Out = ⤅ n_polygon_boundaries = 0; if (!flag.no_clean->answer) { /* check if we need a tmp vector */ /* estimate distance for boundary splitting --> */ for (layer = 0; layer < nlayers; layer++) { layer_id = layers[layer]; Ogr_layer = OGR_DS_GetLayer(Ogr_ds, layer_id); Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer); n_features = feature_count = 0; n_features = OGR_L_GetFeatureCount(Ogr_layer, 1); OGR_L_ResetReading(Ogr_layer); /* count polygons and isles */ G_message(_("Counting polygons for %d features (OGR layer <%s>)..."), n_features, layer_names[layer]); while ((Ogr_feature = OGR_L_GetNextFeature(Ogr_layer)) != NULL) { G_percent(feature_count++, n_features, 1); /* show something happens */ /* Geometry */ Ogr_geometry = OGR_F_GetGeometryRef(Ogr_feature); if (Ogr_geometry != NULL) { poly_count(Ogr_geometry, (type & GV_BOUNDARY)); } OGR_F_Destroy(Ogr_feature); } } G_debug(1, "n polygon boundaries: %d", n_polygon_boundaries); if (n_polygon_boundaries > 50) { split_distance = area_size / log(n_polygon_boundaries); /* divisor is the handle: increase divisor to decrease split_distance */ split_distance = split_distance / 5.; G_debug(1, "root of area size: %f", area_size); G_verbose_message(_("Boundary splitting distance in map units: %G"), split_distance); } /* <-- estimate distance for boundary splitting */ use_tmp_vect = n_polygon_boundaries > 0; if (use_tmp_vect) { /* open temporary vector, do the work in the temporary vector * at the end copy alive lines to output vector * in case of polygons this reduces the coor file size by a factor of 2 to 5 * only needed when cleaning polygons */ sprintf(tempvect, "%s_tmp", output); G_verbose_message(_("Using temporary vector <%s>"), tempvect); Vect_open_new(&Tmp, tempvect, flag.z->answer != 0); Out = &Tmp; } } Vect_hist_command(&Map); /* Points and lines are written immediately with categories. Boundaries of polygons are * written to the vector then cleaned and centroids are calculated for all areas in cleaan vector. * Then second pass through finds all centroids in each polygon feature and adds its category * to the centroid. The result is that one centroids may have 0, 1 ore more categories * of one ore more (more input layers) fields. */ with_z = 0; for (layer = 0; layer < nlayers; layer++) { layer_id = layers[layer]; Ogr_layer = OGR_DS_GetLayer(Ogr_ds, layer_id); Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer); /* Add DB link */ if (!flag.notab->answer) { char *cat_col_name = GV_KEY_COLUMN; if (nlayers == 1) { /* one layer only */ Fi = Vect_default_field_info(&Map, layer + 1, NULL, GV_1TABLE); } else { Fi = Vect_default_field_info(&Map, layer + 1, NULL, GV_MTABLE); } if (ncnames > 0) { cat_col_name = param.cnames->answers[0]; } Vect_map_add_dblink(&Map, layer + 1, layer_names[layer], Fi->table, cat_col_name, Fi->database, Fi->driver); ncols = OGR_FD_GetFieldCount(Ogr_featuredefn); G_debug(2, "%d columns", ncols); /* Create table */ sprintf(buf, "create table %s (%s integer", Fi->table, cat_col_name); db_set_string(&sql, buf); for (i = 0; i < ncols; i++) { Ogr_field = OGR_FD_GetFieldDefn(Ogr_featuredefn, i); Ogr_ftype = OGR_Fld_GetType(Ogr_field); G_debug(3, "Ogr_ftype: %i", Ogr_ftype); /* look up below */ if (i < ncnames - 1) { Ogr_fieldname = G_store(param.cnames->answers[i + 1]); } else { /* Change column names to [A-Za-z][A-Za-z0-9_]* */ Ogr_fieldname = G_store(OGR_Fld_GetNameRef(Ogr_field)); G_debug(3, "Ogr_fieldname: '%s'", Ogr_fieldname); G_str_to_sql(Ogr_fieldname); G_debug(3, "Ogr_fieldname: '%s'", Ogr_fieldname); } /* avoid that we get the 'cat' column twice */ if (strcmp(Ogr_fieldname, GV_KEY_COLUMN) == 0) { sprintf(namebuf, "%s_", Ogr_fieldname); Ogr_fieldname = G_store(namebuf); } /* captial column names are a pain in SQL */ if (flag.tolower->answer) G_str_to_lower(Ogr_fieldname); if (strcmp(OGR_Fld_GetNameRef(Ogr_field), Ogr_fieldname) != 0) { G_warning(_("Column name changed: '%s' -> '%s'"), OGR_Fld_GetNameRef(Ogr_field), Ogr_fieldname); } /** Simple 32bit integer OFTInteger = 0 **/ /** List of 32bit integers OFTIntegerList = 1 **/ /** Double Precision floating point OFTReal = 2 **/ /** List of doubles OFTRealList = 3 **/ /** String of ASCII chars OFTString = 4 **/ /** Array of strings OFTStringList = 5 **/ /** Double byte string (unsupported) OFTWideString = 6 **/ /** List of wide strings (unsupported) OFTWideStringList = 7 **/ /** Raw Binary data (unsupported) OFTBinary = 8 **/ /** OFTDate = 9 **/ /** OFTTime = 10 **/ /** OFTDateTime = 11 **/ if (Ogr_ftype == OFTInteger) { sprintf(buf, ", %s integer", Ogr_fieldname); } else if (Ogr_ftype == OFTIntegerList) { /* hack: treat as string */ sprintf(buf, ", %s varchar ( %d )", Ogr_fieldname, OFTIntegerListlength); G_warning(_("Writing column <%s> with fixed length %d chars (may be truncated)"), Ogr_fieldname, OFTIntegerListlength); } else if (Ogr_ftype == OFTReal) { sprintf(buf, ", %s double precision", Ogr_fieldname); #if GDAL_VERSION_NUM >= 1320 } else if (Ogr_ftype == OFTDate) { sprintf(buf, ", %s date", Ogr_fieldname); } else if (Ogr_ftype == OFTTime) { sprintf(buf, ", %s time", Ogr_fieldname); } else if (Ogr_ftype == OFTDateTime) { sprintf(buf, ", %s datetime", Ogr_fieldname); #endif } else if (Ogr_ftype == OFTString) { int fwidth; fwidth = OGR_Fld_GetWidth(Ogr_field); /* TODO: read all records first and find the longest string length */ if (fwidth == 0) { G_warning(_("Width for column %s set to 255 (was not specified by OGR), " "some strings may be truncated!"), Ogr_fieldname); fwidth = 255; } sprintf(buf, ", %s varchar ( %d )", Ogr_fieldname, fwidth); } else if (Ogr_ftype == OFTStringList) { /* hack: treat as string */ sprintf(buf, ", %s varchar ( %d )", Ogr_fieldname, OFTIntegerListlength); G_warning(_("Writing column %s with fixed length %d chars (may be truncated)"), Ogr_fieldname, OFTIntegerListlength); } else { G_warning(_("Column type not supported (%s)"), Ogr_fieldname); buf[0] = 0; } db_append_string(&sql, buf); G_free(Ogr_fieldname); } db_append_string(&sql, ")"); G_debug(3, db_get_string(&sql)); driver = db_start_driver_open_database(Fi->driver, Vect_subst_var(Fi->database, &Map)); if (driver == NULL) { G_fatal_error(_("Unable open database <%s> by driver <%s>"), Vect_subst_var(Fi->database, &Map), Fi->driver); } if (db_execute_immediate(driver, &sql) != DB_OK) { db_close_database(driver); db_shutdown_driver(driver); G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&sql)); } if (db_create_index2(driver, Fi->table, cat_col_name) != DB_OK) G_warning(_("Unable to create index for table <%s>, key <%s>"), Fi->table, cat_col_name); if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Unable to grant privileges on table <%s>"), Fi->table); db_begin_transaction(driver); } /* Import feature */ cat = 1; nogeom = 0; OGR_L_ResetReading(Ogr_layer); n_features = feature_count = 0; n_features = OGR_L_GetFeatureCount(Ogr_layer, 1); G_important_message(_("Importing %d features (OGR layer <%s>)..."), n_features, layer_names[layer]); while ((Ogr_feature = OGR_L_GetNextFeature(Ogr_layer)) != NULL) { G_percent(feature_count++, n_features, 1); /* show something happens */ /* Geometry */ Ogr_geometry = OGR_F_GetGeometryRef(Ogr_feature); if (Ogr_geometry == NULL) { nogeom++; } else { dim = OGR_G_GetCoordinateDimension(Ogr_geometry); if (dim > 2) with_z = 1; geom(Ogr_geometry, Out, layer + 1, cat, min_area, type, flag.no_clean->answer); } /* Attributes */ if (!flag.notab->answer) { sprintf(buf, "insert into %s values ( %d", Fi->table, cat); db_set_string(&sql, buf); for (i = 0; i < ncols; i++) { Ogr_field = OGR_FD_GetFieldDefn(Ogr_featuredefn, i); Ogr_ftype = OGR_Fld_GetType(Ogr_field); if (OGR_F_IsFieldSet(Ogr_feature, i)) { if (Ogr_ftype == OFTInteger || Ogr_ftype == OFTReal) { sprintf(buf, ", %s", OGR_F_GetFieldAsString(Ogr_feature, i)); #if GDAL_VERSION_NUM >= 1320 /* should we use OGR_F_GetFieldAsDateTime() here ? */ } else if (Ogr_ftype == OFTDate || Ogr_ftype == OFTTime || Ogr_ftype == OFTDateTime) { char *newbuf; db_set_string(&strval, (char *) OGR_F_GetFieldAsString(Ogr_feature, i)); db_double_quote_string(&strval); sprintf(buf, ", '%s'", db_get_string(&strval)); newbuf = G_str_replace(buf, "/", "-"); /* fix 2001/10/21 to 2001-10-21 */ sprintf(buf, "%s", newbuf); #endif } else if (Ogr_ftype == OFTString || Ogr_ftype == OFTIntegerList) { db_set_string(&strval, (char *) OGR_F_GetFieldAsString(Ogr_feature, i)); db_double_quote_string(&strval); sprintf(buf, ", '%s'", db_get_string(&strval)); } } else { /* G_warning (_("Column value not set" )); */ if (Ogr_ftype == OFTInteger || Ogr_ftype == OFTReal) { sprintf(buf, ", NULL"); #if GDAL_VERSION_NUM >= 1320 } else if (Ogr_ftype == OFTString || Ogr_ftype == OFTIntegerList || Ogr_ftype == OFTDate) { #else } else if (Ogr_ftype == OFTString || Ogr_ftype == OFTIntegerList) { #endif sprintf(buf, ", ''"); } } db_append_string(&sql, buf); } db_append_string(&sql, " )"); G_debug(3, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { db_close_database(driver); db_shutdown_driver(driver); G_fatal_error(_("Cannot insert new row: %s"), db_get_string(&sql)); } } OGR_F_Destroy(Ogr_feature); cat++; } G_percent(1, 1, 1); /* finish it */ if (!flag.notab->answer) { db_commit_transaction(driver); db_close_database_shutdown_driver(driver); } if (nogeom > 0) G_warning(_("%d %s without geometry"), nogeom, nogeom == 1 ? "feature" : "features"); } separator = "-----------------------------------------------------"; G_message("%s", separator); if (use_tmp_vect) { /* TODO: is it necessary to build here? probably not, consumes time */ /* GV_BUILD_BASE is sufficient to toggle boundary cleaning */ Vect_build_partial(&Tmp, GV_BUILD_BASE); } if (use_tmp_vect && !flag.no_clean->answer && Vect_get_num_primitives(Out, GV_BOUNDARY) > 0) { int ret, centr, ncentr, otype, n_overlaps, n_nocat; CENTR *Centr; struct spatial_index si; double x, y, total_area, overlap_area, nocat_area; struct bound_box box; struct line_pnts *Points; int nmodif; Points = Vect_new_line_struct(); G_message("%s", separator); G_warning(_("Cleaning polygons, result is not guaranteed!")); if (snap >= 0) { G_message("%s", separator); G_message(_("Snapping boundaries (threshold = %.3e)..."), snap); Vect_snap_lines(&Tmp, GV_BOUNDARY, snap, NULL); } /* It is not to clean to snap centroids, but I have seen data with 2 duplicate polygons * (as far as decimal places were printed) and centroids were not identical */ /* Disabled, because overlapping polygons result in many duplicate centroids anyway */ /* fprintf ( stderr, separator ); fprintf ( stderr, "Snap centroids (threshold 0.000001):\n" ); Vect_snap_lines ( &Map, GV_CENTROID, 0.000001, NULL, stderr ); */ G_message("%s", separator); G_message(_("Breaking polygons...")); Vect_break_polygons(&Tmp, GV_BOUNDARY, NULL); /* It is important to remove also duplicate centroids in case of duplicate input polygons */ G_message("%s", separator); G_message(_("Removing duplicates...")); Vect_remove_duplicates(&Tmp, GV_BOUNDARY | GV_CENTROID, NULL); /* in non-pathological cases, the bulk of the cleaning is now done */ /* Vect_clean_small_angles_at_nodes() can change the geometry so that new intersections * are created. We must call Vect_break_lines(), Vect_remove_duplicates() * and Vect_clean_small_angles_at_nodes() until no more small angles are found */ do { G_message("%s", separator); G_message(_("Breaking boundaries...")); Vect_break_lines(&Tmp, GV_BOUNDARY, NULL); G_message("%s", separator); G_message(_("Removing duplicates...")); Vect_remove_duplicates(&Tmp, GV_BOUNDARY, NULL); G_message("%s", separator); G_message(_("Cleaning boundaries at nodes...")); nmodif = Vect_clean_small_angles_at_nodes(&Tmp, GV_BOUNDARY, NULL); } while (nmodif > 0); /* merge boundaries */ G_message("%s", separator); G_message(_("Merging boundaries...")); Vect_merge_lines(&Tmp, GV_BOUNDARY, NULL, NULL); G_message("%s", separator); if (type & GV_BOUNDARY) { /* that means lines were converted to boundaries */ G_message(_("Changing boundary dangles to lines...")); Vect_chtype_dangles(&Tmp, -1.0, NULL); } else { G_message(_("Removing dangles...")); Vect_remove_dangles(&Tmp, GV_BOUNDARY, -1.0, NULL); } G_message("%s", separator); if (type & GV_BOUNDARY) { G_message(_("Changing boundary bridges to lines...")); Vect_chtype_bridges(&Tmp, NULL); } else { G_message(_("Removing bridges...")); Vect_remove_bridges(&Tmp, NULL); } /* Boundaries are hopefully clean, build areas */ G_message("%s", separator); Vect_build_partial(&Tmp, GV_BUILD_ATTACH_ISLES); /* Calculate new centroids for all areas, centroids have the same id as area */ ncentr = Vect_get_num_areas(&Tmp); G_debug(3, "%d centroids/areas", ncentr); Centr = (CENTR *) G_calloc(ncentr + 1, sizeof(CENTR)); Vect_spatial_index_init(&si, 0); for (centr = 1; centr <= ncentr; centr++) { Centr[centr].valid = 0; Centr[centr].cats = Vect_new_cats_struct(); ret = Vect_get_point_in_area(&Tmp, centr, &x, &y); if (ret < 0) { G_warning(_("Unable to calculate area centroid")); continue; } Centr[centr].x = x; Centr[centr].y = y; Centr[centr].valid = 1; box.N = box.S = y; box.E = box.W = x; box.T = box.B = 0; Vect_spatial_index_add_item(&si, centr, &box); } /* Go through all layers and find centroids for each polygon */ for (layer = 0; layer < nlayers; layer++) { G_message("%s", separator); G_message(_("Finding centroids for OGR layer <%s>..."), layer_names[layer]); layer_id = layers[layer]; Ogr_layer = OGR_DS_GetLayer(Ogr_ds, layer_id); n_features = OGR_L_GetFeatureCount(Ogr_layer, 1); OGR_L_ResetReading(Ogr_layer); cat = 0; /* field = layer + 1 */ G_percent(cat, n_features, 2); while ((Ogr_feature = OGR_L_GetNextFeature(Ogr_layer)) != NULL) { cat++; G_percent(cat, n_features, 2); /* Geometry */ Ogr_geometry = OGR_F_GetGeometryRef(Ogr_feature); if (Ogr_geometry != NULL) { centroid(Ogr_geometry, Centr, &si, layer + 1, cat, min_area, type); } OGR_F_Destroy(Ogr_feature); } } /* Write centroids */ G_message("%s", separator); G_message(_("Writing centroids...")); n_overlaps = n_nocat = 0; total_area = overlap_area = nocat_area = 0.0; for (centr = 1; centr <= ncentr; centr++) { double area; G_percent(centr, ncentr, 2); area = Vect_get_area_area(&Tmp, centr); total_area += area; if (!(Centr[centr].valid)) { continue; } if (Centr[centr].cats->n_cats == 0) { nocat_area += area; n_nocat++; continue; } if (Centr[centr].cats->n_cats > 1) { Vect_cat_set(Centr[centr].cats, nlayers + 1, Centr[centr].cats->n_cats); overlap_area += area; n_overlaps++; } Vect_reset_line(Points); Vect_append_point(Points, Centr[centr].x, Centr[centr].y, 0.0); if (type & GV_POINT) otype = GV_POINT; else otype = GV_CENTROID; Vect_write_line(&Tmp, otype, Points, Centr[centr].cats); } if (Centr) G_free(Centr); Vect_spatial_index_destroy(&si); if (n_overlaps > 0) { G_warning(_("%d areas represent more (overlapping) features, because polygons overlap " "in input layer(s). Such areas are linked to more than 1 row in attribute table. " "The number of features for those areas is stored as category in layer %d"), n_overlaps, nlayers + 1); } G_message("%s", separator); Vect_hist_write(&Map, separator); Vect_hist_write(&Map, "\n"); sprintf(buf, _("%d input polygons\n"), n_polygons); G_message(_("%d input polygons"), n_polygons); Vect_hist_write(&Map, buf); sprintf(buf, _("Total area: %G (%d areas)\n"), total_area, ncentr); G_message(_("Total area: %G (%d areas)"), total_area, ncentr); Vect_hist_write(&Map, buf); sprintf(buf, _("Overlapping area: %G (%d areas)\n"), overlap_area, n_overlaps); G_message(_("Overlapping area: %G (%d areas)"), overlap_area, n_overlaps); Vect_hist_write(&Map, buf); sprintf(buf, _("Area without category: %G (%d areas)\n"), nocat_area, n_nocat); G_message(_("Area without category: %G (%d areas)"), nocat_area, n_nocat); Vect_hist_write(&Map, buf); G_message("%s", separator); } /* needed? * OGR_DS_Destroy( Ogr_ds ); */ if (use_tmp_vect) { /* Copy temporary vector to output vector */ Vect_copy_map_lines(&Tmp, &Map); /* release memory occupied by topo, we may need that memory for main output */ Vect_set_release_support(&Tmp); Vect_close(&Tmp); Vect_delete(tempvect); } Vect_build(&Map); Vect_close(&Map); /* -------------------------------------------------------------------- */ /* Extend current window based on dataset. */ /* -------------------------------------------------------------------- */ if (flag.extend->answer) { G_get_default_window(&loc_wind); loc_wind.north = MAX(loc_wind.north, cellhd.north); loc_wind.south = MIN(loc_wind.south, cellhd.south); loc_wind.west = MIN(loc_wind.west, cellhd.west); loc_wind.east = MAX(loc_wind.east, cellhd.east); loc_wind.rows = (int)ceil((loc_wind.north - loc_wind.south) / loc_wind.ns_res); loc_wind.south = loc_wind.north - loc_wind.rows * loc_wind.ns_res; loc_wind.cols = (int)ceil((loc_wind.east - loc_wind.west) / loc_wind.ew_res); loc_wind.east = loc_wind.west + loc_wind.cols * loc_wind.ew_res; G__put_window(&loc_wind, "../PERMANENT", "DEFAULT_WIND"); } if (with_z && !flag.z->answer) G_warning(_("Input data contains 3D features. Created vector is 2D only, " "use -z flag to import 3D vector.")); exit(EXIT_SUCCESS); }
int execute_random(struct rr_state *theState) { long nt; long nc; struct Cell_head window; int nrows, ncols, row, col; int infd, cinfd, outfd; struct Map_info Out; struct field_info *fi; dbTable *table; dbColumn *column; dbString sql; dbDriver *driver; struct line_pnts *Points; struct line_cats *Cats; int cat; RASTER_MAP_TYPE type; int do_check; G_get_window(&window); nrows = Rast_window_rows(); ncols = Rast_window_cols(); /* open the data files, input raster should be set-up already */ if ((infd = theState->fd_old) < 0) G_fatal_error(_("Unable to open raster map <%s>"), theState->inraster); if (theState->docover == TRUE) { if ((cinfd = theState->fd_cold) < 0) G_fatal_error(_("Unable to open raster map <%s>"), theState->inrcover); } if (theState->outraster != NULL) { if (theState->docover == TRUE) type = theState->cover.type; else type = theState->buf.type; outfd = Rast_open_new(theState->outraster, type); theState->fd_new = outfd; } if (theState->outvector) { if (Vect_open_new(&Out, theState->outvector, theState->z_geometry) < 0) G_fatal_error(_("Unable to create vector map <%s>"), theState->outvector); Vect_hist_command(&Out); fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE); driver = db_start_driver_open_database(fi->driver, Vect_subst_var(fi->database, &Out)); if (!driver) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Vect_subst_var(fi->database, &Out), fi->driver); db_set_error_handler_driver(driver); Vect_map_add_dblink(&Out, 1, NULL, fi->table, GV_KEY_COLUMN, fi->database, fi->driver); if (theState->docover == TRUE) table = db_alloc_table(3); else table = db_alloc_table(2); db_set_table_name(table, fi->table); column = db_get_table_column(table, 0); db_set_column_name(column, GV_KEY_COLUMN); db_set_column_sqltype(column, DB_SQL_TYPE_INTEGER); column = db_get_table_column(table, 1); db_set_column_name(column, "value"); db_set_column_sqltype(column, DB_SQL_TYPE_DOUBLE_PRECISION); if (theState->docover == TRUE) { column = db_get_table_column(table, 2); db_set_column_name(column, "covervalue"); db_set_column_sqltype(column, DB_SQL_TYPE_DOUBLE_PRECISION); } if (db_create_table(driver, table) != DB_OK) G_warning(_("Cannot create new table")); db_begin_transaction(driver); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); db_init_string(&sql); } if (theState->outvector && theState->outraster) G_message(_("Writing raster map <%s> and vector map <%s> ..."), theState->outraster, theState->outvector); else if (theState->outraster) G_message(_("Writing raster map <%s> ..."), theState->outraster); else if (theState->outvector) G_message(_("Writing vector map <%s> ..."), theState->outvector); G_percent(0, theState->nRand, 2); init_rand(); nc = (theState->use_nulls) ? theState->nCells : theState->nCells - theState->nNulls; nt = theState->nRand; /* Number of points to generate */ cat = 1; /* Execute for loop for every row if nt>1 */ for (row = 0; row < nrows && nt; row++) { Rast_get_row(infd, theState->buf.data.v, row, theState->buf.type); if (theState->docover == TRUE) { Rast_get_row(cinfd, theState->cover.data.v, row, theState->cover.type); } for (col = 0; col < ncols && nt; col++) { do_check = 0; if (theState->use_nulls || !is_null_value(theState->buf, col)) do_check = 1; if (do_check && theState->docover == TRUE) { /* skip no data cover points */ if (!theState->use_nulls && is_null_value(theState->cover, col)) do_check = 0; } if (do_check && make_rand() % nc < nt) { nt--; if (is_null_value(theState->buf, col)) cpvalue(&theState->nulls, 0, &theState->buf, col); if (theState->docover == TRUE) { if (is_null_value(theState->cover, col)) cpvalue(&theState->cnulls, 0, &theState->cover, col); } if (theState->outvector) { double x, y, val, coverval; char buf[500]; Vect_reset_line(Points); Vect_reset_cats(Cats); x = window.west + (col + .5) * window.ew_res; y = window.north - (row + .5) * window.ns_res; val = cell_as_dbl(&theState->buf, col); if (theState->docover == 1) coverval = cell_as_dbl(&theState->cover, col); if (theState->z_geometry) Vect_append_point(Points, x, y, val); else Vect_append_point(Points, x, y, 0.0); Vect_cat_set(Cats, 1, cat); Vect_write_line(&Out, GV_POINT, Points, Cats); if (theState->docover == 1) if (is_null_value(theState->cover, col)) sprintf(buf, "insert into %s values ( %d, %f, NULL )", fi->table, cat, val); else sprintf(buf, "insert into %s values ( %d, %f, %f )", fi->table, cat, val, coverval); else sprintf(buf, "insert into %s values ( %d, %f )", fi->table, cat, val); db_set_string(&sql, buf); if (db_execute_immediate(driver, &sql) != DB_OK) G_fatal_error(_("Cannot insert new record: %s"), db_get_string(&sql)); cat++; } G_percent((theState->nRand - nt), theState->nRand, 2); } else { set_to_null(&theState->buf, col); if (theState->docover == 1) set_to_null(&theState->cover, col); } if (do_check) nc--; } while (col < ncols) { set_to_null(&theState->buf, col); if (theState->docover == 1) set_to_null(&theState->cover, col); col++; } if (theState->outraster) { if (theState->docover == 1) Rast_put_row(outfd, theState->cover.data.v, theState->cover.type); else Rast_put_row(outfd, theState->buf.data.v, theState->buf.type); } } /* Catch any remaining rows in the window */ if (theState->outraster && row < nrows) { for (col = 0; col < ncols; col++) { if (theState->docover == 1) set_to_null(&theState->cover, col); else set_to_null(&theState->buf, col); } for (; row < nrows; row++) { if (theState->docover == 1) Rast_put_row(outfd, theState->cover.data.v, theState->cover.type); else Rast_put_row(outfd, theState->buf.data.v, theState->buf.type); } } if (nt > 0) G_warning(_("Only [%ld] random points created"), theState->nRand - nt); /* close files */ Rast_close(infd); if (theState->docover == TRUE) Rast_close(cinfd); if (theState->outvector) { db_commit_transaction(driver); if (db_create_index2(driver, fi->table, GV_KEY_COLUMN) != DB_OK) G_warning(_("Unable to create index")); if (db_grant_on_table (driver, fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) { G_fatal_error(_("Unable to grant privileges on table <%s>"), fi->table); } db_close_database_shutdown_driver(driver); if (theState->notopol != 1) Vect_build(&Out); Vect_close(&Out); } if (theState->outraster) Rast_close(outfd); return 0; } /* execute_random() */
int main(int argc, char *argv[]) { struct Map_info In, Out; static struct line_pnts *Points; struct line_cats *Cats; struct GModule *module; /* GRASS module for parsing arguments */ struct Option *map_in, *map_out; struct Option *method_opt, *afield_opt, *nfield_opt, *abcol, *afcol, *ncol; struct Flag *add_f; int with_z; int afield, nfield, mask_type; dglGraph_s *graph; int *component, nnodes, type, i, nlines, components, max_cat; char buf[2000], *covered; char *desc; /* Attribute table */ dbString sql; dbDriver *driver; struct field_info *Fi; /* initialize GIS environment */ G_gisinit(argv[0]); /* reads grass env, stores program name to G_program_name() */ /* initialize module */ module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("network")); G_add_keyword(_("components")); module->description = _("Computes strongly and weakly connected components in the network."); /* Define the different options as defined in gis.h */ map_in = G_define_standard_option(G_OPT_V_INPUT); afield_opt = G_define_standard_option(G_OPT_V_FIELD); afield_opt->key = "arc_layer"; afield_opt->answer = "1"; afield_opt->label = _("Arc layer"); afield_opt->guisection = _("Cost"); nfield_opt = G_define_standard_option(G_OPT_V_FIELD); nfield_opt->key = "node_layer"; nfield_opt->answer = "2"; nfield_opt->label = _("Node layer"); nfield_opt->guisection = _("Cost"); afcol = G_define_standard_option(G_OPT_DB_COLUMN); afcol->key = "arc_column"; afcol->required = NO; afcol->description = _("Arc forward/both direction(s) cost column (number)"); afcol->guisection = _("Cost"); abcol = G_define_standard_option(G_OPT_DB_COLUMN); abcol->key = "arc_backward_column"; abcol->required = NO; abcol->description = _("Arc backward direction cost column (number)"); abcol->guisection = _("Cost"); ncol = G_define_option(); ncol->key = "node_column"; ncol->type = TYPE_STRING; ncol->required = NO; ncol->description = _("Node cost column (number)"); ncol->guisection = _("Cost"); map_out = G_define_standard_option(G_OPT_V_OUTPUT); method_opt = G_define_option(); method_opt->key = "method"; method_opt->type = TYPE_STRING; method_opt->required = YES; method_opt->multiple = NO; method_opt->options = "weak,strong"; desc = NULL; G_asprintf(&desc, "weak;%s;strong;%s", _("Weakly connected components"), _("Strongly connected components")); method_opt->descriptions = desc; method_opt->description = _("Type of components"); add_f = G_define_flag(); add_f->key = 'a'; add_f->description = _("Add points on nodes"); /* options and flags parser */ if (G_parser(argc, argv)) exit(EXIT_FAILURE); /* TODO: make an option for this */ mask_type = GV_LINE | GV_BOUNDARY; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); Vect_check_input_output_name(map_in->answer, map_out->answer, G_FATAL_EXIT); Vect_set_open_level(2); if (1 > Vect_open_old(&In, map_in->answer, "")) G_fatal_error(_("Unable to open vector map <%s>"), map_in->answer); with_z = Vect_is_3d(&In); if (0 > Vect_open_new(&Out, map_out->answer, with_z)) { Vect_close(&In); G_fatal_error(_("Unable to create vector map <%s>"), map_out->answer); } /* parse filter option and select appropriate lines */ afield = Vect_get_field_number(&In, afield_opt->answer); nfield = Vect_get_field_number(&In, nfield_opt->answer); if (0 != Vect_net_build_graph(&In, mask_type, afield, nfield, afcol->answer, abcol->answer, ncol->answer, 0, 2)) G_fatal_error(_("Unable to build graph for vector map <%s>"), Vect_get_full_name(&In)); graph = Vect_net_get_graph(&In); nnodes = Vect_get_num_nodes(&In); component = (int *)G_calloc(nnodes + 1, sizeof(int)); covered = (char *)G_calloc(nnodes + 1, sizeof(char)); if (!component || !covered) { G_fatal_error(_("Out of memory")); exit(EXIT_FAILURE); } /* Create table */ Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE); Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database, Fi->driver); db_init_string(&sql); 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); sprintf(buf, "create table %s ( cat integer, comp integer)", Fi->table); db_set_string(&sql, buf); G_debug(2, "%s", db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { db_close_database_shutdown_driver(driver); G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&sql)); } if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK) G_warning(_("Cannot create index")); if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Cannot grant privileges on table <%s>"), Fi->table); db_begin_transaction(driver); if (method_opt->answer[0] == 'w') { G_message(_("Computing weakly connected components...")); components = NetA_weakly_connected_components(graph, component); } else { G_message(_("Computing strongly connected components...")); components = NetA_strongly_connected_components(graph, component); } G_debug(3, "Components: %d", components); G_message(_("Writing output...")); Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); nlines = Vect_get_num_lines(&In); max_cat = 1; G_percent(0, nlines, 4); for (i = 1; i <= nlines; i++) { int comp, cat; G_percent(i, nlines, 4); type = Vect_read_line(&In, Points, Cats, i); if (!Vect_cat_get(Cats, afield, &cat)) continue; if (type == GV_LINE || type == GV_BOUNDARY) { int node1, node2; Vect_get_line_nodes(&In, i, &node1, &node2); if (component[node1] == component[node2]) { comp = component[node1]; } else { continue; } } else if (type == GV_POINT) { int node; /* Vect_get_line_nodes(&In, i, &node, NULL); */ node = Vect_find_node(&In, Points->x[0], Points->y[0], Points->z[0], 0, 0); if (!node) continue; comp = component[node]; covered[node] = 1; } else continue; cat = max_cat++; Vect_reset_cats(Cats); Vect_cat_set(Cats, 1, cat); Vect_write_line(&Out, type, Points, Cats); insert_new_record(driver, Fi, &sql, cat, comp); } /*add points on nodes not covered by any point in the network */ if (add_f->answer) { for (i = 1; i <= nnodes; i++) if (!covered[i]) { Vect_reset_cats(Cats); Vect_cat_set(Cats, 1, max_cat); NetA_add_point_on_node(&In, &Out, i, Cats); insert_new_record(driver, Fi, &sql, max_cat++, component[i]); } } db_commit_transaction(driver); db_close_database_shutdown_driver(driver); Vect_close(&In); Vect_build(&Out); Vect_close(&Out); G_done_msg(_("Found %d components."), components); exit(EXIT_SUCCESS); }
int main(int argc, char *argv[]) { struct GModule *module; struct Option *in_opt, *out_opt, *feature_opt, *column_name; struct Flag *smooth_flg, *value_flg, *z_flg, *no_topol; int feature; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("raster")); G_add_keyword(_("conversion")); G_add_keyword(_("geometry")); G_add_keyword(_("vectorization")); module->description = _("Converts a raster map into a vector map."); in_opt = G_define_standard_option(G_OPT_R_INPUT); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); feature_opt = G_define_standard_option(G_OPT_V_TYPE); feature_opt->required = YES; feature_opt->multiple = NO; feature_opt->options = "point,line,area"; feature_opt->answer = NULL; column_name = G_define_standard_option(G_OPT_DB_COLUMN); column_name->label = _("Name of attribute column to store value"); column_name->description = _("Name must be SQL compliant"); column_name->answer = "value"; smooth_flg = G_define_flag(); smooth_flg->key = 's'; smooth_flg->description = _("Smooth corners of area features"); value_flg = G_define_flag(); value_flg->key = 'v'; value_flg->description = _("Use raster values as categories instead of unique sequence (CELL only)"); value_flg->guisection = _("Attributes"); z_flg = G_define_flag(); z_flg->key = 'z'; z_flg->label = _("Write raster values as z coordinate"); z_flg->description = _("Table is not created. " "Currently supported only for points."); z_flg->guisection = _("Attributes"); no_topol = G_define_flag(); no_topol->key = 'b'; no_topol->label = _("Do not build vector topology"); no_topol->description = _("Recommended for massive point conversion"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); feature = Vect_option_to_types(feature_opt); smooth_flag = (smooth_flg->answer) ? SMOOTH : NO_SMOOTH; value_flag = value_flg->answer; if (z_flg->answer && (feature != GV_POINT)) G_fatal_error(_("z flag is supported only for points")); /* Open files */ input_fd = Rast_open_old(in_opt->answer, ""); data_type = Rast_get_map_type(input_fd); data_size = Rast_cell_size(data_type); G_get_window(&cell_head); if (value_flag && data_type != CELL_TYPE) { G_warning(_("Raster is not CELL, '-v' flag ignored, raster values will be written to the table.")); value_flag = 0; } if (z_flg->answer) Vect_open_new(&Map, out_opt->answer, 1); else Vect_open_new(&Map, out_opt->answer, 0); Vect_hist_command(&Map); Cats = Vect_new_cats_struct(); /* Open category labels */ if (data_type == CELL_TYPE) { if (0 == Rast_read_cats(in_opt->answer, "", &RastCats)) has_cats = 1; } else has_cats = 0; db_init_string(&sql); db_init_string(&label); /* Create table */ if ((feature & (GV_AREA | GV_POINT | GV_LINE)) && (!value_flag || (value_flag && has_cats)) && !(z_flg->answer)) { char buf[1000]; Fi = Vect_default_field_info(&Map, 1, NULL, GV_1TABLE); Vect_map_add_dblink(&Map, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database, Fi->driver); driver = db_start_driver_open_database(Fi->driver, Vect_subst_var(Fi->database, &Map)); if (driver == NULL) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Fi->database, Fi->driver); /* Create new table */ db_zero_string(&sql); sprintf(buf, "create table %s ( cat integer", Fi->table); db_append_string(&sql, buf); if (!value_flag) { /* add value to the table */ if (data_type == CELL_TYPE) { db_append_string(&sql, ", "); db_append_string(&sql, column_name->answer); db_append_string(&sql, " integer"); } else { db_append_string(&sql, ","); db_append_string(&sql, column_name->answer); db_append_string(&sql, " double precision"); } } if (has_cats) { int i, len; int clen = 0; /* Get maximum column length */ for (i = 0; i < RastCats.ncats; i++) { len = strlen(RastCats.labels[i]); if (len > clen) clen = len; } clen += 10; sprintf(buf, ", label varchar(%d)", clen); db_append_string(&sql, buf); } db_append_string(&sql, ")"); G_debug(3, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) G_fatal_error(_("Unable to create table: %s"), db_get_string(&sql)); if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK) G_warning(_("Unable to create index")); if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Unable to grant privileges on table <%s>"), Fi->table); db_begin_transaction(driver); } else { driver = NULL; } /* init variables for lines and areas */ first_read = 1; last_read = 0; direction = FORWARD; row_length = cell_head.cols; n_rows = cell_head.rows; row_count = 0; if (feature == GV_LINE) { alloc_lines_bufs(row_length + 2); extract_lines(); } else if (feature == GV_AREA) { alloc_areas_bufs(row_length + 2); extract_areas(); } else { /* GV_POINT */ extract_points(z_flg->answer); } Rast_close(input_fd); if (!no_topol->answer) Vect_build(&Map); /* insert cats and optionally labels if raster cats were used */ if (driver && value_flag) { char buf[1000]; int c, i, cat, fidx, ncats, lastcat, tp, id; fidx = Vect_cidx_get_field_index(&Map, 1); if (fidx >= 0) { ncats = Vect_cidx_get_num_cats_by_index(&Map, fidx); lastcat = -1; for (c = 0; c < ncats; c++) { Vect_cidx_get_cat_by_index(&Map, fidx, c, &cat, &tp, &id); if (lastcat == cat) continue; /* find label, slow -> TODO faster */ db_set_string(&label, ""); for (i = 0; i < RastCats.ncats; i++) { if (cat == (int)RastCats.q.table[i].dLow) { /* cats are in dLow/High not in cLow/High !!! */ db_set_string(&label, RastCats.labels[i]); db_double_quote_string(&label); break; } } G_debug(3, "cat = %d label = %s", cat, db_get_string(&label)); sprintf(buf, "insert into %s values ( %d, '%s')", Fi->table, cat, db_get_string(&label)); db_set_string(&sql, buf); G_debug(3, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) G_fatal_error(_("Unable to insert into table: %s"), db_get_string(&sql)); lastcat = cat; } } } if (has_cats) Rast_free_cats(&RastCats); if (driver != NULL) { db_commit_transaction(driver); db_close_database_shutdown_driver(driver); } Vect_close(&Map); G_done_msg(" "); exit(EXIT_SUCCESS); }
/* Create GRASS vector output map. Create attribute table. Calculate geometries and write them into the output map. Calculate attributes and write them into the output map's attribute table. */ void writeMap() { int i, j; double xlength, ylength, zlength; double length, flatLength, bailLength; double xoffset, yoffset, zoffset; double xys[12]; int ratio; double zRatio; /* attributes to be written to output map */ int boneID; int skelID; int unitID; int oldID; int cat; char *organization; char buf[MAXSTR]; if ( numPoints < 2 ) { G_fatal_error ("Less than two valid measurement points in input file"); } G_message (_("Constructing geometries for %i valid points:"), numPoints ); /* CREATE OUTPUT VECTOR MAP */ if (Vect_legal_filename(output->answer) < 0) { G_fatal_error(_("Use '%s' option to change vector map name"), output->key); } Map = (struct Map_info *) G_malloc (sizeof ( struct Map_info ) ); if (Vect_open_new(Map, output->answer, WITH_Z) < 0) { G_fatal_error(_("Unable to create vector map <%s>"), output->answer); } Vect_set_map_name(Map, output->answer); Vect_hist_command(Map); if ((organization = getenv("GRASS_ORGANIZATION"))) { Vect_set_organization(Map, organization); } else { Vect_set_organization(Map, "UNKNOWN ORGANIZATION"); } Vect_set_date(Map, G_date()); Vect_set_person(Map, G_whoami()); Vect_set_map_date(Map, ""); Vect_set_scale(Map, 2400); Vect_set_comment(Map, ""); Vect_set_zone(Map, 0); Vect_set_thresh(Map, 0.0); /* START DBMS INTERFACE */ /* prepare strings for use in db_* calls */ db_init_string(&sql); /* start default database driver */ Fi = Vect_default_field_info(Map, 1, NULL, GV_1TABLE); driver = db_start_driver_open_database(Fi->driver,Vect_subst_var(Fi->database, Map)); if (driver == NULL) { Vect_delete(output->answer); G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Vect_subst_var(Fi->database, Map), Fi->driver); } /* create attribute table */ db_begin_transaction ( driver ); sprintf(buf, "create table %s (cat integer, skel_id integer, bone_id integer, unit_id integer, GRASSRGB varchar(11),BONERGB varchar(11));", Fi->table); if ( DEBUG ) { fprintf ( stderr, "Creating attribute table: %s\n", buf ); } db_set_string(&sql, buf); if (db_execute_immediate(driver, &sql) != DB_OK) { Vect_delete(output->answer); G_fatal_error(_("Unable to create attribute table: %s"), db_get_string(&sql)); } if (db_grant_on_table (driver, output->answer, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) { Vect_delete(output->answer); G_fatal_error(_("Unable to grant privileges on table <%s>"), output->answer); } if (db_create_index2(driver, output->answer, "cat") != DB_OK) { G_warning(_("Unable to create index for table <%s>, key <%s>"), output->answer, "cat"); } /* link vector map to attribute table */ if (Vect_map_add_dblink(Map, 1, NULL, Fi->table, "cat", Fi->database, Fi->driver) ) { Vect_delete(output->answer); G_fatal_error(_("Unable to add database link for vector map <%s>"), Vect_get_full_name(Map)); } /* PROCESS POINTS AND WRITE GEOMETRIES */ /* Now process point measurements and write geometries into output vector map. */ /* At this stage, the global points array has an even number of valid points. */ oldID = pointTable[0].SKEL_ID; unitID = 1; cat = 0; for ( i = 0; i < numPoints; i = i + 2 ) { /* This boneID is a generalized ID that does not differentiate between start and end measurement. */ boneID = (int) pointTable[i+1].BONE_ID / 2; skelID = pointTable[i+1].SKEL_ID; /* get coordinates for top and bottom of bone */ ax = pointTable[i].X; ay = pointTable[i].Y; az = pointTable[i].Z; bx = pointTable[i+1].X; by = pointTable[i+1].Y; bz = pointTable[i+1].Z; /* get vector lengths */ xlength = fabs (ax - bx); ylength = fabs (ay - by); zlength = fabs (az - bz); /* get real length */ length = sqrt ( (xlength*xlength) + (ylength*ylength) + (zlength*zlength) ); /* get length in x/y plane */ flatLength = sqrt ( (xlength*xlength) + (ylength*ylength) ); /* determine ratio for triangles, depending on bone type */ ratio = 12; /* default */ for ( j = 0; j < NUM_RATIOS; j ++ ) { if ( boneID == RATIO_ID[j] ) { ratio = RATIO_VAL[j]; } } /* get bail length */ bailLength = (double) ( length / (double) ratio); /* calculate bail offsets from top point (one bail is mirror of the other) */ xoffset = (bailLength * ylength) / flatLength; yoffset = ( (bailLength * xlength) / flatLength ) * (-1); zoffset = 0; xys[0]= ax + xoffset; xys[1]= ay + yoffset; xys[2]= az + zoffset; xys[6]= ax - xoffset; xys[7]= ay - yoffset; xys[8]= az - zoffset; /* get 3rd axis offsets */ zRatio = (zlength/ratio) / flatLength; xoffset = xlength * zRatio; yoffset = ylength * zRatio; zoffset = (flatLength/ratio) * (-1); xys[3]= ax + xoffset; xys[4]= ay + yoffset; xys[5]= az + zoffset; xys[9]= ax - xoffset; xys[10]= ay - yoffset; xys[11]= az - zoffset; /* Increase unit ID by "1", if we have another skeleton ID */ if ( oldID != pointTable[i+1].SKEL_ID ) { unitID ++; oldID = pointTable[i+1].SKEL_ID; /* switch to next colour for next geometry */ RGBNUM ++; if ( RGBNUM == RGBMAX ) { RGBNUM = 0; } } /* write geometries */ if ( MODE == MODE_DARTS ) { writeTriangle ( cat, skelID, boneID, unitID, xys, 0, 6 ); cat ++; writeTriangle ( cat, skelID, boneID, unitID, xys, 3, 9 ); cat ++; } if ( MODE == MODE_LINES ) { writeLine ( cat, skelID, boneID, unitID ); cat ++; } if ( MODE == MODE_PLANES_H ) { writeTriangle ( cat, skelID, boneID, unitID, xys, 0, 6 ); cat ++; } if ( MODE == MODE_PLANES_V ) { writeTriangle ( cat, skelID, boneID, unitID, xys, 3, 9 ); cat ++; } if ( MODE == MODE_POINTS ) { writePoints ( cat, skelID, boneID, unitID ); cat = cat + 2; } if ( MODE == MODE_PYRAMIDS ) { writeTriangle ( cat, skelID, boneID, unitID, xys, 0, 3 ); cat ++; writeTriangle ( cat, skelID, boneID, unitID, xys, 3, 6 ); cat ++; writeTriangle ( cat, skelID, boneID, unitID, xys, 6, 9 ); cat ++; writeTriangle ( cat, skelID, boneID, unitID, xys, 9, 0 ); cat ++; writeSquare ( cat, skelID, boneID, unitID, xys ); cat ++; } /* switch to next colour for bone colouring */ RGBNUM_BONE ++; if ( RGBNUM_BONE == RGBMAX ) { RGBNUM_BONE = 0; } G_percent ( i, numPoints - 2, 1 ); } fprintf ( stdout, "\n" ); /* commit DBMS actions */ db_commit_transaction(driver); db_close_database_shutdown_driver(driver); if (!Vect_build(Map)) { G_warning("Building topology failed"); } Vect_close(Map); db_free_string(&sql); }
int main(int argc, char *argv[]) { struct GModule *module; struct Option *out_opt, *in_opt; struct Flag *z_flag, *circle_flag, *l_flag, *int_flag; char buf[2000]; /* DWG */ char path[2000]; short initerror, entset, retval; AD_OBJHANDLE pspace, mspace; PAD_ENT_HDR adenhd; PAD_ENT aden; AD_VMADDR entlist; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("import")); module->description = _("Converts DWG/DXF to GRASS vector map"); in_opt = G_define_standard_option(G_OPT_F_INPUT); in_opt->description = _("Name of DWG or DXF file"); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); out_opt->required = YES; layers_opt = G_define_option(); layers_opt->key = "layers"; layers_opt->type = TYPE_STRING; layers_opt->required = NO; layers_opt->multiple = YES; layers_opt->description = _("List of layers to import"); invert_flag = G_define_flag(); invert_flag->key = 'i'; invert_flag->description = _("Invert selection by layers (don't import layers in list)"); z_flag = G_define_flag(); z_flag->key = 'z'; z_flag->description = _("Create 3D vector map"); circle_flag = G_define_flag(); circle_flag->key = 'c'; circle_flag->description = _("Write circles as points (centre)"); l_flag = G_define_flag(); l_flag->key = 'l'; l_flag->description = _("List available layers and exit"); int_flag = G_define_flag(); int_flag->key = 'n'; int_flag->description = _("Use numeric type for attribute \"layer\""); if (G_parser(argc, argv)) exit(EXIT_FAILURE); db_init_string(&sql); db_init_string(&str); adenhd = (PAD_ENT_HDR) G_malloc(sizeof(AD_ENT_HDR)); aden = (PAD_ENT) G_malloc(sizeof(AD_ENT)); Layer = (PAD_LAY) G_malloc(sizeof(AD_LAY)); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); Block = NULL; atrans = 20; /* nested, recursive levels */ Trans = (TRANS *) G_malloc(atrans * sizeof(TRANS)); /* Init OpenDWG */ sprintf(path, "%s/etc/adinit.dat", G_gisbase()); if (!adInitAd2(path, &initerror)) { sprintf(buf, _("Unable to initialize OpenDWG Toolkit, error: %d: %s."), initerror, adErrorStr(initerror)); if (initerror == AD_UNABLE_TO_OPEN_INIT_FILE) sprintf(buf, _("%s Cannot open %s"), buf, path); G_fatal_error(buf); } adSetupDwgRead(); adSetupDxfRead(); /* Open input file */ if ((dwghandle = adLoadFile(in_opt->answer, AD_PRELOAD_ALL, 1)) == NULL) { G_fatal_error(_("Unable to open input file <%s>. Error %d: %s"), in_opt->answer, adError(), adErrorStr(adError())); } if (l_flag->answer) { /* List layers */ PAD_TB adtb; AD_DWGHDR adhd; int i; char on, frozen, vpfrozen, locked; adtb = (PAD_TB) G_malloc(sizeof(AD_TB)); G_debug(2, "%d layers", (int)adNumLayers(dwghandle)); adReadHeaderBlock(dwghandle, &adhd); adStartLayerGet(dwghandle); fprintf(stdout, "%d layers:\n", (int)adNumLayers(dwghandle)); for (i = 0; i < (int)adNumLayers(dwghandle); i++) { adGetLayer(dwghandle, &(adtb->lay)); if (!adtb->lay.purgedflag) { fprintf(stdout, "%s COLOR %d, ", adtb->lay.name, adtb->lay.color); } adGetLayerState(dwghandle, adtb->lay.objhandle, &on, &frozen, &vpfrozen, &locked); if (on) fprintf(stdout, "ON, "); else fprintf(stdout, "OFF, "); if (frozen) fprintf(stdout, "FROZEN, "); else fprintf(stdout, "THAWED, "); if (vpfrozen) fprintf(stdout, "VPFROZEN, "); else fprintf(stdout, "VPTHAWED, "); if (locked) fprintf(stdout, "LOCKED\n"); else fprintf(stdout, "UNLOCKED\n"); } adCloseFile(dwghandle); adCloseAd2(); exit(EXIT_SUCCESS); } /* open output vector */ if (Vect_open_new(&Map, out_opt->answer, z_flag->answer) < 0) G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer); Vect_hist_command(&Map); /* Add DB link */ Fi = Vect_default_field_info(&Map, 1, NULL, GV_1TABLE); Vect_map_add_dblink(&Map, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database, Fi->driver); driver = db_start_driver_open_database(Fi->driver, Vect_subst_var(Fi->database, &Map)); if (driver == NULL) { G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Vect_subst_var(Fi->database, &Map), Fi->driver); } db_set_error_handler_driver(driver); db_begin_transaction(driver); /* Create table */ if (int_flag->answer) { /* List layers */ sprintf(buf, "create table %s ( cat integer, entity_name varchar(20), color int, weight int, " "layer real, block varchar(100), txt varchar(100) )", Fi->table); } else { sprintf(buf, "create table %s ( cat integer, entity_name varchar(20), color int, weight int, " "layer varchar(100), block varchar(100), txt varchar(100) )", Fi->table); } db_set_string(&sql, buf); G_debug(3, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { db_close_database(driver); db_shutdown_driver(driver); G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&sql)); } if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK) G_warning(_("Unable to create index for table <%s>, key <%s>"), Fi->table, GV_KEY_COLUMN); if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Unable to grant privileges on table <%s>"), Fi->table); cat = 1; n_elements = n_skipped = 0; /* Write each entity. Some entities may be composed by other entities (like INSERT or BLOCK) */ /* Set transformation for first (index 0) level */ Trans[0].dx = Trans[0].dy = Trans[0].dz = 0; Trans[0].xscale = Trans[0].yscale = Trans[0].zscale = 1; Trans[0].rotang = 0; if (adGetBlockHandle(dwghandle, pspace, AD_PAPERSPACE_HANDLE)) { entlist = adEntityList(dwghandle, pspace); adStartEntityGet(entlist); for (entset = 0; entset < 2; entset++) { do { if (!(retval = adGetEntity(entlist, adenhd, aden))) continue; wrentity(adenhd, aden, 0, entlist, circle_flag->answer); } while (retval == 1); if (entset == 0) { if (adGetBlockHandle(dwghandle, mspace, AD_MODELSPACE_HANDLE)) { entlist = adEntityList(dwghandle, mspace); adStartEntityGet(entlist); } } } } db_commit_transaction(driver); db_close_database_shutdown_driver(driver); adCloseFile(dwghandle); adCloseAd2(); Vect_build(&Map, stderr); Vect_close(&Map); if (n_skipped > 0) G_message(_("%d elements skipped (layer name was not in list)"), n_skipped); G_done_msg(_("%d elements processed"), n_elements); exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { int field, type, vertex_type; double dmax; char buf[DB_SQL_MAX]; struct { struct Option *input, *output, *type, *dmax, *lfield, *use; } opt; struct { struct Flag *table, *inter; } flag; struct GModule *module; struct Map_info In, Out; struct line_cats *LCats; struct line_pnts *LPoints; dbDriver *driver; struct field_info *Fi; dbString stmt; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("geometry")); G_add_keyword("3D"); G_add_keyword(_("node")); G_add_keyword(_("vertex")); module->description = _("Creates points along input lines in new vector map with 2 layers."); opt.input = G_define_standard_option(G_OPT_V_INPUT); opt.lfield = G_define_standard_option(G_OPT_V_FIELD); opt.lfield->key = "llayer"; opt.lfield->answer = "1"; opt.lfield->label = "Line layer number or name"; opt.lfield->guisection = _("Selection"); opt.type = G_define_standard_option(G_OPT_V3_TYPE); opt.type->answer = "point,line,boundary,centroid,face"; opt.type->guisection = _("Selection"); opt.output = G_define_standard_option(G_OPT_V_OUTPUT); opt.use = G_define_option(); opt.use->key = "use"; opt.use->type = TYPE_STRING; opt.use->required = NO; opt.use->description = _("Use line nodes or vertices only"); opt.use->options = "node,vertex"; opt.dmax = G_define_option(); opt.dmax->key = "dmax"; opt.dmax->type = TYPE_DOUBLE; opt.dmax->required = NO; opt.dmax->answer = "100"; opt.dmax->description = _("Maximum distance between points in map units"); flag.inter = G_define_flag(); flag.inter->key = 'i'; flag.inter->description = _("Interpolate points between line vertices (only for use=vertex)"); flag.table = G_define_standard_flag(G_FLG_V_TABLE); if (G_parser(argc, argv)) exit(EXIT_FAILURE); LCats = Vect_new_cats_struct(); LPoints = Vect_new_line_struct(); db_init_string(&stmt); type = Vect_option_to_types(opt.type); dmax = atof(opt.dmax->answer); vertex_type = 0; if (opt.use->answer) { if (opt.use->answer[0] == 'n') vertex_type = GV_NODE; else vertex_type = GV_VERTEX; } Vect_check_input_output_name(opt.input->answer, opt.output->answer, G_FATAL_EXIT); /* Open input lines */ Vect_set_open_level(2); if (Vect_open_old2(&In, opt.input->answer, "", opt.lfield->answer) < 0) G_fatal_error(_("Unable to open vector map <%s>"), opt.input->answer); Vect_set_error_handler_io(&In, &Out); field = Vect_get_field_number(&In, opt.lfield->answer); /* Open output segments */ if (Vect_open_new(&Out, opt.output->answer, Vect_is_3d(&In)) < 0) G_fatal_error(_("Unable to create vector map <%s>"), opt.output->answer); Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); /* Table */ Fi = NULL; if (!flag.table->answer) { struct field_info *Fin; /* copy input table */ Fin = Vect_get_field(&In, field); if (Fin) { /* table defined */ int ret; Fi = Vect_default_field_info(&Out, 1, NULL, GV_MTABLE); Vect_map_add_dblink(&Out, 1, NULL, Fi->table, Fin->key, Fi->database, Fi->driver); ret = db_copy_table(Fin->driver, Fin->database, Fin->table, Fi->driver, Vect_subst_var(Fi->database, &Out), Fi->table); if (ret == DB_FAILED) { G_fatal_error(_("Unable to copy table <%s>"), Fin->table); } } Fi = Vect_default_field_info(&Out, 2, NULL, GV_MTABLE); Vect_map_add_dblink(&Out, 2, NULL, Fi->table, GV_KEY_COLUMN, Fi->database, Fi->driver); /* Open driver */ 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); if (field == -1) sprintf(buf, "create table %s ( cat int, along double precision )", Fi->table); else sprintf(buf, "create table %s ( cat int, lcat int, along double precision )", Fi->table); db_append_string(&stmt, buf); if (db_execute_immediate(driver, &stmt) != DB_OK) { G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&stmt)); } if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK) G_warning(_("Unable to create index for table <%s>, key <%s>"), Fi->table, GV_KEY_COLUMN); if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Unable to grant privileges on table <%s>"), Fi->table); db_begin_transaction(driver); } if (type & (GV_POINTS | GV_LINES | GV_FACE)) { int line, nlines, nskipped; nskipped = 0; nlines = Vect_get_num_lines(&In); for (line = 1; line <= nlines; line++) { int ltype, cat; G_debug(3, "line = %d", line); G_percent(line, nlines, 2); ltype = Vect_read_line(&In, LPoints, LCats, line); if (!(ltype & type)) continue; if (!Vect_cat_get(LCats, field, &cat) && field != -1) { nskipped++; continue; } /* Assign CAT for layer 0 objects (i.e. boundaries) */ if (field == -1) cat = -1; if (LPoints->n_points <= 1) { write_point(&Out, LPoints->x[0], LPoints->y[0], LPoints->z[0], cat, 0.0, driver, Fi); } else { /* lines */ write_line(&Out, LPoints, cat, vertex_type, flag.inter->answer, dmax, driver, Fi); } } if (nskipped > 0) G_warning(_("%d features without category in layer <%d> skipped. " "Note that features without category (usually boundaries) are not " "skipped when '%s=-1' is given."), nskipped, field, opt.lfield->key); } if (type == GV_AREA) { int area, nareas, centroid, cat; nareas = Vect_get_num_areas(&In); for (area = 1; area <= nareas; area++) { int i, isle, nisles; G_percent(area, nareas, 2); centroid = Vect_get_area_centroid(&In, area); cat = -1; if (centroid > 0) { Vect_read_line(&In, NULL, LCats, centroid); if (!Vect_cat_get(LCats, field, &cat)) continue; } Vect_get_area_points(&In, area, LPoints); write_line(&Out, LPoints, cat, vertex_type, flag.inter->answer, dmax, driver, Fi); nisles = Vect_get_area_num_isles(&In, area); for (i = 0; i < nisles; i++) { isle = Vect_get_area_isle(&In, area, i); Vect_get_isle_points(&In, isle, LPoints); write_line(&Out, LPoints, cat, vertex_type, flag.inter->answer, dmax, driver, Fi); } } } if (!flag.table->answer) { db_commit_transaction(driver); db_close_database_shutdown_driver(driver); } Vect_build(&Out); /* Free, close ... */ Vect_close(&In); G_done_msg(_("%d points written to output vector map."), Vect_get_num_primitives(&Out, GV_POINT)); Vect_close(&Out); exit(EXIT_SUCCESS); }
int main(int argc, char *argv[]) { /* loop */ int i, j; /* store filename and path */ char *dig_file; char buf[2000]; /* Other local variables */ int attCount, nbreaks; struct grid_description grid_info; struct Cell_head window; struct Map_info Map; struct Option *vectname, *grid, *coord, *box, *angle, *position_opt, *breaks; struct GModule *module; struct Flag *points_fl, *line_fl; int points_p, line_p, output_type; char *desc; struct line_pnts *Points; struct line_cats *Cats; /* Attributes */ struct field_info *Fi; dbDriver *Driver; dbString sql; G_gisinit(argv[0]); /* Set description */ module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("geometry")); module->description = _("Creates a vector map of a user-defined grid."); vectname = G_define_standard_option(G_OPT_V_OUTPUT); vectname->key = "map"; grid = G_define_option(); grid->key = "grid"; grid->key_desc = _("rows,columns"); grid->type = TYPE_INTEGER; grid->required = YES; grid->multiple = NO; grid->description = _("Number of rows and columns in grid"); position_opt = G_define_option(); position_opt->key = "position"; position_opt->type = TYPE_STRING; position_opt->required = NO; position_opt->multiple = NO; position_opt->options = "region,coor"; position_opt->answer = "region"; position_opt->description = _("Where to place the grid"); desc = NULL; G_asprintf(&desc, "region;%s;coor;%s", _("current region"), _("use 'coor' and 'box' options")); position_opt->descriptions = desc; coord = G_define_option(); coord->key = "coor"; coord->key_desc = "x,y"; coord->type = TYPE_DOUBLE; coord->required = NO; coord->multiple = NO; coord->description = _("Lower left easting and northing coordinates of map"); box = G_define_option(); box->key = "box"; box->key_desc = _("width,height"); box->type = TYPE_DOUBLE; box->required = NO; box->multiple = NO; box->description = _("Width and height of boxes in grid"); angle = G_define_option(); angle->key = "angle"; angle->type = TYPE_DOUBLE; angle->required = NO; angle->description = _("Angle of rotation (in degrees counter-clockwise)"); angle->answer = "0"; breaks = G_define_option(); breaks->key = "breaks"; breaks->type = TYPE_INTEGER; breaks->required = NO; breaks->description = _("Number of vertex points per grid cell"); breaks->options = "0-60"; breaks->answer = "3"; points_fl = G_define_flag(); points_fl->key = 'p'; points_fl->description = _("Create grid of points instead of areas and centroids"); line_fl = G_define_flag(); line_fl->key = 'l'; line_fl->description = _("Create grid as lines, instead of areas"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); line_p = line_fl->answer; if (line_p) { output_type = GV_LINE; } else { output_type = GV_BOUNDARY; } points_p = points_fl->answer; /* get the current window */ G_get_window(&window); /* * information we need to collect from user: origin point x and y (lower * left), shift in x, shift in y, number of rows, number of cols */ dig_file = G_store(vectname->answer); /* Number of row and cols */ grid_info.num_rows = atoi(grid->answers[0]); grid_info.num_cols = atoi(grid->answers[1]); grid_info.angle = M_PI / 180 * atof(angle->answer); nbreaks = atoi(breaks->answer); /* Position */ if (position_opt->answer[0] == 'r') { /* region */ if (coord->answer) G_fatal_error(_("'coor' and 'position=region' are exclusive options")); if (box->answer) G_fatal_error(_("'box' and 'position=region' are exclusive options")); if (grid_info.angle != 0.0) G_fatal_error(_("'angle' and 'position=region' are exclusive options")); grid_info.origin_x = window.west; grid_info.origin_y = window.south; grid_info.length = (window.east - window.west) / grid_info.num_cols; grid_info.width = (window.north - window.south) / grid_info.num_rows; G_debug(2, "x = %e y = %e l = %e w = %e", grid_info.origin_x, grid_info.origin_y, grid_info.length, grid_info.width); } else { if (!coord->answer) G_fatal_error(_("'coor' option missing")); if (!box->answer) G_fatal_error(_("'box' option missing")); if (!G_scan_easting (coord->answers[0], &(grid_info.origin_x), window.proj)) G_fatal_error(_("Invalid easting"));; if (!G_scan_northing (coord->answers[1], &(grid_info.origin_y), window.proj)) G_fatal_error(_("Invalid northing"));; if (!G_scan_resolution (box->answers[0], &(grid_info.length), window.proj)) G_fatal_error(_("Invalid distance"));; if (!G_scan_resolution (box->answers[1], &(grid_info.width), window.proj)) G_fatal_error(_("Invalid distance"));; } /* * vector rows are the actual number of rows of vectors to make up the * entire grid. ditto for cols. */ grid_info.num_vect_rows = grid_info.num_rows + 1; grid_info.num_vect_cols = grid_info.num_cols + 1; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); db_init_string(&sql); /* Open output map */ if (0 > Vect_open_new(&Map, dig_file, 0)) { G_fatal_error(_("Unable to create vector map <%s>"), dig_file); } Vect_hist_command(&Map); /* Open database, create table */ Fi = Vect_default_field_info(&Map, 1, NULL, GV_1TABLE); Vect_map_add_dblink(&Map, Fi->number, Fi->name, Fi->table, Fi->key, Fi->database, Fi->driver); Driver = db_start_driver_open_database(Fi->driver, Vect_subst_var(Fi->database, &Map)); if (Driver == NULL) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Fi->database, Fi->driver); db_set_error_handler_driver(Driver); if (grid_info.num_rows < 27 && grid_info.num_cols < 27) { sprintf(buf, "create table %s ( cat integer, row integer, col integer, " "rown varchar(1), coln varchar(1))", Fi->table); } else { sprintf(buf, "create table %s ( cat integer, row integer, col integer)", Fi->table); } db_set_string(&sql, buf); G_debug(1, "SQL: %s", db_get_string(&sql)); if (db_execute_immediate(Driver, &sql) != DB_OK) { G_fatal_error(_("Unable to create table: %s"), db_get_string(&sql)); } if (db_create_index2(Driver, Fi->table, Fi->key) != DB_OK) G_warning(_("Unable to create index")); if (db_grant_on_table (Driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Unable to grant privileges on table <%s>"), Fi->table); if (!points_p) { /* create areas */ write_grid(&grid_info, &Map, nbreaks, output_type); } /* Create a grid of label points at the centres of the grid cells */ G_verbose_message(_("Creating centroids...")); /* Write out centroids and attributes */ /* If the output id is lines it skips to add centroids and attributes TODO decide what to write in the attribute table */ if (!line_p) { db_begin_transaction(Driver); attCount = 0; for (i = 0; i < grid_info.num_rows; ++i) { for (j = 0; j < grid_info.num_cols; ++j) { double x, y; const int point_type = points_p ? GV_POINT : GV_CENTROID; x = grid_info.origin_x + (0.5 + j) * grid_info.length; y = grid_info.origin_y + (0.5 + i) * grid_info.width; rotate(&x, &y, grid_info.origin_x, grid_info.origin_y, grid_info.angle); Vect_reset_line(Points); Vect_reset_cats(Cats); Vect_append_point(Points, x, y, 0.0); Vect_cat_set(Cats, 1, attCount + 1); Vect_write_line(&Map, point_type, Points, Cats); sprintf(buf, "insert into %s values ", Fi->table); if (db_set_string(&sql, buf) != DB_OK) G_fatal_error(_("Unable to fill attribute table")); if (grid_info.num_rows < 27 && grid_info.num_cols < 27) { sprintf(buf, "( %d, %d, %d, '%c', '%c' )", attCount + 1, grid_info.num_rows - i, j + 1, 'A' + grid_info.num_rows - i - 1, 'A' + j); } else { sprintf(buf, "( %d, %d, %d )", attCount + 1, i + 1, j + 1); } if (db_append_string(&sql, buf) != DB_OK) G_fatal_error(_("Unable to fill attribute table")); G_debug(3, "SQL: %s", db_get_string(&sql)); if (db_execute_immediate(Driver, &sql) != DB_OK) { G_fatal_error(_("Unable to insert new record: %s"), db_get_string(&sql)); } attCount++; } } } db_commit_transaction(Driver); db_close_database_shutdown_driver(Driver); Vect_build(&Map); Vect_close(&Map); exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { int field, type, vertex_type; double dmax; struct Option *in_opt, *out_opt, *type_opt, *dmax_opt, *lfield_opt; struct Flag *inter_flag, *vertex_flag, *table_flag, *node_flag; struct GModule *module; char *mapset; struct Map_info In, Out; struct line_cats *LCats; struct line_pnts *LPoints; char buf[2000]; G_gisinit(argv[0]); module = G_define_module(); module->keywords = _("vector, geometry"); module->description = _("Create points along input lines in new vector with 2 layers."); in_opt = G_define_standard_option(G_OPT_V_INPUT); in_opt->description = _("Input vector map containing lines"); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); out_opt->description = _("Output vector map where points will be written"); type_opt = G_define_standard_option(G_OPT_V_TYPE); type_opt->answer = "point,line,boundary,centroid"; lfield_opt = G_define_standard_option(G_OPT_V_FIELD); lfield_opt->key = "llayer"; lfield_opt->answer = "1"; lfield_opt->description = "Line layer"; node_flag = G_define_flag(); node_flag->key = 'n'; node_flag->description = _("Write line nodes"); vertex_flag = G_define_flag(); vertex_flag->key = 'v'; vertex_flag->description = _("Write line vertices"); inter_flag = G_define_flag(); inter_flag->key = 'i'; inter_flag->description = _("Interpolate points between line vertices"); dmax_opt = G_define_option(); dmax_opt->key = "dmax"; dmax_opt->type = TYPE_DOUBLE; dmax_opt->required = NO; dmax_opt->answer = "100"; dmax_opt->description = _("Maximum distance between points in map units"); 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); LCats = Vect_new_cats_struct(); PCats = Vect_new_cats_struct(); LPoints = Vect_new_line_struct(); PPoints = Vect_new_line_struct(); db_init_string(&stmt); field = atoi(lfield_opt->answer); type = Vect_option_to_types(type_opt); dmax = atof(dmax_opt->answer); if (node_flag->answer && vertex_flag->answer) G_fatal_error(_("Use either -n or -v flag, not both")); if (node_flag->answer) vertex_type = GV_NODE; else if (vertex_flag->answer) vertex_type = GV_VERTEX; else vertex_type = 0; Vect_check_input_output_name(in_opt->answer, out_opt->answer, GV_FATAL_EXIT); /* Open input lines */ mapset = G_find_vector2(in_opt->answer, NULL); if (mapset == NULL) G_fatal_error(_("Vector map <%s> not found"), in_opt->answer); Vect_set_open_level(2); Vect_open_old(&In, in_opt->answer, mapset); /* Open output segments */ Vect_open_new(&Out, out_opt->answer, Vect_is_3d(&In)); Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); /* Table */ if (!table_flag->answer) { struct field_info *Fin; /* copy input table */ Fin = Vect_get_field(&In, field); if (Fin) { /* table defined */ int ret; Fi = Vect_default_field_info(&Out, 1, NULL, GV_MTABLE); Vect_map_add_dblink(&Out, 1, NULL, Fi->table, Fin->key, Fi->database, Fi->driver); ret = db_copy_table(Fin->driver, Fin->database, Fin->table, Fi->driver, Vect_subst_var(Fi->database, &Out), Fi->table); if (ret == DB_FAILED) { G_fatal_error(_("Unable to copy table <%s>"), Fin->table); } } Fi = Vect_default_field_info(&Out, 2, NULL, GV_MTABLE); Vect_map_add_dblink(&Out, 2, NULL, Fi->table, "cat", Fi->database, Fi->driver); /* Open driver */ 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); sprintf(buf, "create table %s ( cat int, lcat int, along double precision )", Fi->table); db_append_string(&stmt, buf); if (db_execute_immediate(driver, &stmt) != DB_OK) { db_close_database_shutdown_driver(driver); G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&stmt)); } if (db_create_index2(driver, Fi->table, "cat") != DB_OK) G_warning(_("Unable to create index for table <%s>, key <%s>"), Fi->table, "cat"); if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Unable to grant privileges on table <%s>"), Fi->table); db_begin_transaction(driver); } point_cat = 1; if (type & (GV_POINTS | GV_LINES)) { int line, nlines; nlines = Vect_get_num_lines(&In); for (line = 1; line <= nlines; line++) { int ltype, cat; G_debug(3, "line = %d", line); ltype = Vect_read_line(&In, LPoints, LCats, line); if (!(ltype & type)) continue; Vect_cat_get(LCats, field, &cat); if (LPoints->n_points <= 1) { write_point(&Out, LPoints->x[0], LPoints->y[0], LPoints->z[0], cat, 0.0, table_flag->answer); } else { /* lines */ write_line(&Out, LPoints, cat, vertex_type, inter_flag->answer, dmax, table_flag->answer); } G_percent(line, nlines, 2); } } if (type == GV_AREA) { int area, nareas, centroid, cat; nareas = Vect_get_num_areas(&In); for (area = 1; area <= nareas; area++) { int i, isle, nisles; centroid = Vect_get_area_centroid(&In, area); cat = -1; if (centroid > 0) { Vect_read_line(&In, NULL, LCats, centroid); Vect_cat_get(LCats, field, &cat); } Vect_get_area_points(&In, area, LPoints); write_line(&Out, LPoints, cat, vertex_type, inter_flag->answer, dmax, table_flag->answer); nisles = Vect_get_area_num_isles(&In, area); for (i = 0; i < nisles; i++) { isle = Vect_get_area_isle(&In, area, i); Vect_get_isle_points(&In, isle, LPoints); write_line(&Out, LPoints, cat, vertex_type, inter_flag->answer, dmax, table_flag->answer); } G_percent(area, nareas, 2); } } if (!table_flag->answer) { db_commit_transaction(driver); db_close_database_shutdown_driver(driver); } Vect_build(&Out); /* Free, close ... */ Vect_close(&In); Vect_close(&Out); G_done_msg(_("%d points written to output vector map"), point_cat - 1); exit(EXIT_SUCCESS); }
int main(int argc, char *argv[]) { struct Map_info In, Out; static struct line_pnts *Points, *PPoints; struct line_cats *Cats, *TCats; struct ilist *slist; struct GModule *module; /* GRASS module for parsing arguments */ struct Option *map_in, *map_out; struct Option *catf_opt, *fieldf_opt, *wheref_opt; struct Option *catt_opt, *fieldt_opt, *wheret_opt, *typet_opt; struct Option *afield_opt, *nfield_opt, *abcol, *afcol, *ncol, *atype_opt; struct Flag *geo_f, *segments_f; int with_z, geo, segments; int atype, ttype; struct varray *varrayf, *varrayt; int flayer, tlayer; int afield, nfield; dglGraph_s *graph; struct ilist *nodest; int i, j, nnodes, nlines; int *dst, *nodes_to_features; int from_nr; /* 'from' features not reachable */ dglInt32_t **nxt; struct line_cats **on_path; char *segdir; char buf[2000]; /* Attribute table */ dbString sql; dbDriver *driver; struct field_info *Fi; /* initialize GIS environment */ G_gisinit(argv[0]); /* reads grass env, stores program name to G_program_name() */ /* initialize module */ module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("network")); G_add_keyword(_("shortest path")); module->label = _("Computes shortest distance via the network between " "the given sets of features."); module->description = _("Finds the shortest paths from each 'from' point to the nearest 'to' feature " "and various information about this relation are uploaded to the attribute table."); /* Define the different options as defined in gis.h */ map_in = G_define_standard_option(G_OPT_V_INPUT); map_out = G_define_standard_option(G_OPT_V_OUTPUT); afield_opt = G_define_standard_option(G_OPT_V_FIELD); afield_opt->key = "arc_layer"; afield_opt->answer = "1"; afield_opt->label = _("Arc layer"); afield_opt->guisection = _("Cost"); atype_opt = G_define_standard_option(G_OPT_V_TYPE); atype_opt->key = "arc_type"; atype_opt->options = "line,boundary"; atype_opt->answer = "line,boundary"; atype_opt->label = _("Arc type"); atype_opt->guisection = _("Cost"); nfield_opt = G_define_standard_option(G_OPT_V_FIELD); nfield_opt->key = "node_layer"; nfield_opt->answer = "2"; nfield_opt->label = _("Node layer"); nfield_opt->guisection = _("Cost"); fieldf_opt = G_define_standard_option(G_OPT_V_FIELD); fieldf_opt->key = "from_layer"; fieldf_opt->label = _("From layer number or name"); fieldf_opt->guisection = _("From"); catf_opt = G_define_standard_option(G_OPT_V_CATS); catf_opt->key = "from_cats"; catf_opt->label = _("From category values"); catf_opt->guisection = _("From"); wheref_opt = G_define_standard_option(G_OPT_DB_WHERE); wheref_opt->key = "from_where"; wheref_opt->label = _("From WHERE conditions of SQL statement without 'where' keyword"); wheref_opt->guisection = _("From"); fieldt_opt = G_define_standard_option(G_OPT_V_FIELD); fieldt_opt->key = "to_layer"; fieldt_opt->description = _("To layer number or name"); fieldt_opt->guisection = _("To"); typet_opt = G_define_standard_option(G_OPT_V_TYPE); typet_opt->key = "to_type"; typet_opt->options = "point,line,boundary"; typet_opt->answer = "point"; typet_opt->description = _("To feature type"); typet_opt->guisection = _("To"); catt_opt = G_define_standard_option(G_OPT_V_CATS); catt_opt->key = "to_cats"; catt_opt->label = _("To category values"); catt_opt->guisection = _("To"); wheret_opt = G_define_standard_option(G_OPT_DB_WHERE); wheret_opt->key = "to_where"; wheret_opt->label = _("To WHERE conditions of SQL statement without 'where' keyword"); wheret_opt->guisection = _("To"); afcol = G_define_standard_option(G_OPT_DB_COLUMN); afcol->key = "arc_column"; afcol->required = NO; afcol->description = _("Arc forward/both direction(s) cost column (number)"); afcol->guisection = _("Cost"); abcol = G_define_standard_option(G_OPT_DB_COLUMN); abcol->key = "arc_backward_column"; abcol->required = NO; abcol->description = _("Arc backward direction cost column (number)"); abcol->guisection = _("Cost"); ncol = G_define_standard_option(G_OPT_DB_COLUMN); ncol->key = "node_column"; ncol->required = NO; ncol->description = _("Node cost column (number)"); ncol->guisection = _("Cost"); geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = _("Use geodesic calculation for longitude-latitude locations"); segments_f = G_define_flag(); #if 0 /* use this to sync with v.net.path */ segments_f->key = 's'; segments_f->description = _("Write output as original input segments, " "not each path as one line."); #else segments_f->key = 'l'; segments_f->description = _("Write each output path as one line, " "not as original input segments."); #endif /* options and flags parser */ if (G_parser(argc, argv)) exit(EXIT_FAILURE); atype = Vect_option_to_types(atype_opt); ttype = Vect_option_to_types(typet_opt); Points = Vect_new_line_struct(); PPoints = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); TCats = Vect_new_cats_struct(); slist = G_new_ilist(); Vect_check_input_output_name(map_in->answer, map_out->answer, G_FATAL_EXIT); Vect_set_open_level(2); if (1 > Vect_open_old(&In, map_in->answer, "")) G_fatal_error(_("Unable to open vector map <%s>"), map_in->answer); with_z = Vect_is_3d(&In); if (0 > Vect_open_new(&Out, map_out->answer, with_z)) { Vect_close(&In); G_fatal_error(_("Unable to create vector map <%s>"), map_out->answer); } if (geo_f->answer) { geo = 1; if (G_projection() != PROJECTION_LL) G_warning(_("The current projection is not longitude-latitude")); } else geo = 0; #if 0 /* use this to sync with v.net.path */ segments = segments_f->answer; #else segments = !segments_f->answer; #endif nnodes = Vect_get_num_nodes(&In); nlines = Vect_get_num_lines(&In); dst = (int *)G_calloc(nnodes + 1, sizeof(int)); nxt = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *)); nodes_to_features = (int *)G_calloc(nnodes + 1, sizeof(int)); on_path = (struct line_cats **)G_calloc(nlines + 1, sizeof(struct line_cats *)); segdir = (char *)G_calloc(nlines + 1, sizeof(char)); if (!dst || !nxt || !nodes_to_features || !on_path || !segdir) G_fatal_error(_("Out of memory")); for (i = 1; i <= nlines; i++) { on_path[i] = Vect_new_cats_struct(); segdir[i] = 0; } /*initialise varrays and nodes list appropriatelly */ afield = Vect_get_field_number(&In, afield_opt->answer); nfield = Vect_get_field_number(&In, nfield_opt->answer); flayer = atoi(fieldf_opt->answer); tlayer = atoi(fieldt_opt->answer); if (NetA_initialise_varray(&In, flayer, GV_POINT, wheref_opt->answer, catf_opt->answer, &varrayf) <= 0) { G_fatal_error(_("No 'from' features selected. " "Please check options '%s', '%s', '%s'."), fieldf_opt->key, wheref_opt->key, catf_opt->key); } if (NetA_initialise_varray(&In, tlayer, ttype, wheret_opt->answer, catt_opt->answer, &varrayt) <= 0) { G_fatal_error(_("No 'to' features selected. " "Please check options '%s', '%s', '%s'."), fieldt_opt->key, wheret_opt->key, catt_opt->key); } nodest = Vect_new_list(); NetA_varray_to_nodes(&In, varrayt, nodest, nodes_to_features); if (nodest->n_values == 0) G_fatal_error(_("No 'to' features")); if (0 != Vect_net_build_graph(&In, atype, afield, nfield, afcol->answer, abcol->answer, ncol->answer, geo, 2)) G_fatal_error(_("Unable to build graph for vector map <%s>"), Vect_get_full_name(&In)); graph = Vect_net_get_graph(&In); G_message(_("Distances to 'to' features ...")); NetA_distance_to_points(graph, nodest, dst, nxt); /* Create table */ Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE); Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database, Fi->driver); db_init_string(&sql); 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); sprintf(buf, "create table %s ( cat integer, tcat integer, dist double precision)", Fi->table); db_set_string(&sql, buf); G_debug(2, "%s", db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&sql)); } if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK) G_warning(_("Cannot create index")); if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Cannot grant privileges on table <%s>"), Fi->table); db_begin_transaction(driver); Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); G_message(_("Tracing paths from 'from' features ...")); from_nr = 0; for (i = 1; i <= nlines; i++) { if (varrayf->c[i]) { int type = Vect_read_line(&In, Points, Cats, i); int node, tcat, cat; double cost; dglInt32_t *vertex, vertex_id; if (!Vect_cat_get(Cats, flayer, &cat)) continue; if (type & GV_POINTS) { node = Vect_find_node(&In, Points->x[0], Points->y[0], Points->z[0], 0, 0); } else { Vect_get_line_nodes(&In, i, &node, NULL); } if (node < 1) continue; if (dst[node] < 0) { /* unreachable */ from_nr++; continue; } cost = dst[node] / (double)In.dgraph.cost_multip; vertex = dglGetNode(graph, node); vertex_id = node; slist->n_values = 0; while (nxt[vertex_id] != NULL) { int edge_id; edge_id = (int) dglEdgeGet_Id(graph, nxt[vertex_id]); if (segments) { Vect_cat_set(on_path[abs(edge_id)], 1, cat); if (edge_id < 0) { segdir[abs(edge_id)] = 1; } } else G_ilist_add(slist, edge_id); vertex = dglEdgeGet_Tail(graph, nxt[vertex_id]); vertex_id = dglNodeGet_Id(graph, vertex); } G_debug(3, "read line %d, vertex id %d", nodes_to_features[vertex_id], (int)vertex_id); Vect_read_line(&In, NULL, TCats, nodes_to_features[vertex_id]); if (!Vect_cat_get(TCats, tlayer, &tcat)) continue; Vect_write_line(&Out, type, Points, Cats); sprintf(buf, "insert into %s values (%d, %d, %f)", Fi->table, cat, tcat, cost); db_set_string(&sql, buf); G_debug(3, "%s", db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { G_fatal_error(_("Cannot insert new record: %s"), db_get_string(&sql)); }; if (!segments) { Vect_reset_line(PPoints); for (j = 0; j < slist->n_values; j++) { Vect_read_line(&In, Points, NULL, abs(slist->value[j])); if (slist->value[j] > 0) Vect_append_points(PPoints, Points, GV_FORWARD); else Vect_append_points(PPoints, Points, GV_BACKWARD); PPoints->n_points--; } PPoints->n_points++; Vect_reset_cats(Cats); Vect_cat_set(Cats, 1, cat); Vect_write_line(&Out, GV_LINE, PPoints, Cats); } } } if (segments) { for (i = 1; i <= nlines; i++) { if (on_path[i]->n_cats > 0) { int type; if (segdir[i]) { type = Vect_read_line(&In, PPoints, NULL, i); Vect_reset_line(Points); Vect_append_points(Points, PPoints, GV_BACKWARD); } else type = Vect_read_line(&In, Points, NULL, i); Vect_write_line(&Out, type, Points, on_path[i]); } } } db_commit_transaction(driver); db_close_database_shutdown_driver(driver); Vect_build(&Out); Vect_close(&In); Vect_close(&Out); for (i = 1; i <= nlines; i++) Vect_destroy_cats_struct(on_path[i]); G_free(on_path); G_free(nodes_to_features); G_free(dst); G_free(nxt); G_free(segdir); if (from_nr) G_warning(n_("%d 'from' feature was not reachable", "%d 'from' features were not reachable", from_nr), from_nr); exit(EXIT_SUCCESS); }
int main(int argc, char *argv[]) { struct Map_info In, Out, cut_map; static struct line_pnts *Points; struct line_cats *Cats; struct GModule *module; /* GRASS module for parsing arguments */ struct Option *map_in, *map_out, *cut_out; struct Option *afield_opt, *nfield_opt, *abcol, *afcol, *ncol; struct Option *catsource_opt, *wheresource_opt; struct Option *catsink_opt, *wheresink_opt; int with_z; int afield, nfield, mask_type; struct varray *varray_source, *varray_sink; dglGraph_s *graph; int i, nlines, *flow, total_flow; struct ilist *source_list, *sink_list, *cut; int find_cut; char buf[2000]; /* Attribute table */ dbString sql; dbDriver *driver; struct field_info *Fi; /* initialize GIS environment */ G_gisinit(argv[0]); /* reads grass env, stores program name to G_program_name() */ /* initialize module */ module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("network")); G_add_keyword(_("flow")); module->description = _("Computes the maximum flow between two sets of nodes in the network."); /* Define the different options as defined in gis.h */ map_in = G_define_standard_option(G_OPT_V_INPUT); afield_opt = G_define_standard_option(G_OPT_V_FIELD); afield_opt->key = "arc_layer"; afield_opt->answer = "1"; afield_opt->label = _("Arc layer"); afield_opt->guisection = _("Cost"); nfield_opt = G_define_standard_option(G_OPT_V_FIELD); nfield_opt->key = "node_layer"; nfield_opt->answer = "2"; nfield_opt->label = _("Node layer"); nfield_opt->guisection = _("Cost"); map_out = G_define_standard_option(G_OPT_V_OUTPUT); cut_out = G_define_standard_option(G_OPT_V_OUTPUT); cut_out->key = "cut"; cut_out->description = _("Name for output vector map containing a minimum cut"); afcol = G_define_standard_option(G_OPT_DB_COLUMN); afcol->key = "arc_column"; afcol->required = NO; afcol->description = _("Arc forward/both direction(s) cost column (number)"); afcol->guisection = _("Cost"); abcol = G_define_standard_option(G_OPT_DB_COLUMN); abcol->key = "arc_backward_column"; abcol->required = NO; abcol->description = _("Arc backward direction cost column (number)"); abcol->guisection = _("Cost"); ncol = G_define_standard_option(G_OPT_DB_COLUMN); ncol->key = "node_column"; ncol->required = NO; ncol->description = _("Node cost column (number)"); ncol->guisection = _("Cost"); catsource_opt = G_define_standard_option(G_OPT_V_CATS); catsource_opt->key = "source_cats"; catsource_opt->label = _("Source category values"); catsource_opt->guisection = _("Source"); wheresource_opt = G_define_standard_option(G_OPT_DB_WHERE); wheresource_opt->key = "source_where"; wheresource_opt->label = _("Source WHERE conditions of SQL statement without 'where' keyword"); wheresource_opt->guisection = _("Source"); catsink_opt = G_define_standard_option(G_OPT_V_CATS); catsink_opt->key = "sink_cats"; catsink_opt->label = _("Sink category values"); catsink_opt->guisection = _("Sink"); wheresink_opt = G_define_standard_option(G_OPT_DB_WHERE); wheresink_opt->key = "sink_where"; wheresink_opt->label = _("Sink WHERE conditions of SQL statement without 'where' keyword"); wheresink_opt->guisection = _("Sink"); /* options and flags parser */ if (G_parser(argc, argv)) exit(EXIT_FAILURE); find_cut = (cut_out->answer[0]); /* TODO: make an option for this */ mask_type = GV_LINE | GV_BOUNDARY; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); Vect_check_input_output_name(map_in->answer, map_out->answer, G_FATAL_EXIT); Vect_set_open_level(2); if (1 > Vect_open_old(&In, map_in->answer, "")) G_fatal_error(_("Unable to open vector map <%s>"), map_in->answer); with_z = Vect_is_3d(&In); if (0 > Vect_open_new(&Out, map_out->answer, with_z)) { Vect_close(&In); G_fatal_error(_("Unable to create vector map <%s>"), map_out->answer); } if (find_cut && 0 > Vect_open_new(&cut_map, cut_out->answer, with_z)) { Vect_close(&In); Vect_close(&Out); G_fatal_error(_("Unable to create vector map <%s>"), cut_out->answer); } /* parse filter option and select appropriate lines */ afield = Vect_get_field_number(&In, afield_opt->answer); nfield = Vect_get_field_number(&In, nfield_opt->answer); /* Create table */ Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE); Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database, Fi->driver); db_init_string(&sql); 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); sprintf(buf, "create table %s (cat integer, flow double precision)", Fi->table); db_set_string(&sql, buf); G_debug(2, "%s", db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { db_close_database_shutdown_driver(driver); G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&sql)); } if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK) G_warning(_("Cannot create index")); if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Cannot grant privileges on table <%s>"), Fi->table); db_begin_transaction(driver); source_list = Vect_new_list(); sink_list = Vect_new_list(); if (NetA_initialise_varray (&In, nfield, GV_POINT, wheresource_opt->answer, catsource_opt->answer, &varray_source) <= 0) { G_fatal_error(_("No source features selected. " "Please check options '%s', '%s'."), catsource_opt->key, wheresource_opt->key); } if (NetA_initialise_varray (&In, nfield, GV_POINT, wheresink_opt->answer, catsink_opt->answer, &varray_sink) <= 0) { G_fatal_error(_("No sink features selected. " "Please check options '%s', '%s'."), catsink_opt->key, wheresink_opt->key); } NetA_varray_to_nodes(&In, varray_source, source_list, NULL); NetA_varray_to_nodes(&In, varray_sink, sink_list, NULL); if (source_list->n_values == 0) G_fatal_error(_("No sources")); if (sink_list->n_values == 0) G_fatal_error(_("No sinks")); Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); if (0 != Vect_net_build_graph(&In, mask_type, afield, nfield, afcol->answer, abcol->answer, ncol->answer, 0, 0)) G_fatal_error(_("Unable to build graph for vector map <%s>"), Vect_get_full_name(&In)); graph = Vect_net_get_graph(&In); nlines = Vect_get_num_lines(&In); flow = (int *)G_calloc(nlines + 1, sizeof(int)); if (!flow) G_fatal_error(_("Out of memory")); total_flow = NetA_flow(graph, source_list, sink_list, flow); G_debug(3, "Max flow: %d", total_flow); if (find_cut) { cut = Vect_new_list(); total_flow = NetA_min_cut(graph, source_list, sink_list, flow, cut); G_debug(3, "Min cut: %d", total_flow); } G_message(_("Writing the output...")); G_percent_reset(); for (i = 1; i <= nlines; i++) { G_percent(i, nlines, 1); int type = Vect_read_line(&In, Points, Cats, i); Vect_write_line(&Out, type, Points, Cats); if (type == GV_LINE) { int cat; Vect_cat_get(Cats, afield, &cat); if (cat == -1) continue; /*TODO: warning? */ sprintf(buf, "insert into %s values (%d, %f)", Fi->table, cat, flow[i] / (double)In.dgraph.cost_multip); db_set_string(&sql, buf); G_debug(3, "%s", db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { db_close_database_shutdown_driver(driver); G_fatal_error(_("Cannot insert new record: %s"), db_get_string(&sql)); }; } } if (find_cut) { for (i = 0; i < cut->n_values; i++) { int type = Vect_read_line(&In, Points, Cats, cut->value[i]); Vect_write_line(&cut_map, type, Points, Cats); } Vect_destroy_list(cut); Vect_build(&cut_map); Vect_close(&cut_map); } db_commit_transaction(driver); db_close_database_shutdown_driver(driver); G_free(flow); Vect_destroy_list(source_list); Vect_destroy_list(sink_list); Vect_build(&Out); Vect_close(&In); Vect_close(&Out); exit(EXIT_SUCCESS); }
int main(int argc, char *argv[]) { char *output, buf[DB_SQL_MAX]; double (*rng)(void) = G_drand48; double zmin, zmax; int seed; int i, j, k, n, type, usefloat; int area, nareas, field; struct boxlist *List = NULL; BOX_SIZE *size_list = NULL; int alloc_size_list = 0; struct Map_info In, Out; struct line_pnts *Points; struct line_cats *Cats; struct cat_list *cat_list; struct bound_box box; struct Cell_head window; struct GModule *module; struct { struct Option *input, *field, *cats, *where, *output, *nsites, *zmin, *zmax, *zcol, *ztype, *seed; } parm; struct { struct Flag *z, *notopo, *a; } flag; struct field_info *Fi; dbDriver *driver; dbTable *table; dbString sql; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("sampling")); G_add_keyword(_("statistics")); G_add_keyword(_("random")); module->description = _("Generates random 2D/3D vector points."); parm.output = G_define_standard_option(G_OPT_V_OUTPUT); parm.nsites = G_define_option(); parm.nsites->key = "n"; parm.nsites->type = TYPE_INTEGER; parm.nsites->required = YES; parm.nsites->description = _("Number of points to be created"); parm.input = G_define_standard_option(G_OPT_V_INPUT); parm.input->required = NO; parm.input->description = _("Restrict points to areas in input vector"); parm.input->guisection = _("Selection"); parm.field = G_define_standard_option(G_OPT_V_FIELD_ALL); parm.field->guisection = _("Selection"); parm.cats = G_define_standard_option(G_OPT_V_CATS); parm.cats->guisection = _("Selection"); parm.where = G_define_standard_option(G_OPT_DB_WHERE); parm.where->guisection = _("Selection"); parm.zmin = G_define_option(); parm.zmin->key = "zmin"; parm.zmin->type = TYPE_DOUBLE; parm.zmin->required = NO; parm.zmin->description = _("Minimum z height (needs -z flag or column name)"); parm.zmin->answer = "0.0"; parm.zmin->guisection = _("3D output"); parm.zmax = G_define_option(); parm.zmax->key = "zmax"; parm.zmax->type = TYPE_DOUBLE; parm.zmax->required = NO; parm.zmax->description = _("Maximum z height (needs -z flag or column name)"); parm.zmax->answer = "0.0"; parm.zmax->guisection = _("3D output"); parm.seed = G_define_option(); parm.seed->key = "seed"; parm.seed->type = TYPE_INTEGER; parm.seed->required = NO; parm.seed->description = _("The seed to initialize the random generator. If not set the process ID is used"); parm.zcol = G_define_standard_option(G_OPT_DB_COLUMN); parm.zcol->label = _("Name of column for z values"); parm.zcol->description = _("Writes z values to column"); parm.zcol->guisection = _("3D output"); parm.ztype = G_define_option(); parm.ztype->key = "column_type"; parm.ztype->type = TYPE_STRING; parm.ztype->required = NO; parm.ztype->multiple = NO; parm.ztype->description = _("Type of column for z values"); parm.ztype->options = "integer,double precision"; parm.ztype->answer = "double precision"; parm.ztype->guisection = _("3D output"); flag.z = G_define_flag(); flag.z->key = 'z'; flag.z->description = _("Create 3D output"); flag.z->guisection = _("3D output"); flag.a = G_define_flag(); flag.a->key = 'a'; flag.a->description = _("Generate n points for each individual area"); flag.notopo = G_define_standard_flag(G_FLG_V_TOPO); if (G_parser(argc, argv)) exit(EXIT_FAILURE); output = parm.output->answer; n = atoi(parm.nsites->answer); if(parm.seed->answer) seed = atoi(parm.seed->answer); if (n <= 0) { G_fatal_error(_("Number of points must be > 0 (%d given)"), n); } nareas = 0; cat_list = NULL; field = -1; if (parm.input->answer) { Vect_set_open_level(2); /* topology required */ if (2 > Vect_open_old2(&In, parm.input->answer, "", parm.field->answer)) G_fatal_error(_("Unable to open vector map <%s>"), parm.input->answer); if (parm.field->answer) field = Vect_get_field_number(&In, parm.field->answer); if ((parm.cats->answer || parm.where->answer) && field == -1) { G_warning(_("Invalid layer number (%d). Parameter '%s' or '%s' specified, assuming layer '1'."), field, parm.cats->key, parm.where->key); field = 1; } if (field > 0) cat_list = Vect_cats_set_constraint(&In, field, parm.where->answer, parm.cats->answer); nareas = Vect_get_num_areas(&In); if (nareas == 0) { Vect_close(&In); G_fatal_error(_("No areas in vector map <%s>"), parm.input->answer); } } else { if (flag.a->answer) G_fatal_error(_("The <-%c> flag requires an input vector with areas"), flag.a->key); } /* create new vector map */ if (-1 == Vect_open_new(&Out, output, flag.z->answer ? WITH_Z : WITHOUT_Z)) G_fatal_error(_("Unable to create vector map <%s>"), output); Vect_set_error_handler_io(NULL, &Out); /* Do we need to write random values into attribute table? */ usefloat = -1; if (parm.zcol->answer) { Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE); driver = db_start_driver_open_database(Fi->driver, Vect_subst_var(Fi->database, &Out)); if (driver == NULL) { G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Vect_subst_var(Fi->database, &Out), Fi->driver); } db_set_error_handler_driver(driver); db_begin_transaction(driver); db_init_string(&sql); sprintf(buf, "create table %s (%s integer, %s %s)", Fi->table, GV_KEY_COLUMN, parm.zcol->answer, parm.ztype->answer); db_set_string(&sql, buf); Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database, Fi->driver); /* Create table */ G_debug(3, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { G_fatal_error(_("Unable to create table: %s"), db_get_string(&sql)); } /* Create index */ if (db_create_index2(driver, Fi->table, Fi->key) != DB_OK) G_warning(_("Unable to create index")); /* Grant */ if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) { G_fatal_error(_("Unable to grant privileges on table <%s>"), Fi->table); } /* OK. Let's check what type of column user has created */ db_set_string(&sql, Fi->table); if (db_describe_table(driver, &sql, &table) != DB_OK) { G_fatal_error(_("Unable to describe table <%s>"), Fi->table); } if (db_get_table_number_of_columns(table) != 2) { G_fatal_error(_("Table should contain only two columns")); } type = db_get_column_sqltype(db_get_table_column(table, 1)); if (type == DB_SQL_TYPE_SMALLINT || type == DB_SQL_TYPE_INTEGER) usefloat = 0; if (type == DB_SQL_TYPE_REAL || type == DB_SQL_TYPE_DOUBLE_PRECISION) usefloat = 1; if (usefloat < 0) { G_fatal_error(_("You have created unsupported column type. This module supports only INTEGER" " and DOUBLE PRECISION column types.")); } } Vect_hist_command(&Out); /* Init the random seed */ if(parm.seed->answer) G_srand48(seed); else G_srand48_auto(); G_get_window(&window); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); if (nareas > 0) { int first = 1, count; struct bound_box abox, bbox; box.W = window.west; box.E = window.east; box.S = window.south; box.N = window.north; box.B = -PORT_DOUBLE_MAX; box.T = PORT_DOUBLE_MAX; count = 0; for (i = 1; i <= nareas; i++) { if (!Vect_get_area_centroid(&In, i)) continue; if (field > 0) { if (Vect_get_area_cats(&In, i, Cats)) continue; if (!Vect_cats_in_constraint(Cats, field, cat_list)) continue; } Vect_get_area_box(&In, i, &abox); if (!Vect_box_overlap(&abox, &box)) continue; if (first) { Vect_box_copy(&bbox, &abox); first = 0; } else Vect_box_extend(&bbox, &abox); count++; } if (count == 0) { Vect_close(&In); Vect_close(&Out); Vect_delete(output); G_fatal_error(_("Selected areas in input vector <%s> do not overlap with the current region"), parm.input->answer); } Vect_box_copy(&box, &bbox); /* does the vector overlap with the current region ? */ if (box.W >= window.east || box.E <= window.west || box.S >= window.north || box.N <= window.south) { Vect_close(&In); Vect_close(&Out); Vect_delete(output); G_fatal_error(_("Input vector <%s> does not overlap with the current region"), parm.input->answer); } /* try to reduce the current region */ if (window.east > box.E) window.east = box.E; if (window.west < box.W) window.west = box.W; if (window.north > box.N) window.north = box.N; if (window.south < box.S) window.south = box.S; List = Vect_new_boxlist(1); alloc_size_list = 10; size_list = G_malloc(alloc_size_list * sizeof(BOX_SIZE)); } zmin = zmax = 0; if (flag.z->answer || parm.zcol->answer) { zmax = atof(parm.zmax->answer); zmin = atof(parm.zmin->answer); } G_message(_("Generating points...")); if (flag.a->answer && nareas > 0) { struct bound_box abox, bbox; int cat = 1; /* n points for each area */ nareas = Vect_get_num_areas(&In); G_percent(0, nareas, 1); for (area = 1; area <= nareas; area++) { G_percent(area, nareas, 1); if (!Vect_get_area_centroid(&In, area)) continue; if (field > 0) { if (Vect_get_area_cats(&In, area, Cats)) continue; if (!Vect_cats_in_constraint(Cats, field, cat_list)) { continue; } } box.W = window.west; box.E = window.east; box.S = window.south; box.N = window.north; box.B = -PORT_DOUBLE_MAX; box.T = PORT_DOUBLE_MAX; Vect_get_area_box(&In, area, &abox); if (!Vect_box_overlap(&box, &abox)) continue; bbox = abox; if (bbox.W < box.W) bbox.W = box.W; if (bbox.E > box.E) bbox.E = box.E; if (bbox.S < box.S) bbox.S = box.S; if (bbox.N > box.N) bbox.N = box.N; for (i = 0; i < n; ++i) { double x, y, z; int outside = 1; int ret; Vect_reset_line(Points); Vect_reset_cats(Cats); while (outside) { x = rng() * (bbox.W - bbox.E) + bbox.E; y = rng() * (bbox.N - bbox.S) + bbox.S; z = rng() * (zmax - zmin) + zmin; ret = Vect_point_in_area(x, y, &In, area, &abox); G_debug(3, " area = %d Vect_point_in_area() = %d", area, ret); if (ret >= 1) { outside = 0; } } if (flag.z->answer) Vect_append_point(Points, x, y, z); else Vect_append_point(Points, x, y, 0.0); if (parm.zcol->answer) { sprintf(buf, "insert into %s values ( %d, ", Fi->table, i + 1); db_set_string(&sql, buf); /* Round random value if column is integer type */ if (usefloat) sprintf(buf, "%f )", z); else sprintf(buf, "%.0f )", z); db_append_string(&sql, buf); G_debug(3, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { G_fatal_error(_("Cannot insert new row: %s"), db_get_string(&sql)); } } Vect_cat_set(Cats, 1, cat++); Vect_write_line(&Out, GV_POINT, Points, Cats); } } } else { /* n points in total */ for (i = 0; i < n; ++i) { double x, y, z; G_percent(i, n, 4); Vect_reset_line(Points); Vect_reset_cats(Cats); x = rng() * (window.west - window.east) + window.east; y = rng() * (window.north - window.south) + window.south; z = rng() * (zmax - zmin) + zmin; if (nareas) { int outside = 1; do { /* select areas by box */ box.E = x; box.W = x; box.N = y; box.S = y; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_areas_by_box(&In, &box, List); G_debug(3, " %d areas selected by box", List->n_values); /* sort areas by size, the smallest is likely to be the nearest */ if (alloc_size_list < List->n_values) { alloc_size_list = List->n_values; size_list = G_realloc(size_list, alloc_size_list * sizeof(BOX_SIZE)); } k = 0; for (j = 0; j < List->n_values; j++) { area = List->id[j]; if (!Vect_get_area_centroid(&In, area)) continue; if (field > 0) { if (Vect_get_area_cats(&In, area, Cats)) continue; if (!Vect_cats_in_constraint(Cats, field, cat_list)) { continue; } } List->id[k] = List->id[j]; List->box[k] = List->box[j]; size_list[k].i = List->id[k]; box = List->box[k]; size_list[k].box = List->box[k]; size_list[k].size = (box.N - box.S) * (box.E - box.W); k++; } List->n_values = k; if (List->n_values == 2) { /* simple swap */ if (size_list[1].size < size_list[0].size) { size_list[0].i = List->id[1]; size_list[1].i = List->id[0]; size_list[0].box = List->box[1]; size_list[1].box = List->box[0]; } } else if (List->n_values > 2) qsort(size_list, List->n_values, sizeof(BOX_SIZE), sort_by_size); for (j = 0; j < List->n_values; j++) { int ret; area = size_list[j].i; ret = Vect_point_in_area(x, y, &In, area, &size_list[j].box); G_debug(3, " area = %d Vect_point_in_area() = %d", area, ret); if (ret >= 1) { outside = 0; break; } } if (outside) { x = rng() * (window.west - window.east) + window.east; y = rng() * (window.north - window.south) + window.south; z = rng() * (zmax - zmin) + zmin; } } while (outside); } if (flag.z->answer) Vect_append_point(Points, x, y, z); else Vect_append_point(Points, x, y, 0.0); if (parm.zcol->answer) { sprintf(buf, "insert into %s values ( %d, ", Fi->table, i + 1); db_set_string(&sql, buf); /* Round random value if column is integer type */ if (usefloat) sprintf(buf, "%f )", z); else sprintf(buf, "%.0f )", z); db_append_string(&sql, buf); G_debug(3, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { G_fatal_error(_("Cannot insert new row: %s"), db_get_string(&sql)); } } Vect_cat_set(Cats, 1, i + 1); Vect_write_line(&Out, GV_POINT, Points, Cats); } G_percent(1, 1, 1); } if (parm.zcol->answer) { db_commit_transaction(driver); db_close_database_shutdown_driver(driver); } if (!flag.notopo->answer) { Vect_build(&Out); } Vect_close(&Out); exit(EXIT_SUCCESS); }
int main(int argc, char *argv[]) { int i, j, k; int print_as_matrix; /* only for all */ int all; /* calculate from each to each within the threshold */ struct GModule *module; struct Option *from_opt, *to_opt, *from_type_opt, *to_type_opt, *from_field_opt, *to_field_opt; struct Option *out_opt, *max_opt, *min_opt, *table_opt; struct Option *upload_opt, *column_opt, *to_column_opt; struct Flag *print_flag, *all_flag; struct Map_info From, To, Out, *Outp; int from_type, to_type, from_field, to_field; double max, min; double *max_step; int n_max_steps, curr_step; struct line_pnts *FPoints, *TPoints; struct line_cats *FCats, *TCats; NEAR *Near, *near; int anear; /* allocated space, used only for all */ UPLOAD *Upload; /* zero terminated */ int ftype, fcat, tcat, count; int nfrom, nto, nfcats, fline, tline, tseg, tarea, area, isle, nisles; double tx, ty, tz, dist, talong, tmp_tx, tmp_ty, tmp_tz, tmp_dist, tmp_talong; struct field_info *Fi, *toFi; dbString stmt, dbstr; dbDriver *driver, *to_driver; int *catexist, ncatexist, *cex; char buf1[2000], buf2[2000]; int update_ok, update_err, update_exist, update_notexist, update_dupl, update_notfound; struct boxlist *List; struct bound_box box; dbCatValArray cvarr; dbColumn *column; all = 0; print_as_matrix = 0; column = NULL; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("database")); G_add_keyword(_("attribute table")); module->description = _("Finds the nearest element in vector map 'to' for elements in vector map 'from'."); from_opt = G_define_standard_option(G_OPT_V_INPUT); from_opt->key = "from"; from_opt->description = _("Name of existing vector map (from)"); from_opt->guisection = _("From"); from_field_opt = G_define_standard_option(G_OPT_V_FIELD); from_field_opt->key = "from_layer"; from_field_opt->label = _("Layer number or name (from)"); from_field_opt->guisection = _("From"); from_type_opt = G_define_standard_option(G_OPT_V_TYPE); from_type_opt->key = "from_type"; from_type_opt->options = "point,centroid"; from_type_opt->answer = "point"; from_type_opt->label = _("Feature type (from)"); from_type_opt->guisection = _("From"); to_opt = G_define_standard_option(G_OPT_V_INPUT); to_opt->key = "to"; to_opt->description = _("Name of existing vector map (to)"); to_opt->guisection = _("To"); to_field_opt = G_define_standard_option(G_OPT_V_FIELD); to_field_opt->key = "to_layer"; to_field_opt->label = _("Layer number or name (to)"); to_field_opt->guisection = _("To"); to_type_opt = G_define_standard_option(G_OPT_V_TYPE); to_type_opt->key = "to_type"; to_type_opt->options = "point,line,boundary,centroid,area"; to_type_opt->answer = "point,line,area"; to_type_opt->label = _("Feature type (to)"); to_type_opt->guisection = _("To"); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); out_opt->key = "output"; out_opt->required = NO; out_opt->description = _("Name for output vector map containing lines " "connecting nearest elements"); max_opt = G_define_option(); max_opt->key = "dmax"; max_opt->type = TYPE_DOUBLE; max_opt->required = NO; max_opt->answer = "-1"; max_opt->description = _("Maximum distance or -1 for no limit"); min_opt = G_define_option(); min_opt->key = "dmin"; min_opt->type = TYPE_DOUBLE; min_opt->required = NO; min_opt->answer = "-1"; min_opt->description = _("Minimum distance or -1 for no limit"); upload_opt = G_define_option(); upload_opt->key = "upload"; upload_opt->type = TYPE_STRING; upload_opt->required = YES; upload_opt->multiple = YES; upload_opt->options = "cat,dist,to_x,to_y,to_along,to_angle,to_attr"; upload_opt->description = _("Values describing the relation between two nearest features"); upload_opt->descriptions = _("cat;category of the nearest feature;" "dist;minimum distance to nearest feature;" "to_x;x coordinate of the nearest point on 'to' feature;" "to_y;y coordinate of the nearest point on 'to' feature;" "to_along;distance between points/centroids in 'from' map and the linear feature's " "start point in 'to' map, along this linear feature;" "to_angle;angle between the linear feature in 'to' map and the positive x axis, at " "the location of point/centroid in 'from' map, counterclockwise, in radians, which " "is between -PI and PI inclusive;" "to_attr;attribute of nearest feature given by to_column option"); /* "from_x - x coordinate of the nearest point on 'from' feature;" */ /* "from_y - y coordinate of the nearest point on 'from' feature;" */ /* "from_along - distance to the nearest point on 'from' feature along linear feature;" */ column_opt = G_define_standard_option(G_OPT_DB_COLUMN); column_opt->required = YES; column_opt->multiple = YES; column_opt->description = _("Column name(s) where values specified by 'upload' option will be uploaded"); column_opt->guisection = _("From_map"); to_column_opt = G_define_standard_option(G_OPT_DB_COLUMN); to_column_opt->key = "to_column"; to_column_opt->description = _("Column name of nearest feature (used with upload=to_attr)"); to_column_opt->guisection = _("To"); table_opt = G_define_standard_option(G_OPT_DB_TABLE); table_opt->gisprompt = "new_dbtable,dbtable,dbtable"; table_opt->description = _("Name of table created for output when the distance to all flag is used"); print_flag = G_define_flag(); print_flag->key = 'p'; print_flag->label = _("Print output to stdout, don't update attribute table"); print_flag->description = _("First column is always category of 'from' feature called from_cat"); all_flag = G_define_flag(); all_flag->key = 'a'; all_flag->label = _("Calculate distances to all features within the threshold"); all_flag->description = _("The output is written to stdout but may be uploaded " "to a new table created by this module. " "From categories are may be multiple."); /* huh? */ /* GUI dependency */ from_opt->guidependency = G_store(from_field_opt->key); sprintf(buf1, "%s,%s", to_field_opt->key, to_column_opt->key); to_opt->guidependency = G_store(buf1); to_field_opt->guidependency = G_store(to_column_opt->key); if (G_parser(argc, argv)) exit(EXIT_FAILURE); from_type = Vect_option_to_types(from_type_opt); to_type = Vect_option_to_types(to_type_opt); from_field = atoi(from_field_opt->answer); max = atof(max_opt->answer); min = atof(min_opt->answer); if (all_flag->answer) all = 1; /* Read upload and column options */ /* count */ i = 0; while (upload_opt->answers[i]) i++; if (strcmp(from_opt->answer, to_opt->answer) == 0 && all && !table_opt->answer && i == 1) print_as_matrix = 1; /* alloc */ Upload = (UPLOAD *) G_calloc(i + 1, sizeof(UPLOAD)); /* read upload */ i = 0; while (upload_opt->answers[i]) { if (strcmp(upload_opt->answers[i], "cat") == 0) Upload[i].upload = CAT; else if (strcmp(upload_opt->answers[i], "from_x") == 0) Upload[i].upload = FROM_X; else if (strcmp(upload_opt->answers[i], "from_y") == 0) Upload[i].upload = FROM_Y; else if (strcmp(upload_opt->answers[i], "to_x") == 0) Upload[i].upload = TO_X; else if (strcmp(upload_opt->answers[i], "to_y") == 0) Upload[i].upload = TO_Y; else if (strcmp(upload_opt->answers[i], "from_along") == 0) Upload[i].upload = FROM_ALONG; else if (strcmp(upload_opt->answers[i], "to_along") == 0) Upload[i].upload = TO_ALONG; else if (strcmp(upload_opt->answers[i], "dist") == 0) Upload[i].upload = DIST; else if (strcmp(upload_opt->answers[i], "to_angle") == 0) Upload[i].upload = TO_ANGLE; else if (strcmp(upload_opt->answers[i], "to_attr") == 0) { if (!(to_column_opt->answer)) { G_fatal_error(_("to_column option missing")); } Upload[i].upload = TO_ATTR; } i++; } Upload[i].upload = END; /* read columns */ i = 0; while (column_opt->answers[i]) { if (Upload[i].upload == END) { G_warning(_("Too many column names")); break; } Upload[i].column = G_store(column_opt->answers[i]); i++; } if (Upload[i].upload != END) G_fatal_error(_("Not enough column names")); /* Open 'from' vector */ Vect_set_open_level(2); Vect_open_old(&From, from_opt->answer, G_mapset()); /* Open 'to' vector */ Vect_set_open_level(2); Vect_open_old2(&To, to_opt->answer, "", to_field_opt->answer); to_field = Vect_get_field_number(&To, to_field_opt->answer); /* Open output vector */ if (out_opt->answer) { Vect_open_new(&Out, out_opt->answer, WITHOUT_Z); Vect_hist_command(&Out); Outp = &Out; } else { Outp = NULL; } /* TODO: add maxdist = -1 to Vect_select_ !!! */ /* Calc maxdist */ n_max_steps = 1; if (max != 0) { struct bound_box fbox, tbox; double dx, dy, dz, tmp_max; int n_features = 0; Vect_get_map_box(&From, &fbox); Vect_get_map_box(&To, &tbox); Vect_box_extend(&fbox, &tbox); dx = fbox.E - fbox.W; dy = fbox.N - fbox.S; if (Vect_is_3d(&From)) dz = fbox.T - fbox.B; else dz = 0.0; tmp_max = sqrt(dx * dx + dy * dy + dz * dz); if (max < 0) max = tmp_max; /* how to determine a reasonable number of steps to increase the search box? */ /* with max > 0 but max <<< tmp_max, 2 steps are sufficient, first 0 then max * a reasonable number of steps also depends on the number of features in To * e.g. only one area in To, no need to step */ nto = Vect_get_num_lines(&To); for (tline = 1; tline <= nto; tline++) { /* TODO: Vect_get_line_type() */ n_features += ((to_type & To.plus.Line[tline]->type) != 0); } if (to_type & GV_AREA) { if (Vect_get_num_areas(&To) > n_features) n_features = Vect_get_num_areas(&To); } if (n_features == 0) G_fatal_error(_("No features of selected type in To vector <%s>"), to_opt->answer); n_max_steps = sqrt(n_features) * max / tmp_max; /* max 9 steps from testing */ if (n_max_steps > 9) n_max_steps = 9; if (n_max_steps < 2) n_max_steps = 2; if (n_max_steps > n_features) n_max_steps = n_features; G_debug(2, "max = %f", max); G_debug(2, "maximum reasonable search distance = %f", tmp_max); G_debug(2, "n_features = %d", n_features); G_debug(2, "n_max_steps = %d", n_max_steps); } if (min > max) G_fatal_error("dmin can not be larger than dmax"); if (n_max_steps > 1) { /* set up steps to increase search box */ max_step = G_malloc(n_max_steps * sizeof(double)); /* first step always 0 */ max_step[0] = 0; for (curr_step = 1; curr_step < n_max_steps - 1; curr_step++) { /* for 9 steps, this would be max / [128, 64, 32, 16, 8, 4, 2] */ max_step[curr_step] = max / (2 << (n_max_steps - 1 - curr_step)); } /* last step always max */ max_step[n_max_steps - 1] = max; } else { max_step = G_malloc(sizeof(double)); max_step[0] = max; } /* Open database driver */ db_init_string(&stmt); db_init_string(&dbstr); driver = NULL; if (!print_flag->answer) { if (!all) { Fi = Vect_get_field(&From, from_field); if (Fi == NULL) G_fatal_error(_("Database connection not defined for layer %d"), from_field); 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); /* check if column exists */ i = 0; while (column_opt->answers[i]) { db_get_column(driver, Fi->table, column_opt->answers[i], &column); if (column) { db_free_column(column); column = NULL; } else { G_fatal_error(_("Column <%s> not found in table <%s>"), column_opt->answers[i], Fi->table); } i++; } } else { driver = db_start_driver_open_database(NULL, NULL); if (driver == NULL) G_fatal_error(_("Unable to open default database")); } } to_driver = NULL; if (to_column_opt->answer) { toFi = Vect_get_field(&To, to_field); if (toFi == NULL) G_fatal_error(_("Database connection not defined for layer %d"), to_field); to_driver = db_start_driver_open_database(toFi->driver, toFi->database); if (to_driver == NULL) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), toFi->database, toFi->driver); /* check if to_column exists */ db_get_column(to_driver, toFi->table, to_column_opt->answer, &column); if (column) { db_free_column(column); column = NULL; } else { G_fatal_error(_("Column <%s> not found in table <%s>"), to_column_opt->answer, toFi->table); } /* Check column types */ if (!print_flag->answer && !all) { char *fcname = NULL; int fctype, tctype; i = 0; while (column_opt->answers[i]) { if (Upload[i].upload == TO_ATTR) { fcname = column_opt->answers[i]; break; } i++; } if (fcname) { fctype = db_column_Ctype(driver, Fi->table, fcname); tctype = db_column_Ctype(to_driver, toFi->table, to_column_opt->answer); if (((tctype == DB_C_TYPE_STRING || tctype == DB_C_TYPE_DATETIME) && (fctype == DB_C_TYPE_INT || fctype == DB_C_TYPE_DOUBLE)) || ((tctype == DB_C_TYPE_INT || tctype == DB_C_TYPE_DOUBLE) && (fctype == DB_C_TYPE_STRING || fctype == DB_C_TYPE_DATETIME)) ) { G_fatal_error(_("Incompatible column types")); } } } } FPoints = Vect_new_line_struct(); TPoints = Vect_new_line_struct(); FCats = Vect_new_cats_struct(); TCats = Vect_new_cats_struct(); List = Vect_new_boxlist(1); /* Allocate space ( may be more than needed (duplicate cats and elements without cats) ) */ nfrom = Vect_get_num_lines(&From); nto = Vect_get_num_lines(&To); if (all) { /* Attention with space for all, it can easily run out of memory */ anear = 2 * nfrom; Near = (NEAR *) G_calloc(anear, sizeof(NEAR)); } else { Near = (NEAR *) G_calloc(nfrom, sizeof(NEAR)); } /* Read all cats from 'from' */ if (!all) { nfcats = 0; for (i = 1; i <= nfrom; i++) { ftype = Vect_read_line(&From, NULL, FCats, i); /* This keeps also categories of areas for future (if area s in from_type) */ if (!(ftype & from_type) && (ftype != GV_CENTROID || !(from_type & GV_AREA))) continue; Vect_cat_get(FCats, from_field, &fcat); if (fcat < 0) continue; Near[nfcats].from_cat = fcat; nfcats++; } G_debug(1, "%d cats loaded from vector (including duplicates)", nfcats); /* Sort by cats and remove duplicates */ qsort((void *)Near, nfcats, sizeof(NEAR), cmp_near); /* remove duplicates */ for (i = 1; i < nfcats; i++) { if (Near[i].from_cat == Near[i - 1].from_cat) { for (j = i; j < nfcats - 1; j++) { Near[j].from_cat = Near[j + 1].from_cat; } nfcats--; } } G_debug(1, "%d cats loaded from vector (unique)", nfcats); } /* Go through all lines in 'from' and find nearest in 'to' for each */ /* Note: as from_type is restricted to GV_POINTS (for now) everything is simple */ count = 0; /* count of distances in 'all' mode */ /* Find nearest lines */ if (to_type & (GV_POINTS | GV_LINES)) { struct line_pnts *LLPoints; if (G_projection() == PROJECTION_LL) { LLPoints = Vect_new_line_struct(); } else { LLPoints = NULL; } G_message(_("Finding nearest feature...")); for (fline = 1; fline <= nfrom; fline++) { int tmp_tcat; double tmp_tangle, tangle; double tmp_min = (min < 0 ? 0 : min); double box_edge = 0; int done = 0; curr_step = 0; G_debug(3, "fline = %d", fline); G_percent(fline, nfrom, 2); ftype = Vect_read_line(&From, FPoints, FCats, fline); if (!(ftype & from_type)) continue; Vect_cat_get(FCats, from_field, &fcat); if (fcat < 0 && !all) continue; while (!done) { done = 1; if (!all) { /* enlarge search box until we get a hit */ /* the objective is to enlarge the search box * in the first iterations just a little bit * to keep the number of hits low */ Vect_reset_boxlist(List); while (curr_step < n_max_steps) { box_edge = max_step[curr_step]; if (box_edge < tmp_min) continue; box.E = FPoints->x[0] + box_edge; box.W = FPoints->x[0] - box_edge; box.N = FPoints->y[0] + box_edge; box.S = FPoints->y[0] - box_edge; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_lines_by_box(&To, &box, to_type, List); curr_step++; if (List->n_values > 0) break; } } else { box.E = FPoints->x[0] + max; box.W = FPoints->x[0] - max; box.N = FPoints->y[0] + max; box.S = FPoints->y[0] - max; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_lines_by_box(&To, &box, to_type, List); } G_debug(3, " %d lines in box", List->n_values); tline = 0; dist = PORT_DOUBLE_MAX; for (i = 0; i < List->n_values; i++) { tmp_tcat = -1; Vect_read_line(&To, TPoints, TCats, List->id[i]); tseg = Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0], (Vect_is_3d(&From) && Vect_is_3d(&To)) ? WITH_Z : WITHOUT_Z, &tmp_tx, &tmp_ty, &tmp_tz, &tmp_dist, NULL, &tmp_talong); Vect_point_on_line(TPoints, tmp_talong, NULL, NULL, NULL, &tmp_tangle, NULL); if (tmp_dist > max || tmp_dist < min) continue; /* not in threshold */ /* TODO: more cats of the same field */ Vect_cat_get(TCats, to_field, &tmp_tcat); if (G_projection() == PROJECTION_LL) { /* calculate distances in meters not degrees (only 2D) */ Vect_reset_line(LLPoints); Vect_append_point(LLPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0]); Vect_append_point(LLPoints, tmp_tx, tmp_ty, tmp_tz); tmp_dist = Vect_line_geodesic_length(LLPoints); Vect_reset_line(LLPoints); for (k = 0; k < tseg; k++) Vect_append_point(LLPoints, TPoints->x[k], TPoints->y[k], TPoints->z[k]); Vect_append_point(LLPoints, tmp_tx, tmp_ty, tmp_tz); tmp_talong = Vect_line_geodesic_length(LLPoints); } G_debug(4, " tmp_dist = %f tmp_tcat = %d", tmp_dist, tmp_tcat); if (all) { if (anear <= count) { anear += 10 + nfrom / 10; Near = (NEAR *) G_realloc(Near, anear * sizeof(NEAR)); } near = &(Near[count]); /* store info about relation */ near->from_cat = fcat; near->to_cat = tmp_tcat; /* -1 is OK */ near->dist = tmp_dist; near->from_x = FPoints->x[0]; near->from_y = FPoints->y[0]; near->from_z = FPoints->z[0]; near->to_x = tmp_tx; near->to_y = tmp_ty; near->to_z = tmp_tz; near->to_along = tmp_talong; /* 0 for points */ near->to_angle = tmp_tangle; near->count++; count++; } else { if (tline == 0 || (tmp_dist < dist)) { tline = List->id[i]; tcat = tmp_tcat; dist = tmp_dist; tx = tmp_tx; ty = tmp_ty; tz = tmp_tz; talong = tmp_talong; tangle = tmp_tangle; } } } G_debug(4, " dist = %f", dist); if (curr_step < n_max_steps) { /* enlarging the search box is possible */ if (tline > 0 && dist > box_edge) { /* line found but distance > search edge: * line bbox overlaps with search box, line itself is outside search box */ done = 0; } else if (tline == 0) { /* no line within max dist, but search box can still be enlarged */ done = 0; } } if (done && !all && tline > 0) { /* find near by cat */ near = (NEAR *) bsearch((void *)&fcat, Near, nfcats, sizeof(NEAR), cmp_near); G_debug(4, " near.from_cat = %d near.count = %d", near->from_cat, near->count); /* store info about relation */ if (near->count == 0 || near->dist > dist) { near->to_cat = tcat; /* -1 is OK */ near->dist = dist; near->from_x = FPoints->x[0]; near->from_y = FPoints->y[0]; near->from_z = FPoints->z[0]; near->to_x = tx; near->to_y = ty; near->to_z = tz; near->to_along = talong; /* 0 for points */ near->to_angle = tangle; } near->count++; } } /* done */ } /* next feature */ if (LLPoints) { Vect_destroy_line_struct(LLPoints); } } /* Find nearest areas */ if (to_type & GV_AREA) { G_message(_("Finding nearest areas...")); for (fline = 1; fline <= nfrom; fline++) { double tmp_min = (min < 0 ? 0 : min); double box_edge = 0; int done = 0; curr_step = 0; G_debug(3, "fline = %d", fline); G_percent(fline, nfrom, 2); ftype = Vect_read_line(&From, FPoints, FCats, fline); if (!(ftype & from_type)) continue; Vect_cat_get(FCats, from_field, &fcat); if (fcat < 0 && !all) continue; while (!done) { done = 1; if (!all) { /* enlarge search box until we get a hit */ /* the objective is to enlarge the search box * in the first iterations just a little bit * to keep the number of hits low */ Vect_reset_boxlist(List); while (curr_step < n_max_steps) { box_edge = max_step[curr_step]; if (box_edge < tmp_min) continue; box.E = FPoints->x[0] + box_edge; box.W = FPoints->x[0] - box_edge; box.N = FPoints->y[0] + box_edge; box.S = FPoints->y[0] - box_edge; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_areas_by_box(&To, &box, List); curr_step++; if (List->n_values > 0) break; } } else { box.E = FPoints->x[0] + max; box.W = FPoints->x[0] - max; box.N = FPoints->y[0] + max; box.S = FPoints->y[0] - max; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_areas_by_box(&To, &box, List); } G_debug(4, "%d areas selected by box", List->n_values); /* For each area in box check the distance */ tarea = 0; dist = PORT_DOUBLE_MAX; for (i = 0; i < List->n_values; i++) { int tmp_tcat; area = List->id[i]; G_debug(4, "%d: area %d", i, area); Vect_get_area_points(&To, area, TPoints); /* Find the distance to this area */ if (Vect_point_in_area(FPoints->x[0], FPoints->y[0], &To, area, List->box[i])) { /* in area */ tmp_dist = 0; tmp_tx = FPoints->x[0]; tmp_ty = FPoints->y[0]; } else if (Vect_point_in_poly(FPoints->x[0], FPoints->y[0], TPoints) > 0) { /* in isle */ nisles = Vect_get_area_num_isles(&To, area); for (j = 0; j < nisles; j++) { double tmp2_dist, tmp2_tx, tmp2_ty; isle = Vect_get_area_isle(&To, area, j); Vect_get_isle_points(&To, isle, TPoints); Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0], WITHOUT_Z, &tmp2_tx, &tmp2_ty, NULL, &tmp2_dist, NULL, NULL); if (j == 0 || tmp2_dist < tmp_dist) { tmp_dist = tmp2_dist; tmp_tx = tmp2_tx; tmp_ty = tmp2_ty; } } } else { /* outside area */ Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0], WITHOUT_Z, &tmp_tx, &tmp_ty, NULL, &tmp_dist, NULL, NULL); } if (tmp_dist > max || tmp_dist < min) continue; /* not in threshold */ Vect_get_area_cats(&To, area, TCats); tmp_tcat = -1; /* TODO: all cats of given field ? */ for (j = 0; j < TCats->n_cats; j++) { if (TCats->field[j] == to_field) { if (tmp_tcat >= 0) G_warning(_("More cats found in to_layer (area=%d)"), area); tmp_tcat = TCats->cat[j]; } } G_debug(4, " tmp_dist = %f tmp_tcat = %d", tmp_dist, tmp_tcat); if (all) { if (anear <= count) { anear += 10 + nfrom / 10; Near = (NEAR *) G_realloc(Near, anear * sizeof(NEAR)); } near = &(Near[count]); /* store info about relation */ near->from_cat = fcat; near->to_cat = tmp_tcat; /* -1 is OK */ near->dist = tmp_dist; near->from_x = FPoints->x[0]; near->from_y = FPoints->y[0]; near->to_x = tmp_tx; near->to_y = tmp_ty; near->to_along = 0; /* nonsense for areas */ near->to_angle = 0; /* not supported for areas */ near->count++; count++; } else if (tarea == 0 || tmp_dist < dist) { tarea = area; tcat = tmp_tcat; dist = tmp_dist; tx = tmp_tx; ty = tmp_ty; } } if (curr_step < n_max_steps) { /* enlarging the search box is possible */ if (tarea > 0 && dist > box_edge) { /* area found but distance > search edge: * area bbox overlaps with search box, area itself is outside search box */ done = 0; } else if (tarea == 0) { /* no area within max dist, but search box can still be enlarged */ done = 0; } } if (done && !all && tarea > 0) { /* find near by cat */ near = (NEAR *) bsearch((void *)&fcat, Near, nfcats, sizeof(NEAR), cmp_near); G_debug(4, "near.from_cat = %d near.count = %d dist = %f", near->from_cat, near->count, near->dist); /* store info about relation */ if (near->count == 0 || near->dist > dist) { near->to_cat = tcat; /* -1 is OK */ near->dist = dist; near->from_x = FPoints->x[0]; near->from_y = FPoints->y[0]; near->to_x = tx; near->to_y = ty; near->to_along = 0; /* nonsense for areas */ near->to_angle = 0; /* not supported for areas */ } near->count++; } } /* done */ } /* next feature */ } G_debug(3, "count = %d", count); /* Update database / print to stdout / create output map */ if (print_flag->answer) { /* print header */ fprintf(stdout, "from_cat"); i = 0; while (Upload[i].upload != END) { fprintf(stdout, "|%s", Upload[i].column); i++; } fprintf(stdout, "\n"); } else if (all && table_opt->answer) { /* create new table */ db_set_string(&stmt, "create table "); db_append_string(&stmt, table_opt->answer); db_append_string(&stmt, " (from_cat integer"); j = 0; while (Upload[j].upload != END) { db_append_string(&stmt, ", "); switch (Upload[j].upload) { case CAT: sprintf(buf2, "%s integer", Upload[j].column); break; case DIST: case FROM_X: case FROM_Y: case TO_X: case TO_Y: case FROM_ALONG: case TO_ALONG: case TO_ANGLE: sprintf(buf2, "%s double precision", Upload[j].column); } db_append_string(&stmt, buf2); j++; } db_append_string(&stmt, " )"); G_debug(3, "SQL: %s", db_get_string(&stmt)); if (db_execute_immediate(driver, &stmt) != DB_OK) G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&stmt)); if (db_grant_on_table(driver, table_opt->answer, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Unable to grant privileges on table <%s>"), table_opt->answer); } else if (!all) { /* read existing cats from table */ ncatexist = db_select_int(driver, Fi->table, Fi->key, NULL, &catexist); G_debug(1, "%d cats selected from the table", ncatexist); } update_ok = update_err = update_exist = update_notexist = update_dupl = update_notfound = 0; if (!all) { count = nfcats; } else if (print_as_matrix) { qsort((void *)Near, count, sizeof(NEAR), cmp_near_to); } if (driver) db_begin_transaction(driver); /* select 'to' attributes */ if (to_column_opt->answer) { int nrec; db_CatValArray_init(&cvarr); nrec = db_select_CatValArray(to_driver, toFi->table, toFi->key, to_column_opt->answer, NULL, &cvarr); G_debug(3, "selected values = %d", nrec); if (cvarr.ctype == DB_C_TYPE_DATETIME) { G_warning(_("DATETIME type not yet supported, no attributes will be uploaded")); } db_close_database_shutdown_driver(to_driver); } if (!(print_flag->answer || (all && !table_opt->answer))) /* no printing */ G_message("Update database..."); for (i = 0; i < count; i++) { dbCatVal *catval = 0; if (!(print_flag->answer || (all && !table_opt->answer))) /* no printing */ G_percent(i, count, 1); /* Write line connecting nearest points */ if (Outp != NULL) { Vect_reset_line(FPoints); Vect_reset_cats(FCats); Vect_append_point(FPoints, Near[i].from_x, Near[i].from_y, 0); if (Near[i].dist == 0) { Vect_write_line(Outp, GV_POINT, FPoints, FCats); } else { Vect_append_point(FPoints, Near[i].to_x, Near[i].to_y, 0); Vect_write_line(Outp, GV_LINE, FPoints, FCats); } } if (Near[i].count > 1) update_dupl++; if (Near[i].count == 0) update_notfound++; if (to_column_opt->answer && Near[i].count > 0) { db_CatValArray_get_value(&cvarr, Near[i].to_cat, &catval); } if (print_flag->answer || (all && !table_opt->answer)) { /* print only */ /* input and output is the same && calculate distances && only one upload option given -> print as a matrix */ if (print_as_matrix) { if (i == 0) { for (j = 0; j < nfrom; j++) { if (j == 0) fprintf(stdout, " "); fprintf(stdout, "|%d", Near[j].to_cat); } fprintf(stdout, "\n"); } if (i % nfrom == 0) { fprintf(stdout, "%d", Near[i].from_cat); for (j = 0; j < nfrom; j++) { print_upload(Near, Upload, i + j, &cvarr, catval); } fprintf(stdout, "\n"); } } else { fprintf(stdout, "%d", Near[i].from_cat); print_upload(Near, Upload, i, &cvarr, catval); fprintf(stdout, "\n"); } } else if (all) { /* insert new record */ sprintf(buf1, "insert into %s values ( %d ", table_opt->answer, Near[i].from_cat); db_set_string(&stmt, buf1); j = 0; while (Upload[j].upload != END) { db_append_string(&stmt, ","); switch (Upload[j].upload) { case CAT: sprintf(buf2, " %d", Near[i].to_cat); break; case DIST: sprintf(buf2, " %f", Near[i].dist); break; case FROM_X: sprintf(buf2, " %f", Near[i].from_x); break; case FROM_Y: sprintf(buf2, " %f", Near[i].from_y); break; case TO_X: sprintf(buf2, " %f", Near[i].to_x); break; case TO_Y: sprintf(buf2, " %f", Near[i].to_y); break; case FROM_ALONG: sprintf(buf2, " %f", Near[i].from_along); break; case TO_ALONG: sprintf(buf2, " %f", Near[i].to_along); break; case TO_ANGLE: sprintf(buf2, " %f", Near[i].to_angle); break; case TO_ATTR: if (catval) { switch (cvarr.ctype) { case DB_C_TYPE_INT: sprintf(buf2, " %d", catval->val.i); break; case DB_C_TYPE_DOUBLE: sprintf(buf2, " %.15e", catval->val.d); break; case DB_C_TYPE_STRING: db_set_string(&dbstr, db_get_string(catval->val.s)); db_double_quote_string(&dbstr); sprintf(buf2, " '%s'", db_get_string(&dbstr)); break; case DB_C_TYPE_DATETIME: /* TODO: formating datetime */ sprintf(buf2, " null"); break; } } else { sprintf(buf2, " null"); } break; } db_append_string(&stmt, buf2); j++; } db_append_string(&stmt, " )"); G_debug(3, "SQL: %s", db_get_string(&stmt)); if (db_execute_immediate(driver, &stmt) == DB_OK) { update_ok++; } else { update_err++; } } else { /* update table */ /* check if exists in table */ cex = (int *)bsearch((void *)&(Near[i].from_cat), catexist, ncatexist, sizeof(int), cmp_exist); if (cex == NULL) { /* cat does not exist in DB */ update_notexist++; continue; } update_exist++; sprintf(buf1, "update %s set", Fi->table); db_set_string(&stmt, buf1); j = 0; while (Upload[j].upload != END) { if (j > 0) db_append_string(&stmt, ","); sprintf(buf2, " %s =", Upload[j].column); db_append_string(&stmt, buf2); if (Near[i].count == 0) { /* no nearest found */ db_append_string(&stmt, " null"); } else { switch (Upload[j].upload) { case CAT: if (Near[i].to_cat > 0) sprintf(buf2, " %d", Near[i].to_cat); else sprintf(buf2, " null"); break; case DIST: sprintf(buf2, " %f", Near[i].dist); break; case FROM_X: sprintf(buf2, " %f", Near[i].from_x); break; case FROM_Y: sprintf(buf2, " %f", Near[i].from_y); break; case TO_X: sprintf(buf2, " %f", Near[i].to_x); break; case TO_Y: sprintf(buf2, " %f", Near[i].to_y); break; case FROM_ALONG: sprintf(buf2, " %f", Near[i].from_along); break; case TO_ALONG: sprintf(buf2, " %f", Near[i].to_along); break; case TO_ANGLE: sprintf(buf2, " %f", Near[i].to_angle); break; case TO_ATTR: if (catval) { switch (cvarr.ctype) { case DB_C_TYPE_INT: sprintf(buf2, " %d", catval->val.i); break; case DB_C_TYPE_DOUBLE: sprintf(buf2, " %.15e", catval->val.d); break; case DB_C_TYPE_STRING: db_set_string(&dbstr, db_get_string(catval->val.s)); db_double_quote_string(&dbstr); sprintf(buf2, " '%s'", db_get_string(&dbstr)); break; case DB_C_TYPE_DATETIME: /* TODO: formating datetime */ sprintf(buf2, " null"); break; } } else { sprintf(buf2, " null"); } break; } db_append_string(&stmt, buf2); } j++; } sprintf(buf2, " where %s = %d", Fi->key, Near[i].from_cat); db_append_string(&stmt, buf2); G_debug(2, "SQL: %s", db_get_string(&stmt)); if (db_execute_immediate(driver, &stmt) == DB_OK) { update_ok++; } else { update_err++; } } } G_percent(count, count, 1); if (driver) db_commit_transaction(driver); /* print stats */ if (update_dupl > 0) G_message(_("%d categories with more than 1 feature in vector map <%s>"), update_dupl, from_opt->answer); if (update_notfound > 0) G_message(_("%d categories - no nearest feature found"), update_notfound); if (!print_flag->answer) { db_close_database_shutdown_driver(driver); db_free_string(&stmt); /* print stats */ if (all && table_opt->answer) { G_message(_("%d distances calculated"), count); G_message(_("%d records inserted"), update_ok); if (update_err > 0) G_message(_("%d insert errors"), update_err); } else if (!all) { if (nfcats > 0) G_message(_("%d categories read from the map"), nfcats); if (ncatexist > 0) G_message(_("%d categories exist in the table"), ncatexist); if (update_exist > 0) G_message(_("%d categories read from the map exist in the table"), update_exist); if (update_notexist > 0) G_message(_("%d categories read from the map don't exist in the table"), update_notexist); G_message(_("%d records updated"), update_ok); if (update_err > 0) G_message(_("%d update errors"), update_err); G_free(catexist); } Vect_set_db_updated(&From); } Vect_close(&From); if (Outp != NULL) { Vect_build(Outp); Vect_close(Outp); } G_done_msg(" "); exit(EXIT_SUCCESS); }