void write_point(struct Map_info *Out, double x, double y, double z, int line_cat, double along, int table) { char buf[2000]; G_debug(3, "write_point()"); Vect_reset_line(PPoints); Vect_reset_cats(PCats); /* Write point */ Vect_append_point(PPoints, x, y, z); Vect_cat_set(PCats, 1, line_cat); Vect_cat_set(PCats, 2, point_cat); Vect_write_line(Out, GV_POINT, PPoints, PCats); /* Attributes */ if (!table) { db_zero_string(&stmt); sprintf(buf, "insert into %s values ( %d, %d, %.15g )", Fi->table, point_cat, line_cat, along); db_append_string(&stmt, buf); if (db_execute_immediate(driver, &stmt) != DB_OK) { G_warning(_("Unable to insert new record: '%s'"), db_get_string(&stmt)); } } point_cat++; }
/* Check if point is inside area with category of given field. All cats are set in * Cats with original field. * returns number of cats. */ int point_area(struct Map_info *Map, int field, double x, double y, struct line_cats *Cats) { int i, area, centr; static struct line_cats *CCats = NULL; Vect_reset_cats(Cats); area = Vect_find_area(Map, x, y); G_debug(4, " area = %d", area); if (!area) return 0; centr = Vect_get_area_centroid(Map, area); if (centr <= 0) return 0; if (!CCats) CCats = Vect_new_cats_struct(); Vect_read_line(Map, NULL, CCats, centr); for (i = 0; i < CCats->n_cats; i++) { if (CCats->field[i] == field) { Vect_cat_set(Cats, field, CCats->cat[i]); } } return Cats->n_cats; }
/* Writes a site to file open on fptr. */ int G_site_put(struct Map_info *Map, const Site * s) { static struct line_pnts *Points = NULL; static struct line_cats *Cats = NULL; if (Points == NULL) Points = Vect_new_line_struct(); if (Cats == NULL) Cats = Vect_new_cats_struct(); Vect_reset_line(Points); Vect_reset_cats(Cats); /* no 3D support so far: s->dim[0] */ Vect_append_point(Points, s->east, s->north, 0.0); G_debug(4, "cattype = %d", s->cattype); if (s->cattype == FCELL_TYPE || s->cattype == DCELL_TYPE) G_fatal_error(_("Category must be integer")); if (s->cattype == CELL_TYPE) Vect_cat_set(Cats, 1, s->ccat); Vect_write_line(Map, GV_POINT, Points, Cats); return 0; }
/*! \brief Read feature from OGR layer at given offset (level 1) This function implements random access on level 1. \param Map pointer to Map_info structure \param[out] line_p container used to store line points within \param[out] line_c container used to store line categories within \param offset given offset \return line type \return 0 dead line \return -2 no more features \return -1 out of memory */ int V1_read_line_ogr(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c, off_t offset) { long FID; int type; OGRGeometryH hGeom; G_debug(4, "V1_read_line_ogr() offset = %lu offset_num = %lu", (long) offset, (long) Map->fInfo.ogr.offset_num); if (offset >= Map->fInfo.ogr.offset_num) return -2; if (line_p != NULL) Vect_reset_line(line_p); if (line_c != NULL) Vect_reset_cats(line_c); FID = Map->fInfo.ogr.offset[offset]; G_debug(4, " FID = %ld", FID); /* coordinates */ if (line_p != NULL) { /* Read feature to cache if necessary */ if (Map->fInfo.ogr.feature_cache_id != FID) { G_debug(4, "Read feature (FID = %ld) to cache", FID); if (Map->fInfo.ogr.feature_cache) { OGR_F_Destroy(Map->fInfo.ogr.feature_cache); } Map->fInfo.ogr.feature_cache = OGR_L_GetFeature(Map->fInfo.ogr.layer, FID); if (Map->fInfo.ogr.feature_cache == NULL) { G_fatal_error(_("Unable to get feature geometry, FID %ld"), FID); } Map->fInfo.ogr.feature_cache_id = FID; } hGeom = OGR_F_GetGeometryRef(Map->fInfo.ogr.feature_cache); if (hGeom == NULL) { G_fatal_error(_("Unable to get feature geometry, FID %ld"), FID); } type = read_line(Map, hGeom, offset + 1, line_p); } else { type = get_line_type(Map, FID); } /* category */ if (line_c != NULL) { Vect_cat_set(line_c, 1, (int) FID); } return type; }
/** * \brief Create network arcs (edge) based on given point vector map (nodes) * * \param file input file defining arcs * \param Points input vector point map * \param Out output vector map * \param afield arcs layer * \param nfield nodes layer * * \return number of new arcs */ int create_arcs(FILE * file, struct Map_info *Pnts, struct Map_info *Out, int afield, int nfield) { char buff[1024]; int lcat, fcat, tcat; int node1, node2; int narcs; struct line_pnts *points, *points2; struct line_cats *cats; points = Vect_new_line_struct(); points2 = Vect_new_line_struct(); points = Vect_new_line_struct(); cats = Vect_new_cats_struct(); narcs = 0; while (G_getl2(buff, sizeof(buff) - 1, file)) { if (sscanf(buff, "%d%d%d", &lcat, &fcat, &tcat) != 3) G_fatal_error(_("Error reading file: '%s'"), buff); node1 = find_node(Pnts, afield, fcat); node2 = find_node(Pnts, afield, tcat); if (node1 < 1 || node2 < 1) { G_warning(_("Skipping arc %d"), lcat); continue; } /* geometry */ Vect_read_line(Pnts, points, cats, node1); field2n(cats, nfield); Vect_write_line(Out, GV_POINT, points, cats); Vect_read_line(Pnts, points2, cats, node2); field2n(cats, nfield); Vect_write_line(Out, GV_POINT, points2, cats); Vect_append_points(points, points2, GV_FORWARD); /* category */ Vect_reset_cats(cats); Vect_cat_set(cats, afield, lcat); Vect_write_line(Out, GV_LINE, points, cats); narcs++; } Vect_destroy_line_struct(points); Vect_destroy_cats_struct(cats); return narcs; }
/*! \brief Reads feature from OGR layer (topology level) This function implements random access on level 2. \param Map pointer to Map_info structure \param[out] line_p container used to store line points within \param[out] line_c container used to store line categories within \param line feature id \return feature type \return -2 no more features \return -1 out of memory */ int V2_read_line_ogr(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c, int line) { struct P_line *Line; G_debug(4, "V2_read_line_ogr() line = %d", line); Line = Map->plus.Line[line]; if (Line == NULL) G_fatal_error(_("Attempt to read dead feature %d"), line); if (Line->type == GV_CENTROID) { G_debug(4, "Centroid"); if (line_p != NULL) { int i, found; struct bound_box box; struct boxlist list; struct P_topo_c *topo = (struct P_topo_c *)Line->topo; /* get area bbox */ Vect_get_area_box(Map, topo->area, &box); /* search in spatial index for centroid with area bbox */ dig_init_boxlist(&list, 1); Vect_select_lines_by_box(Map, &box, Line->type, &list); found = 0; for (i = 0; i < list.n_values; i++) { if (list.id[i] == line) { found = i; break; } } Vect_reset_line(line_p); Vect_append_point(line_p, list.box[found].E, list.box[found].N, 0.0); } if (line_c != NULL) { /* cat = FID and offset = FID for centroid */ Vect_reset_cats(line_c); Vect_cat_set(line_c, 1, (int) Line->offset); } return GV_CENTROID; } return V1_read_line_ogr(Map, line_p, line_c, Line->offset); }
/*! \brief Get area categories \param Map pointer to Map_info structure \param area area id \param[out] Cats list of categories \return 0 centroid found (but may be without categories) \return 1 no centroid found */ int Vect_get_area_cats(const struct Map_info *Map, int area, struct line_cats *Cats) { int centroid; Vect_reset_cats(Cats); centroid = Vect_get_area_centroid(Map, area); if (centroid > 0) { Vect_read_line(Map, NULL, Cats, centroid); } else { return 1; /* no centroid */ } return 0; }
/*! \brief Find FIRST category of given field and area \param Map pointer to Map_info structure \param area area id \param field layer number \return first found category of given field \return -1 no centroid or no category found */ int Vect_get_area_cat(const struct Map_info *Map, int area, int field) { int i; static struct line_cats *Cats = NULL; if (!Cats) Cats = Vect_new_cats_struct(); else Vect_reset_cats(Cats); if (Vect_get_area_cats(Map, area, Cats) == 1 || Cats->n_cats == 0) { return -1; } for (i = 0; i < Cats->n_cats; i++) { if (Cats->field[i] == field) { return Cats->cat[i]; } } return -1; }
int QgsGrassEdit::writeLine( int type, struct line_pnts *Points ) { int mode = mCatModeBox->currentIndex(); int field = mFieldBox->currentText().toInt(); int cat = mCatEntry->text().toInt(); Vect_reset_cats( mCats ); if ( mode == CAT_MODE_NEXT || mode == CAT_MODE_MANUAL ) { Vect_cat_set( mCats, field, cat ); // Insert new DB record if link is defined and the record for this cat does not exist QString *key = mProvider->key( field ); if ( !key->isEmpty() ) // Database link defined { QgsAttributeMap *atts = mProvider->attributes( field, cat ); if ( atts->count() == 0 ) // Nothing selected { QString *error = mProvider->insertAttributes( field, cat ); if ( !error->isEmpty() ) { QMessageBox::warning( 0, tr( "Warning" ), *error ); } delete error; } delete atts; } } Vect_line_prune( Points ); int line = mProvider->writeLine( type, Points, mCats ); increaseMaxCat(); return line; }
int point_save(double xmm, double ymm, double zmm, double err) /* c saves point deviations c */ { int cat; Vect_reset_line(Pnts); Vect_reset_cats(Cats); Vect_append_point(Pnts, xmm, ymm, zmm); cat = count; Vect_cat_set(Cats, 1, cat); Vect_write_line(&Map, GV_POINT, Pnts, Cats); db_zero_string(&sql); sprintf(buf, "insert into %s values ( %d ", f->table, cat); db_append_string(&sql, buf); sprintf(buf, ", %f", err); db_append_string(&sql, buf); db_append_string(&sql, ")"); G_debug(3, "%s", 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)); } count++; return 1; }
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 area_area(struct Map_info *In, int *field, struct Map_info *Tmp, struct Map_info *Out, struct field_info *Fi, dbDriver * driver, int operator, int *ofield, ATTRIBUTES * attr, struct ilist *BList, double snap) { int ret, input, line, nlines, area, nareas; int in_area, in_centr, out_cat; struct line_pnts *Points; struct line_cats *Cats; CENTR *Centr; char buf[1000]; dbString stmt; int nmodif; int verbose; verbose = G_verbose(); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); /* optional snap */ if (snap > 0) { int i, j, snapped_lines = 0; struct bound_box box; struct boxlist *boxlist = Vect_new_boxlist(0); struct ilist *reflist = Vect_new_list(); G_message(_("Snapping boundaries with %g ..."), snap); /* snap boundaries in B to boundaries in A, * not modifying boundaries in A */ if (BList->n_values > 1) qsort(BList->value, BList->n_values, sizeof(int), cmp_int); snapped_lines = 0; nlines = BList->n_values; for (i = 0; i < nlines; i++) { line = BList->value[i]; Vect_read_line(Tmp, Points, Cats, line); /* select lines by box */ Vect_get_line_box(Tmp, line, &box); box.E += snap; box.W -= snap; box.N += snap; box.S -= snap; box.T = 0.0; box.B = 0.0; Vect_select_lines_by_box(Tmp, &box, GV_BOUNDARY, boxlist); if (boxlist->n_values > 0) { Vect_reset_list(reflist); for (j = 0; j < boxlist->n_values; j++) { int aline = boxlist->id[j]; if (!bsearch(&aline, BList->value, BList->n_values, sizeof(int), cmp_int)) { G_ilist_add(reflist, aline); } } /* snap bline to alines */ if (Vect_snap_line(Tmp, reflist, Points, snap, 0, NULL, NULL)) { /* rewrite bline*/ Vect_delete_line(Tmp, line); ret = Vect_write_line(Tmp, GV_BOUNDARY, Points, Cats); G_ilist_add(BList, ret); snapped_lines++; G_debug(3, "line %d snapped", line); } } } Vect_destroy_boxlist(boxlist); Vect_destroy_list(reflist); G_verbose_message(n_("%d boundary snapped", "%d boundaries snapped", snapped_lines), snapped_lines); } /* same procedure like for v.in.ogr: * 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 dangles are found */ do { G_message(_("Breaking lines...")); Vect_break_lines_list(Tmp, NULL, BList, GV_BOUNDARY, NULL); /* Probably not necessary for LINE x AREA */ G_message(_("Removing duplicates...")); Vect_remove_duplicates(Tmp, GV_BOUNDARY, NULL); G_message(_("Cleaning boundaries at nodes...")); nmodif = Vect_clean_small_angles_at_nodes(Tmp, GV_BOUNDARY, NULL); } while (nmodif > 0); /* ?: May be result of Vect_break_lines() + Vect_remove_duplicates() any dangle or bridge? * In that case, calls to Vect_remove_dangles() and Vect_remove_bridges() would be also necessary */ G_set_verbose(0); /* should be fast, be silent */ Vect_build_partial(Tmp, GV_BUILD_AREAS); G_set_verbose(verbose); nlines = Vect_get_num_lines(Tmp); ret = 0; for (line = 1; line <= nlines; line++) { if (!Vect_line_alive(Tmp, line)) continue; if (Vect_get_line_type(Tmp, line) == GV_BOUNDARY) { int left, rite; Vect_get_line_areas(Tmp, line, &left, &rite); if (left == 0 || rite == 0) { /* invalid boundary */ ret = 1; break; } } } if (ret) { Vect_remove_dangles(Tmp, GV_BOUNDARY, -1, NULL); Vect_remove_bridges(Tmp, NULL, NULL, NULL); } G_set_verbose(0); Vect_build_partial(Tmp, GV_BUILD_NONE); Vect_build_partial(Tmp, GV_BUILD_BASE); G_set_verbose(verbose); G_message(_("Merging lines...")); Vect_merge_lines(Tmp, GV_BOUNDARY, NULL, NULL); /* Attach islands */ G_message(_("Attaching islands...")); /* can take some time, show messages */ Vect_build_partial(Tmp, GV_BUILD_ATTACH_ISLES); /* Calculate new centroids for all areas */ nareas = Vect_get_num_areas(Tmp); Centr = (CENTR *) G_malloc((nareas + 1) * sizeof(CENTR)); /* index from 1 ! */ for (area = 1; area <= nareas; area++) { ret = Vect_get_point_in_area(Tmp, area, &(Centr[area].x), &(Centr[area].y)); if (ret < 0) { G_warning(_("Cannot calculate area centroid")); Centr[area].valid = 0; } else { Centr[area].valid = 1; } } /* Query input maps */ for (input = 0; input < 2; input++) { G_message(_("Querying vector map <%s>..."), Vect_get_full_name(&(In[input]))); for (area = 1; area <= nareas; area++) { Centr[area].cat[input] = Vect_new_cats_struct(); G_percent(area, nareas, 1); in_area = Vect_find_area(&(In[input]), Centr[area].x, Centr[area].y); if (in_area > 0) { in_centr = Vect_get_area_centroid(&(In[input]), in_area); if (in_centr > 0) { int i; Vect_read_line(&(In[input]), NULL, Cats, in_centr); /* Add all cats with original field number */ for (i = 0; i < Cats->n_cats; i++) { if (Cats->field[i] == field[input]) { ATTR *at; Vect_cat_set(Centr[area].cat[input], ofield[input + 1], Cats->cat[i]); /* Mark as used */ at = find_attr(&(attr[input]), Cats->cat[i]); if (!at) G_fatal_error(_("Attribute not found")); at->used = 1; } } } } } } G_message(_("Writing centroids...")); db_init_string(&stmt); out_cat = 1; for (area = 1; area <= nareas; area++) { int i; G_percent(area, nareas, 1); /* check the condition */ switch (operator) { case OP_AND: if (! (Centr[area].cat[0]->n_cats > 0 && Centr[area].cat[1]->n_cats > 0)) continue; break; case OP_OR: if (! (Centr[area].cat[0]->n_cats > 0 || Centr[area].cat[1]->n_cats > 0)) continue; break; case OP_NOT: if (! (Centr[area].cat[0]->n_cats > 0 && !(Centr[area].cat[1]->n_cats > 0))) continue; break; case OP_XOR: if ((Centr[area].cat[0]->n_cats > 0 && Centr[area].cat[1]->n_cats > 0) || (!(Centr[area].cat[0]->n_cats > 0) && !(Centr[area].cat[1]->n_cats > 0))) continue; break; } Vect_reset_line(Points); Vect_reset_cats(Cats); Vect_append_point(Points, Centr[area].x, Centr[area].y, 0.0); if (ofield[0] > 0) { /* Add new cats for all combinations of input cats (-1 in cycle for null) */ for (i = -1; i < Centr[area].cat[0]->n_cats; i++) { int j; if (i == -1 && Centr[area].cat[0]->n_cats > 0) continue; /* no need to make null */ for (j = -1; j < Centr[area].cat[1]->n_cats; j++) { if (j == -1 && Centr[area].cat[1]->n_cats > 0) continue; /* no need to make null */ if (ofield[0] > 0) Vect_cat_set(Cats, ofield[0], out_cat); /* attributes */ if (driver) { ATTR *at; sprintf(buf, "insert into %s values ( %d", Fi->table, out_cat); db_set_string(&stmt, buf); /* cata */ if (i >= 0) { if (attr[0].columns) { at = find_attr(&(attr[0]), Centr[area].cat[0]->cat[i]); if (!at) G_fatal_error(_("Attribute not found")); if (at->values) db_append_string(&stmt, at->values); else db_append_string(&stmt, attr[0].null_values); } else { sprintf(buf, ", %d", Centr[area].cat[0]->cat[i]); db_append_string(&stmt, buf); } } else { if (attr[0].columns) { db_append_string(&stmt, attr[0].null_values); } else { sprintf(buf, ", null"); db_append_string(&stmt, buf); } } /* catb */ if (j >= 0) { if (attr[1].columns) { at = find_attr(&(attr[1]), Centr[area].cat[1]->cat[j]); if (!at) G_fatal_error(_("Attribute not found")); if (at->values) db_append_string(&stmt, at->values); else db_append_string(&stmt, attr[1].null_values); } else { sprintf(buf, ", %d", Centr[area].cat[1]->cat[j]); db_append_string(&stmt, buf); } } else { if (attr[1].columns) { db_append_string(&stmt, attr[1].null_values); } else { sprintf(buf, ", null"); db_append_string(&stmt, buf); } } db_append_string(&stmt, " )"); G_debug(3, "%s", db_get_string(&stmt)); if (db_execute_immediate(driver, &stmt) != DB_OK) G_warning(_("Unable to insert new record: '%s'"), db_get_string(&stmt)); } out_cat++; } } } /* Add all cats from input vectors */ if (ofield[1] > 0 && field[0] > 0) { for (i = 0; i < Centr[area].cat[0]->n_cats; i++) { if (Centr[area].cat[0]->field[i] == field[0]) Vect_cat_set(Cats, ofield[1], Centr[area].cat[0]->cat[i]); } } if (ofield[2] > 0 && field[1] > 0 && ofield[1] != ofield[2]) { for (i = 0; i < Centr[area].cat[1]->n_cats; i++) { if (Centr[area].cat[1]->field[i] == field[1]) Vect_cat_set(Cats, ofield[2], Centr[area].cat[1]->cat[i]); } } Vect_write_line(Tmp, GV_CENTROID, Points, Cats); Vect_write_line(Out, GV_CENTROID, Points, Cats); } G_set_verbose(0); /* should be fast, be silent */ Vect_build_partial(Tmp, GV_BUILD_CENTROIDS); G_set_verbose(verbose); /* Copy valid boundaries to final output */ nlines = Vect_get_num_lines(Tmp); for (line = 1; line <= nlines; line++) { int i, ltype, side[2], centr[2]; G_percent(line, nlines, 1); /* must be before any continue */ if (!Vect_line_alive(Tmp, line)) continue; ltype = Vect_read_line(Tmp, Points, Cats, line); if (!(ltype & GV_BOUNDARY)) continue; Vect_get_line_areas(Tmp, line, &side[0], &side[1]); for (i = 0; i < 2; i++) { if (side[i] == 0) { /* This should not happen ! */ centr[i] = 0; continue; } if (side[i] > 0) { area = side[i]; } else { /* island */ area = Vect_get_isle_area(Tmp, abs(side[i])); } if (area > 0) centr[i] = Vect_get_area_centroid(Tmp, area); else centr[i] = 0; } if (centr[0] || centr[1]) Vect_write_line(Out, GV_BOUNDARY, Points, Cats); } return 0; }
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) { int i, j, ret, centre, line, centre1, centre2, tfield, tucfield; int nlines, nnodes, type, ltype, afield, nfield, geo, cat; int node, node1, node2; double cost, e1cost, e2cost, n1cost, n2cost, s1cost, s2cost, l, l1; struct Option *map, *output; struct Option *afield_opt, *nfield_opt, *afcol, *abcol, *ncol, *type_opt, *term_opt, *cost_opt, *tfield_opt, *tucfield_opt; struct Flag *geo_f, *turntable_f; struct GModule *module; struct Map_info Map, Out; struct cat_list *catlist; CENTER *Centers = NULL; int acentres = 0, ncentres = 0; NODE *Nodes; struct line_cats *Cats; struct line_pnts *Points, *SPoints; int niso, aiso; double *iso; int npnts1, apnts1 = 0, npnts2, apnts2 = 0; ISOPOINT *pnts1 = NULL, *pnts2 = NULL; int next_iso; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("network")); G_add_keyword(_("isolines")); module->label = _("Splits net by cost isolines."); module->description = _ ("Splits net to bands between cost isolines (direction from center). " "Center node must be opened (costs >= 0). " "Costs of center node are used in calculation."); map = G_define_standard_option(G_OPT_V_INPUT); output = G_define_standard_option(G_OPT_V_OUTPUT); term_opt = G_define_standard_option(G_OPT_V_CATS); term_opt->key = "ccats"; term_opt->required = YES; term_opt->description = _("Categories of centers (points on nodes) to which net " "will be allocated, " "layer for this categories is given by nlayer option"); cost_opt = G_define_option(); cost_opt->key = "costs"; cost_opt->type = TYPE_INTEGER; cost_opt->multiple = YES; cost_opt->required = YES; cost_opt->description = _("Costs for isolines"); afield_opt = G_define_standard_option(G_OPT_V_FIELD); afield_opt->key = "alayer"; afield_opt->answer = "1"; afield_opt->required = YES; afield_opt->label = _("Arc layer"); type_opt = G_define_standard_option(G_OPT_V_TYPE); type_opt->options = "line,boundary"; type_opt->answer = "line,boundary"; type_opt->required = YES; type_opt->label = _("Arc type"); nfield_opt = G_define_standard_option(G_OPT_V_FIELD); nfield_opt->key = "nlayer"; nfield_opt->answer = "2"; nfield_opt->required = YES; nfield_opt->label = _("Node layer"); afcol = G_define_standard_option(G_OPT_DB_COLUMN); afcol->key = "afcolumn"; afcol->description = _("Arc forward/both direction(s) cost column (number)"); afcol->guisection = _("Cost"); abcol = G_define_standard_option(G_OPT_DB_COLUMN); abcol->key = "abcolumn"; abcol->description = _("Arc backward direction cost column (number)"); abcol->guisection = _("Cost"); ncol = G_define_standard_option(G_OPT_DB_COLUMN); ncol->key = "ncolumn"; ncol->description = _("Node cost column (number)"); ncol->guisection = _("Cost"); turntable_f = G_define_flag(); turntable_f->key = 't'; turntable_f->description = _("Use turntable"); turntable_f->guisection = _("Turntable"); tfield_opt = G_define_standard_option(G_OPT_V_FIELD); tfield_opt->key = "tlayer"; tfield_opt->answer = "3"; tfield_opt->label = _("Layer with turntable"); tfield_opt->description = _("Relevant only with -t flag"); tfield_opt->guisection = _("Turntable"); tucfield_opt = G_define_standard_option(G_OPT_V_FIELD); tucfield_opt->key = "tuclayer"; tucfield_opt->answer = "4"; tucfield_opt->label = _("Layer with unique categories used in turntable"); tucfield_opt->description = _("Relevant only with -t flag"); tucfield_opt->guisection = _("Turntable"); geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = _("Use geodesic calculation for longitude-latitude locations"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); Vect_check_input_output_name(map->answer, output->answer, G_FATAL_EXIT); Cats = Vect_new_cats_struct(); Points = Vect_new_line_struct(); SPoints = Vect_new_line_struct(); type = Vect_option_to_types(type_opt); catlist = Vect_new_cat_list(); Vect_str_to_cat_list(term_opt->answer, catlist); /* Iso costs */ aiso = 1; iso = (double *)G_malloc(aiso * sizeof(double)); /* Set first iso to 0 */ iso[0] = 0; niso = 1; i = 0; while (cost_opt->answers[i]) { if (niso == aiso) { aiso += 1; iso = (double *)G_realloc(iso, aiso * sizeof(double)); } iso[niso] = atof(cost_opt->answers[i]); if (iso[niso] <= 0) G_fatal_error(_("Wrong iso cost: %f"), iso[niso]); if (iso[niso] <= iso[niso - 1]) G_fatal_error(_("Iso cost: %f less than previous"), iso[niso]); G_verbose_message(_("Iso cost %d: %f"), niso, iso[niso]); niso++; i++; } /* Should not happen: */ if (niso < 2) G_warning(_ ("Not enough costs, everything reachable falls to first band")); if (geo_f->answer) geo = 1; else geo = 0; Vect_set_open_level(2); if (Vect_open_old(&Map, map->answer, "") < 0) G_fatal_error(_("Unable to open vector map <%s>"), map->answer); afield = Vect_get_field_number(&Map, afield_opt->answer); nfield = Vect_get_field_number(&Map, nfield_opt->answer); tfield = Vect_get_field_number(&Map, tfield_opt->answer); tucfield = Vect_get_field_number(&Map, tucfield_opt->answer); /* Build graph */ if (turntable_f->answer) Vect_net_ttb_build_graph(&Map, type, afield, nfield, tfield, tucfield, afcol->answer, abcol->answer, ncol->answer, geo, 0); else Vect_net_build_graph(&Map, type, afield, nfield, afcol->answer, abcol->answer, ncol->answer, geo, 0); nnodes = Vect_get_num_nodes(&Map); nlines = Vect_get_num_lines(&Map); /* Create list of centres based on list of categories */ for (i = 1; i <= nlines; i++) { ltype = Vect_get_line_type(&Map, i); if (!(ltype & GV_POINT)) continue; Vect_read_line(&Map, Points, Cats, i); node = Vect_find_node(&Map, Points->x[0], Points->y[0], Points->z[0], 0, 0); if (!node) { G_warning(_("Point is not connected to the network")); continue; } if (!(Vect_cat_get(Cats, nfield, &cat))) continue; if (Vect_cat_in_cat_list(cat, catlist)) { Vect_net_get_node_cost(&Map, node, &n1cost); if (n1cost == -1) { /* closed */ G_warning(_("Centre at closed node (costs = -1) ignored")); } else { if (acentres == ncentres) { acentres += 1; Centers = (CENTER *) G_realloc(Centers, acentres * sizeof(CENTER)); } Centers[ncentres].cat = cat; Centers[ncentres].node = node; G_debug(2, "centre = %d node = %d cat = %d", ncentres, node, cat); ncentres++; } } } G_message(_("Number of centres: %d (nlayer %d)"), ncentres, nfield); if (ncentres == 0) G_warning(_ ("Not enough centres for selected nlayer. Nothing will be allocated.")); /* alloc and reset space for all nodes */ if (turntable_f->answer) { /* if turntable is used we are looking for lines as destinations, instead of the intersections (nodes) */ Nodes = (NODE *) G_calloc((nlines * 2 + 2), sizeof(NODE)); for (i = 2; i <= (nlines * 2 + 2); i++) { Nodes[i].centre = -1;/* NOTE: first two items of Nodes are not used */ } } else { Nodes = (NODE *) G_calloc((nnodes + 1), sizeof(NODE)); for (i = 1; i <= nnodes; i++) { Nodes[i].centre = -1; } } apnts1 = 1; pnts1 = (ISOPOINT *) G_malloc(apnts1 * sizeof(ISOPOINT)); apnts2 = 1; pnts2 = (ISOPOINT *) G_malloc(apnts2 * sizeof(ISOPOINT)); /* Fill Nodes by neares centre and costs from that centre */ for (centre = 0; centre < ncentres; centre++) { node1 = Centers[centre].node; Vect_net_get_node_cost(&Map, node1, &n1cost); G_debug(2, "centre = %d node = %d cat = %d", centre, node1, Centers[centre].cat); G_message(_("Calculating costs from centre %d..."), centre + 1); if (turntable_f->answer) for (line = 1; line <= nlines; line++) { G_debug(5, " node1 = %d line = %d", node1, line); Vect_net_get_node_cost(&Map, line, &n2cost); /* closed, left it as not attached */ if (Vect_read_line(&Map, Points, Cats, line) < 0) continue; if (Vect_get_line_type(&Map, line) != GV_LINE) continue; if (!Vect_cat_get(Cats, tucfield, &cat)) continue; for (j = 0; j < 2; j++) { if (j == 1) cat *= -1; ret = Vect_net_ttb_shortest_path(&Map, node1, 0, cat, 1, tucfield, NULL, &cost); if (ret == -1) { continue; } /* node unreachable */ /* We must add centre node costs (not calculated by Vect_net_shortest_path() ), but * only if centre and node are not identical, because at the end node cost is add later */ if (ret != 1) cost += n1cost; G_debug(5, "Arc nodes: %d %d cost: %f (x old cent: %d old cost %f", node1, line, cost, Nodes[line * 2 + j].centre, Nodes[line * 2 + j].cost); if (Nodes[line * 2 + j].centre == -1 || cost < Nodes[line * 2 + j].cost) { Nodes[line * 2 + j].cost = cost; Nodes[line * 2 + j].centre = centre; } } } else for (node2 = 1; node2 <= nnodes; node2++) { G_percent(node2, nnodes, 1); G_debug(5, " node1 = %d node2 = %d", node1, node2); Vect_net_get_node_cost(&Map, node2, &n2cost); if (n2cost == -1) { continue; } /* closed, left it as not attached */ ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &cost); if (ret == -1) { continue; } /* node unreachable */ /* We must add centre node costs (not calculated by Vect_net_shortest_path() ), but * only if centre and node are not identical, because at the end node cost is add later */ if (node1 != node2) cost += n1cost; G_debug(5, "Arc nodes: %d %d cost: %f (x old cent: %d old cost %f", node1, node2, cost, Nodes[node2].centre, Nodes[node2].cost); if (Nodes[node2].centre == -1 || cost < Nodes[node2].cost) { Nodes[node2].cost = cost; Nodes[node2].centre = centre; } } } /* Write arcs to new map */ if (Vect_open_new(&Out, output->answer, Vect_is_3d(&Map)) < 0) G_fatal_error(_("Unable to create vector map <%s>"), output->answer); Vect_hist_command(&Out); G_message("Generating isolines..."); nlines = Vect_get_num_lines(&Map); for (line = 1; line <= nlines; line++) { G_percent(line, nlines, 2); ltype = Vect_read_line(&Map, Points, NULL, line); if (!(ltype & type)) { continue; } l = Vect_line_length(Points); if (l == 0) continue; if (turntable_f->answer) { centre1 = Nodes[line * 2].centre; centre2 = Nodes[line * 2 + 1].centre; s1cost = Nodes[line * 2].cost; s2cost = Nodes[line * 2 + 1].cost; n1cost = n2cost = 0; } else { Vect_get_line_nodes(&Map, line, &node1, &node2); centre1 = Nodes[node1].centre; centre2 = Nodes[node2].centre; s1cost = Nodes[node1].cost; s2cost = Nodes[node2].cost; Vect_net_get_node_cost(&Map, node1, &n1cost); Vect_net_get_node_cost(&Map, node2, &n2cost); } Vect_net_get_line_cost(&Map, line, GV_FORWARD, &e1cost); Vect_net_get_line_cost(&Map, line, GV_BACKWARD, &e2cost); G_debug(3, "Line %d : length = %f", line, l); G_debug(3, "Arc centres: %d %d (nodes: %d %d)", centre1, centre2, node1, node2); G_debug(3, " s1cost = %f n1cost = %f e1cost = %f", s1cost, n1cost, e1cost); G_debug(3, " s2cost = %f n2cost = %f e2cost = %f", s2cost, n2cost, e2cost); /* First check if arc is reachable from at least one side */ if ((centre1 != -1 && n1cost != -1 && e1cost != -1) || (centre2 != -1 && n2cost != -1 && e2cost != -1)) { /* Line is reachable at least from one side */ G_debug(3, " -> arc is reachable"); /* Add costs of node to starting costs */ s1cost += n1cost; s2cost += n2cost; e1cost /= l; e2cost /= l; /* Find points on isolines along the line in both directions, add them to array, * first point is placed at the beginning/end of line */ /* Forward */ npnts1 = 0; /* in case this direction is closed */ if (centre1 != -1 && n1cost != -1 && e1cost != -1) { /* Find iso for beginning of the line */ next_iso = 0; for (i = niso - 1; i >= 0; i--) { if (iso[i] <= s1cost) { next_iso = i; break; } } /* Add first */ pnts1[0].iso = next_iso; pnts1[0].distance = 0; npnts1++; next_iso++; /* Calculate distances for points along line */ while (next_iso < niso) { if (e1cost == 0) break; /* Outside line */ l1 = (iso[next_iso] - s1cost) / e1cost; if (l1 >= l) break; /* Outside line */ if (npnts1 == apnts1) { apnts1 += 1; pnts1 = (ISOPOINT *) G_realloc(pnts1, apnts1 * sizeof(ISOPOINT)); } pnts1[npnts1].iso = next_iso; pnts1[npnts1].distance = l1; G_debug(3, " forward %d : iso %d : distance %f : cost %f", npnts1, next_iso, l1, iso[next_iso]); npnts1++; next_iso++; } } G_debug(3, " npnts1 = %d", npnts1); /* Backward */ npnts2 = 0; if (centre2 != -1 && n2cost != -1 && e2cost != -1) { /* Find iso for beginning of the line */ next_iso = 0; for (i = niso - 1; i >= 0; i--) { if (iso[i] <= s2cost) { next_iso = i; break; } } /* Add first */ pnts2[0].iso = next_iso; pnts2[0].distance = l; npnts2++; next_iso++; /* Calculate distances for points along line */ while (next_iso < niso) { if (e2cost == 0) break; /* Outside line */ l1 = (iso[next_iso] - s2cost) / e2cost; if (l1 >= l) break; /* Outside line */ if (npnts2 == apnts2) { apnts2 += 1; pnts2 = (ISOPOINT *) G_realloc(pnts2, apnts2 * sizeof(ISOPOINT)); } pnts2[npnts2].iso = next_iso; pnts2[npnts2].distance = l - l1; G_debug(3, " backward %d : iso %d : distance %f : cost %f", npnts2, next_iso, l - l1, iso[next_iso]); npnts2++; next_iso++; } } G_debug(3, " npnts2 = %d", npnts2); /* Limit number of points by maximum costs in reverse direction, this may remove * also the first point in one direction, but not in both */ /* Forward */ if (npnts2 > 0) { for (i = 0; i < npnts1; i++) { G_debug(3, " pnt1 = %d dist1 = %f iso1 = %d max iso2 = %d", i, pnts1[i].distance, pnts1[i].iso, pnts2[npnts2 - 1].iso); if (pnts2[npnts2 - 1].iso < pnts1[i].iso) { G_debug(3, " -> cut here"); npnts1 = i; break; } } } G_debug(3, " npnts1 cut = %d", npnts1); /* Backward */ if (npnts1 > 0) { for (i = 0; i < npnts2; i++) { G_debug(3, " pnt2 = %d dist2 = %f iso2 = %d max iso1 = %d", i, pnts2[i].distance, pnts2[i].iso, pnts1[npnts1 - 1].iso); if (pnts1[npnts1 - 1].iso < pnts2[i].iso) { G_debug(3, " -> cut here"); npnts2 = i; break; } } } G_debug(3, " npnts2 cut = %d", npnts2); /* Biggest cost shoud be equal if exist (npnts > 0). Cut out overlapping segments, * this can cut only points on line but not first points */ if (npnts1 > 1 && npnts2 > 1) { while (npnts1 > 1 && npnts2 > 1) { if (pnts1[npnts1 - 1].distance >= pnts2[npnts2 - 1].distance) { /* overlap */ npnts1--; npnts2--; } else { break; } } } G_debug(3, " npnts1 2. cut = %d", npnts1); G_debug(3, " npnts2 2. cut = %d", npnts2); /* Now we have points in both directions which may not overlap, npoints in one * direction may be 0 but not both */ /* Join both arrays, iso of point is for next segment (point is at the beginning) */ /* In case npnts1 == 0 add point at distance 0 */ if (npnts1 == 0) { G_debug(3, " npnts1 = 0 -> add first at distance 0, cat = %d", pnts2[npnts2 - 1].iso); pnts1[0].iso = pnts2[npnts2 - 1].iso; /* use last point iso in reverse direction */ pnts1[0].distance = 0; npnts1++; } for (i = npnts2 - 1; i >= 0; i--) { /* Check if identical */ if (pnts1[npnts1 - 1].distance == pnts2[i].distance) continue; if (npnts1 == apnts1) { apnts1 += 1; pnts1 = (ISOPOINT *) G_realloc(pnts1, apnts1 * sizeof(ISOPOINT)); } pnts1[npnts1].iso = pnts2[i].iso - 1; /* last may be -1, but it is not used */ pnts1[npnts1].distance = pnts2[i].distance; npnts1++; } /* In case npnts2 == 0 add point at the end */ if (npnts2 == 0) { pnts1[npnts1].iso = 0; /* not used */ pnts1[npnts1].distance = l; npnts1++; } /* Create line segments. */ for (i = 1; i < npnts1; i++) { cat = pnts1[i - 1].iso + 1; G_debug(3, " segment %f - %f cat %d", pnts1[i - 1].distance, pnts1[i].distance, cat); ret = Vect_line_segment(Points, pnts1[i - 1].distance, pnts1[i].distance, SPoints); if (ret == 0) { G_warning(_ ("Cannot get line segment, segment out of line")); } else { Vect_reset_cats(Cats); Vect_cat_set(Cats, 1, cat); Vect_write_line(&Out, ltype, SPoints, Cats); } } } else { /* arc is not reachable */ G_debug(3, " -> arc is not reachable"); Vect_reset_cats(Cats); Vect_write_line(&Out, ltype, Points, Cats); } } Vect_build(&Out); /* Free, ... */ G_free(Nodes); G_free(Centers); Vect_close(&Map); Vect_close(&Out); exit(EXIT_SUCCESS); }
/*! \brief Load vector map to memory The other alternative may be to load to a tmp file \param grassname vector map name \param[out] number of loaded features \return pointer to geoline struct \return NULL on failure */ geoline *Gv_load_vect(const char *grassname, int *nlines) { struct Map_info map; struct line_pnts *points; struct line_cats *Cats = NULL; geoline *top, *gln, *prev; int np, i, n, nareas, nl = 0, area, type, is3d; struct Cell_head wind; float vect[2][3]; const char *mapset; mapset = G_find_vector2(grassname, ""); if (!mapset) { G_warning(_("Vector map <%s> not found"), grassname); return NULL; } Vect_set_open_level(2); if (Vect_open_old(&map, grassname, "") == -1) { G_warning(_("Unable to open vector map <%s>"), G_fully_qualified_name(grassname, mapset)); return NULL; } top = gln = (geoline *) G_malloc(sizeof(geoline)); /* G_fatal_error */ if (!top) { return NULL; } prev = top; #ifdef TRAK_MEM Tot_mem += sizeof(geoline); #endif points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); G_get_set_window(&wind); Vect_set_constraint_region(&map, wind.north, wind.south, wind.east, wind.west, PORT_DOUBLE_MAX, -PORT_DOUBLE_MAX); is3d = Vect_is_3d(&map); /* Read areas */ n = Vect_get_num_areas(&map); nareas = 0; G_debug(3, "Reading vector areas (nareas = %d)", n); for (area = 1; area <= n; area++) { G_debug(3, " area %d", area); Vect_get_area_points(&map, area, points); if (points->n_points < 3) continue; /* initialize style */ gln->highlighted = 0; gln->type = OGSF_POLYGON; gln->npts = np = points->n_points; G_debug(3, " np = %d", np); if (is3d) { gln->dims = 3; gln->p3 = (Point3 *) G_calloc(np, sizeof(Point3)); /* G_fatal_error */ if (!gln->p3) { return (NULL); } #ifdef TRAK_MEM Tot_mem += (np * sizeof(Point3)); #endif } else { gln->dims = 2; gln->p2 = (Point2 *) G_calloc(np, sizeof(Point2)); /* G_fatal_error */ if (!gln->p2) { return (NULL); } #ifdef TRAK_MEM Tot_mem += (np * sizeof(Point2)); #endif } for (i = 0; i < np; i++) { if (is3d) { gln->p3[i][X] = points->x[i]; gln->p3[i][Y] = points->y[i]; gln->p3[i][Z] = points->z[i]; } else { gln->p2[i][X] = points->x[i]; gln->p2[i][Y] = points->y[i]; } } /* Calc normal (should be average) */ if (is3d) { vect[0][X] = (float)(gln->p3[0][X] - gln->p3[1][X]); vect[0][Y] = (float)(gln->p3[0][Y] - gln->p3[1][Y]); vect[0][Z] = (float)(gln->p3[0][Z] - gln->p3[1][Z]); vect[1][X] = (float)(gln->p3[2][X] - gln->p3[1][X]); vect[1][Y] = (float)(gln->p3[2][Y] - gln->p3[1][Y]); vect[1][Z] = (float)(gln->p3[2][Z] - gln->p3[1][Z]); GS_v3cross(vect[1], vect[0], gln->norm); } gln->cats = NULL; gln->next = (geoline *) G_malloc(sizeof(geoline)); /* G_fatal_error */ if (!gln->next) { return (NULL); } #ifdef TRAK_MEM Tot_mem += sizeof(geoline); #endif prev = gln; gln = gln->next; nareas++; } G_debug(3, "%d areas loaded", nareas); /* Read all lines */ G_debug(3, "Reading vector lines ..."); while (-1 < (type = Vect_read_next_line(&map, points, Cats))) { G_debug(3, "line type = %d", type); if (type & (GV_LINES | GV_FACE)) { if (type & (GV_LINES)) { gln->type = OGSF_LINE; } else { gln->type = OGSF_POLYGON; /* Vect_append_point ( points, points->x[0], points->y[0], points->z[0] ); */ } /* initialize style */ gln->highlighted = 0; gln->npts = np = points->n_points; G_debug(3, " np = %d", np); if (is3d) { gln->dims = 3; gln->p3 = (Point3 *) G_calloc(np, sizeof(Point3)); /* G_fatal_error */ if (!gln->p3) { return (NULL); } #ifdef TRAK_MEM Tot_mem += (np * sizeof(Point3)); #endif } else { gln->dims = 2; gln->p2 = (Point2 *) G_calloc(np, sizeof(Point2)); /* G_fatal_error */ if (!gln->p2) { return (NULL); } #ifdef TRAK_MEM Tot_mem += (np * sizeof(Point2)); #endif } for (i = 0; i < np; i++) { if (is3d) { gln->p3[i][X] = points->x[i]; gln->p3[i][Y] = points->y[i]; gln->p3[i][Z] = points->z[i]; } else { gln->p2[i][X] = points->x[i]; gln->p2[i][Y] = points->y[i]; } } /* Calc normal (should be average) */ if (is3d && gln->type == OGSF_POLYGON) { vect[0][X] = (float)(gln->p3[0][X] - gln->p3[1][X]); vect[0][Y] = (float)(gln->p3[0][Y] - gln->p3[1][Y]); vect[0][Z] = (float)(gln->p3[0][Z] - gln->p3[1][Z]); vect[1][X] = (float)(gln->p3[2][X] - gln->p3[1][X]); vect[1][Y] = (float)(gln->p3[2][Y] - gln->p3[1][Y]); vect[1][Z] = (float)(gln->p3[2][Z] - gln->p3[1][Z]); GS_v3cross(vect[1], vect[0], gln->norm); G_debug(3, "norm %f %f %f", gln->norm[0], gln->norm[1], gln->norm[2]); } /* Store category info for thematic display */ if (Cats->n_cats > 0) { gln->cats = Cats; Cats = Vect_new_cats_struct(); } else { gln->cats = NULL; Vect_reset_cats(Cats); } gln->next = (geoline *) G_malloc(sizeof(geoline)); /* G_fatal_error */ if (!gln->next) { return (NULL); } #ifdef TRAK_MEM Tot_mem += sizeof(geoline); #endif prev = gln; gln = gln->next; nl++; } } G_debug(3, "%d lines loaded", nl); nl += nareas; prev->next = NULL; G_free(gln); #ifdef TRAK_MEM Tot_mem -= sizeof(geoline); #endif Vect_close(&map); if (!nl) { G_warning(_("No features from vector map <%s> fall within current region"), G_fully_qualified_name(grassname, mapset)); return (NULL); } else { G_message(_("Vector map <%s> loaded (%d features)"), G_fully_qualified_name(grassname, mapset), nl); } *nlines = nl; #ifdef TRAK_MEM G_debug(3, "Total vect memory = %d Kbytes", Tot_mem / 1000); #endif return (top); }
/** \brief Extrude 2D vector feature to 3D - point -> 3d line (vertical) - line -> set of faces (each segment defines one face) - area -> set of faces + kernel \param In input vector map \param[in,out] Out output vector map \param Cats categories \param Points points \param fdrast background raster map \param trace trace raster map values \param interpolation method \param objheight object height \param voffset vertical offset \param window raster region \param type feature type \param centroid number of centroid for area \return number of written objects */ int extrude(struct Map_info *In, struct Map_info *Out, const struct line_cats *Cats, const struct line_pnts *Points, int fdrast, int trace, int interp_method, double scale, int null_defined, double null_val, double objheight, double voffset, const struct Cell_head *window, int type, int centroid) { int k; /* Points->n_points */ int nlines; double voffset_dem; /* minimal offset */ double voffset_curr; /* offset of current point */ double voffset_next; /* offset of next point */ nlines = 0; if (type != GV_POINT && Points->n_points < 2) return nlines; /* not enough points to face */ if (!Points_wall) { Points_wall = Vect_new_line_struct(); Points_roof = Vect_new_line_struct(); Points_floor = Vect_new_line_struct(); Cats_floor = Vect_new_cats_struct(); } else { Vect_reset_line(Points_wall); Vect_reset_line(Points_roof); Vect_reset_line(Points_floor); Vect_reset_cats(Cats_floor); } voffset_dem = 0.0; /* do not trace -> calculate minimum dem offset */ if (fdrast >= 0 && !trace) { for (k = 0; k < Points->n_points; k++) { voffset_curr = scale * Rast_get_sample(fdrast, window, NULL, Points->y[k], Points->x[k], /* north, east */ 0, interp_method); if (Rast_is_d_null_value(&voffset_curr)) { if (null_defined) voffset_curr = null_val; else voffset_curr = 0.; } if (k == 0) { voffset_dem = voffset_curr; } else { if (voffset_curr < voffset_dem) voffset_dem = voffset_curr; } } } /* build walls, roof and floor */ for (k = 0; ; k++) { voffset_curr = voffset_next = 0.0; if (fdrast >= 0 && trace) { voffset_curr = scale * Rast_get_sample(fdrast, window, NULL, Points->y[k], Points->x[k], /* north, east */ 0, interp_method); if (type != GV_POINT) { voffset_next = scale * Rast_get_sample(fdrast, window, NULL, Points->y[k + 1], /* north, east */ Points->x[k + 1], 0, interp_method); } } if (Rast_is_d_null_value(&voffset_curr)) { if (null_defined) voffset_curr = null_val; else voffset_curr = 0.; } if (Rast_is_d_null_value(&voffset_next)) { if (null_defined) voffset_next = null_val; else voffset_next = 0.; } if (trace) { voffset_curr += voffset; voffset_next += voffset; } else { voffset_curr = voffset_dem + voffset; voffset_next = voffset_dem + voffset; } if (type == GV_POINT) { /* point -> 3d line (vertical) */ Vect_append_point(Points_wall, Points->x[k], Points->y[k], Points->z[k] + voffset_curr); Vect_append_point(Points_wall, Points->x[k], Points->y[k], Points->z[k] + objheight + (trace ? voffset_curr : 0.)); } if (type & (GV_LINE | GV_AREA)) { /* reset */ Vect_reset_line(Points_wall); /* line/boundary segment -> face */ Vect_append_point(Points_wall, Points->x[k], Points->y[k], Points->z[k] + voffset_curr); Vect_append_point(Points_wall, Points->x[k + 1], Points->y[k + 1], Points->z[k + 1] + voffset_next); Vect_append_point(Points_wall, Points->x[k + 1], Points->y[k + 1], Points->z[k + 1] + objheight + (trace ? voffset_next : 0.)); Vect_append_point(Points_wall, Points->x[k], Points->y[k], Points->z[k] + objheight + (trace ? voffset_curr : 0.)); Vect_append_point(Points_wall, Points->x[k], Points->y[k], Points->z[k] + voffset_curr); Vect_write_line(Out, GV_FACE, Points_wall, Cats); nlines++; if (type == GV_AREA) { /* roof */ Vect_append_point(Points_roof, Points->x[k], Points->y[k], Points->z[k] + objheight + (trace ? voffset_curr : 0.)); /* floor */ Vect_append_point(Points_floor, Points->x[k], Points->y[k], Points->z[k] + voffset_curr); } } if (k >= Points->n_points - 2) break; } if (type == GV_POINT) { Vect_write_line(Out, GV_LINE, Points_wall, Cats); } else if (type == GV_AREA && Points_roof->n_points > 2) { /* close roof and floor */ Vect_append_point(Points_roof, Points_roof->x[0], Points_roof->y[0], Points_roof->z[0]); Vect_append_point(Points_floor, Points_floor->x[0], Points_floor->y[0], Points_floor->z[0]); /* write roof and floor */ Vect_write_line(Out, GV_FACE, Points_roof, Cats); Vect_write_line(Out, GV_FACE, Points_floor, Cats); nlines += 2; if (centroid > 0) { /* centroid -> kernel */ Vect_read_line(In, Points_floor, Cats_floor, centroid); Points_floor->z[0] = Points_roof->z[0] / 2.0; /* TODO: do it better */ Vect_write_line(Out, GV_KERNEL, Points_floor, Cats_floor); nlines++; } } return nlines; }
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 extract_points(int z_flag) { struct line_pnts *points = Vect_new_line_struct(); CELL *cellbuf; FCELL *fcellbuf; DCELL *dcellbuf; int row, col; double x, y; int count; switch (data_type) { case CELL_TYPE: cellbuf = Rast_allocate_c_buf(); break; case FCELL_TYPE: fcellbuf = Rast_allocate_f_buf(); break; case DCELL_TYPE: dcellbuf = Rast_allocate_d_buf(); break; } G_message(_("Extracting points...")); count = 1; for (row = 0; row < cell_head.rows; row++) { G_percent(row, n_rows, 2); y = Rast_row_to_northing((double)(row + .5), &cell_head); switch (data_type) { case CELL_TYPE: Rast_get_c_row(input_fd, cellbuf, row); break; case FCELL_TYPE: Rast_get_f_row(input_fd, fcellbuf, row); break; case DCELL_TYPE: Rast_get_d_row(input_fd, dcellbuf, row); break; } for (col = 0; col < cell_head.cols; col++) { int cat, val; double dval; x = Rast_col_to_easting((double)(col + .5), &cell_head); switch (data_type) { case CELL_TYPE: if (Rast_is_c_null_value(cellbuf + col)) continue; val = cellbuf[col]; dval = val; break; case FCELL_TYPE: if (Rast_is_f_null_value(fcellbuf + col)) continue; dval = fcellbuf[col]; break; case DCELL_TYPE: if (Rast_is_d_null_value(dcellbuf + col)) continue; dval = dcellbuf[col]; break; } /* value_flag is used only for CELL type */ cat = (value_flag) ? val : count; Vect_reset_line(points); Vect_reset_cats(Cats); Vect_cat_set(Cats, 1, cat); Vect_append_point(points, x, y, dval); Vect_write_line(&Map, GV_POINT, points, Cats); if ((driver != NULL) && !value_flag) { insert_value(cat, val, dval); } count++; } } G_percent(row, n_rows, 2); switch (data_type) { case CELL_TYPE: G_free(cellbuf); break; case FCELL_TYPE: G_free(fcellbuf); break; case DCELL_TYPE: G_free(dcellbuf); break; } Vect_destroy_line_struct(points); return (1); }
int main(int argc, char **argv) { double radius; double fisher, david, douglas, lloyd, lloydip, morisita; int i, nquads, *counts; struct Cell_head window; struct GModule *module; struct { struct Option *input, *field, *output, *n, *r; } parm; struct { struct Flag *g; } flag; COOR *quads; struct Map_info Map; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("statistics")); G_add_keyword(_("point pattern")); module->description = _("Indices for quadrat counts of vector point lists."); parm.input = G_define_standard_option(G_OPT_V_INPUT); parm.field = G_define_standard_option(G_OPT_V_FIELD_ALL); parm.output = G_define_standard_option(G_OPT_V_OUTPUT); parm.output->required = NO; parm.output->description = _("Name for output quadrat centers map (number of points is written as category)"); parm.n = G_define_option(); parm.n->key = "nquadrats"; parm.n->type = TYPE_INTEGER; parm.n->required = YES; parm.n->description = _("Number of quadrats"); parm.r = G_define_option(); parm.r->key = "radius"; parm.r->type = TYPE_DOUBLE; parm.r->required = YES; parm.r->description = _("Quadrat radius"); flag.g = G_define_flag(); flag.g->key = 'g'; flag.g->description = _("Print results in shell script style"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); sscanf(parm.n->answer, "%d", &nquads); sscanf(parm.r->answer, "%lf", &radius); G_get_window(&window); /* Open input */ Vect_set_open_level(2); if (Vect_open_old2(&Map, parm.input->answer, "", parm.field->answer) < 0) G_fatal_error(_("Unable to open vector map <%s>"), parm.input->answer); /* Get the quadrats */ G_message(_("Finding quadrats...")); quads = find_quadrats(nquads, radius, window); /* Get the counts per quadrat */ G_message(_("Counting points quadrats...")); counts = (int *)G_malloc(nquads * (sizeof(int))); count_sites(quads, nquads, counts, radius, &Map, Vect_get_field_number(&Map, parm.field->answer)); Vect_close(&Map); /* output if requested */ if (parm.output->answer) { struct Map_info Out; struct line_pnts *Points; struct line_cats *Cats; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); if (Vect_open_new(&Out, parm.output->answer, 0) < 0) G_fatal_error(_("Unable to create vector map <%s>"), parm.output->answer); Vect_hist_command(&Out); for (i = 0; i < nquads; i++) { Vect_reset_line(Points); Vect_reset_cats(Cats); Vect_append_point(Points, quads[i].x, quads[i].y, 0.0); Vect_cat_set(Cats, 1, counts[i]); Vect_write_line(&Out, GV_POINT, Points, Cats); } Vect_build(&Out); Vect_close(&Out); } /* Indices if requested */ qindices(counts, nquads, &fisher, &david, &douglas, &lloyd, &lloydip, &morisita); if (!flag.g->answer) { fprintf(stdout, "-----------------------------------------------------------\n"); fprintf(stdout, "Index Realization\n"); fprintf(stdout, "-----------------------------------------------------------\n"); fprintf(stdout, "Fisher el al (1922) Relative Variance %g\n", fisher); fprintf(stdout, "David & Moore (1954) Index of Cluster Size %g\n", david); fprintf(stdout, "Douglas (1975) Index of Cluster Frequency %g\n", douglas); fprintf(stdout, "Lloyd (1967) \"mean crowding\" %g\n", lloyd); fprintf(stdout, "Lloyd (1967) Index of patchiness %g\n", lloydip); fprintf(stdout, "Morisita's (1959) I (variability b/n patches) %g\n", morisita); fprintf(stdout, "-----------------------------------------------------------\n"); } else { fprintf(stdout, "fisher=%g\n", fisher); fprintf(stdout, "david=%g\n", david); fprintf(stdout, "douglas=%g\n", douglas); fprintf(stdout, "lloyd=%g\n", lloyd); fprintf(stdout, "lloydip=%g\n", lloydip); fprintf(stdout, "morisita=%g\n", morisita); } exit(EXIT_SUCCESS); }
int main(int argc, char *argv[]) { int i, cat, with_z, more, ctype, nrows; char buf[DB_SQL_MAX]; int count; double coor[3]; int ncoor; struct Option *driver_opt, *database_opt, *table_opt; struct Option *xcol_opt, *ycol_opt, *zcol_opt, *keycol_opt, *where_opt, *outvect; struct Flag *same_table_flag; struct GModule *module; struct Map_info Map; struct line_pnts *Points; struct line_cats *Cats; dbString sql; dbDriver *driver; dbCursor cursor; dbTable *table; dbColumn *column; dbValue *value; struct field_info *fi; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("import")); G_add_keyword(_("database")); G_add_keyword(_("points")); module->description = _("Creates new vector (points) map from database table containing coordinates."); table_opt = G_define_standard_option(G_OPT_DB_TABLE); table_opt->required = YES; table_opt->description = _("Input table name"); driver_opt = G_define_standard_option(G_OPT_DB_DRIVER); driver_opt->options = db_list_drivers(); driver_opt->answer = (char *)db_get_default_driver_name(); driver_opt->guisection = _("Input DB"); database_opt = G_define_standard_option(G_OPT_DB_DATABASE); database_opt->answer = (char *)db_get_default_database_name(); database_opt->guisection = _("Input DB"); xcol_opt = G_define_standard_option(G_OPT_DB_COLUMN); xcol_opt->key = "x"; xcol_opt->required = YES; xcol_opt->description = _("Name of column containing x coordinate"); ycol_opt = G_define_standard_option(G_OPT_DB_COLUMN); ycol_opt->key = "y"; ycol_opt->required = YES; ycol_opt->description = _("Name of column containing y coordinate"); zcol_opt = G_define_standard_option(G_OPT_DB_COLUMN); zcol_opt->key = "z"; zcol_opt->description = _("Name of column containing z coordinate"); zcol_opt->guisection = _("3D output"); keycol_opt = G_define_standard_option(G_OPT_DB_COLUMN); keycol_opt->key = "key"; keycol_opt->required = NO; keycol_opt->label = _("Name of column containing category number"); keycol_opt->description = _("Must refer to an integer column"); where_opt = G_define_standard_option(G_OPT_DB_WHERE); where_opt->guisection = _("Selection"); outvect = G_define_standard_option(G_OPT_V_OUTPUT); same_table_flag = G_define_flag(); same_table_flag->key = 't'; same_table_flag->description = _("Use imported table as attribute table for new map"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); if (zcol_opt->answer) { with_z = WITH_Z; ncoor = 3; } else { with_z = WITHOUT_Z; ncoor = 2; } Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); db_init_string(&sql); if (G_get_overwrite()) { /* We don't want to delete the input table when overwriting the output * vector. */ char name[GNAME_MAX], mapset[GMAPSET_MAX]; if (!G_name_is_fully_qualified(outvect->answer, name, mapset)) { strcpy(name, outvect->answer); strcpy(mapset, G_mapset()); } Vect_set_open_level(1); /* no topo needed */ if (strcmp(mapset, G_mapset()) == 0 && G_find_vector2(name, mapset) && Vect_open_old(&Map, name, mapset) >= 0) { int num_dblinks; num_dblinks = Vect_get_num_dblinks(&Map); for (i = 0; i < num_dblinks; i++) { if ((fi = Vect_get_dblink(&Map, i)) != NULL && strcmp(fi->driver, driver_opt->answer) == 0 && strcmp(fi->database, database_opt->answer) == 0 && strcmp(fi->table, table_opt->answer) == 0) G_fatal_error(_("Vector map <%s> cannot be overwritten " "because input table <%s> is linked to " "this map."), outvect->answer, table_opt->answer); } Vect_close(&Map); } } if (Vect_open_new(&Map, outvect->answer, with_z) < 0) G_fatal_error(_("Unable to create vector map <%s>"), outvect->answer); Vect_set_error_handler_io(NULL, &Map); Vect_hist_command(&Map); fi = Vect_default_field_info(&Map, 1, NULL, GV_1TABLE); /* Open driver */ driver = db_start_driver_open_database(driver_opt->answer, database_opt->answer); if (driver == NULL) { G_fatal_error(_("Unable to open database <%s> by driver <%s>"), fi->database, fi->driver); } db_set_error_handler_driver(driver); /* check if target table already exists */ G_debug(3, "Output vector table <%s>, driver: <%s>, database: <%s>", outvect->answer, db_get_default_driver_name(), db_get_default_database_name()); if (!same_table_flag->answer && db_table_exists(db_get_default_driver_name(), db_get_default_database_name(), outvect->answer) == 1) G_fatal_error(_("Output vector map, table <%s> (driver: <%s>, database: <%s>) " "already exists"), outvect->answer, db_get_default_driver_name(), db_get_default_database_name()); if (keycol_opt->answer) { int coltype; coltype = db_column_Ctype(driver, table_opt->answer, keycol_opt->answer); if (coltype == -1) G_fatal_error(_("Column <%s> not found in table <%s>"), keycol_opt->answer, table_opt->answer); if (coltype != DB_C_TYPE_INT) G_fatal_error(_("Data type of key column must be integer")); } else { if (same_table_flag->answer) { G_fatal_error(_("Option <%s> must be specified when -%c flag is given"), keycol_opt->key, same_table_flag->key); } if (strcmp(db_get_default_driver_name(), "sqlite") != 0) G_fatal_error(_("Unable to define key column. This operation is not supported " "by <%s> driver. You need to define <%s> option."), fi->driver, keycol_opt->key); } /* Open select cursor */ sprintf(buf, "SELECT %s, %s", xcol_opt->answer, ycol_opt->answer); db_set_string(&sql, buf); if (with_z) { sprintf(buf, ", %s", zcol_opt->answer); db_append_string(&sql, buf); } if (keycol_opt->answer) { sprintf(buf, ", %s", keycol_opt->answer); db_append_string(&sql, buf); } sprintf(buf, " FROM %s", table_opt->answer); db_append_string(&sql, buf); if (where_opt->answer) { sprintf(buf, " WHERE %s", where_opt->answer); db_append_string(&sql, buf); } G_debug(2, "SQL: %s", db_get_string(&sql)); if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) { G_fatal_error(_("Unable to open select cursor: '%s'"), db_get_string(&sql)); } table = db_get_cursor_table(&cursor); nrows = db_get_num_rows(&cursor); G_debug(2, "%d points selected", nrows); count = cat = 0; G_message(_("Writing features...")); while (db_fetch(&cursor, DB_NEXT, &more) == DB_OK && more) { G_percent(count, nrows, 2); /* key column */ if (keycol_opt->answer) { column = db_get_table_column(table, with_z ? 3 : 2); ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column)); if (ctype != DB_C_TYPE_INT) G_fatal_error(_("Key column must be integer")); value = db_get_column_value(column); cat = db_get_value_int(value); } else { cat++; } /* coordinates */ for (i = 0; i < ncoor; i++) { column = db_get_table_column(table, i); ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column)); if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE) G_fatal_error(_("x/y/z column must be integer or double")); value = db_get_column_value(column); if (ctype == DB_C_TYPE_INT) coor[i] = (double)db_get_value_int(value); else coor[i] = db_get_value_double(value); } Vect_reset_line(Points); Vect_reset_cats(Cats); Vect_append_point(Points, coor[0], coor[1], coor[2]); Vect_cat_set(Cats, 1, cat); Vect_write_line(&Map, GV_POINT, Points, Cats); count++; } G_percent(1, 1, 1); /* close connection to input DB before copying attributes */ db_close_database_shutdown_driver(driver); /* Copy table */ if (!same_table_flag->answer) { G_message(_("Copying attributes...")); if (DB_FAILED == db_copy_table_where(driver_opt->answer, database_opt->answer, table_opt->answer, fi->driver, fi->database, fi->table, where_opt->answer)) { /* where can be NULL */ G_warning(_("Unable to copy table")); } else { Vect_map_add_dblink(&Map, 1, NULL, fi->table, keycol_opt->answer ? keycol_opt->answer : GV_KEY_COLUMN, fi->database, fi->driver); } if (!keycol_opt->answer) { /* TODO: implement for all DB drivers in generic way if * possible */ driver = db_start_driver_open_database(fi->driver, fi->database); if (driver == NULL) { G_fatal_error(_("Unable to open database <%s> by driver <%s>"), fi->database, fi->driver); } db_set_error_handler_driver(driver); /* add key column */ sprintf(buf, "ALTER TABLE %s ADD COLUMN %s INTEGER", fi->table, GV_KEY_COLUMN); db_set_string(&sql, buf); if (db_execute_immediate(driver, &sql) != DB_OK) { G_fatal_error(_("Unable to add key column <%s>: " "SERIAL type is not supported by <%s>"), GV_KEY_COLUMN, fi->driver); } /* update key column */ sprintf(buf, "UPDATE %s SET %s = _ROWID_", fi->table, GV_KEY_COLUMN); db_set_string(&sql, buf); if (db_execute_immediate(driver, &sql) != DB_OK) { G_fatal_error(_("Failed to update key column <%s>"), GV_KEY_COLUMN); } } } else { /* do not copy attributes, link original table */ Vect_map_add_dblink(&Map, 1, NULL, table_opt->answer, keycol_opt->answer ? keycol_opt->answer : GV_KEY_COLUMN, database_opt->answer, driver_opt->answer); } Vect_build(&Map); Vect_close(&Map); G_done_msg(_n("%d point written to vector map.", "%d points written to vector map.", count), count); return (EXIT_SUCCESS); }
int line_area(struct Map_info *In, int *field, struct Map_info *Tmp, struct Map_info *Out, struct field_info *Fi, dbDriver * driver, int operator, int *ofield, ATTRIBUTES * attr, struct ilist *BList) { int line, nlines, ncat; struct line_pnts *Points; struct line_cats *Cats, *ACats, *OCats; char buf[1000]; dbString stmt; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); ACats = Vect_new_cats_struct(); OCats = Vect_new_cats_struct(); db_init_string(&stmt); G_message(_("Breaking lines...")); Vect_break_lines_list(Tmp, NULL, BList, GV_LINE | GV_BOUNDARY, NULL); /* G_message(_("Merging lines...")); Vect_merge_lines(Tmp, GV_LINE, NULL, NULL); */ nlines = Vect_get_num_lines(Tmp); /* Warning!: cleaning process (break) creates new vertices which are usually slightly * moved (RE), to compare such new vertex with original input is a problem? * * TODO?: would it be better to copy centroids also and query output map? */ /* Check if the line is inside or outside binput area */ G_message(_("Selecting lines...")); ncat = 1; for (line = 1; line <= nlines; line++) { int ltype; G_percent(line, nlines, 1); /* must be before any continue */ if (!Vect_line_alive(Tmp, line)) continue; ltype = Vect_get_line_type(Tmp, line); if (ltype == GV_BOUNDARY) { /* No more needed */ continue; } /* Now the type should be only GV_LINE */ /* Decide if the line is inside or outside the area. In theory: * 1) All vertices outside * - easy, first vertex must be outside * 2) All vertices inside * 3) All vertices on the boundary, we take it as inside (attention, * result of Vect_point_in_area() for points on segments between vertices may be both * inside or outside, because of representation of numbers) * 4) One or two end vertices on the boundary, all others outside * 5) One or two end vertices on the boundary, all others inside * */ /* Note/TODO: the test done is quite simple, check the point in the middle of segment. * If the line overlaps the boundary, the result may be both outside and inside * this should be solved (check angles?) * This should not happen if Vect_break_lines_list() works correctly */ /* merge here */ merge_line(Tmp, line, Points, Cats); G_debug(3, "line = %d", line); point_area(&(In[1]), field[1], (Points->x[0] + Points->x[1]) / 2, (Points->y[0] + Points->y[1]) / 2, ACats); if ((ACats->n_cats > 0 && operator == OP_AND) || (ACats->n_cats == 0 && operator == OP_NOT)) { int i; /* Point is inside */ G_debug(3, "OK, write line, line ncats = %d area ncats = %d", Cats->n_cats, ACats->n_cats); Vect_reset_cats(OCats); if (ofield[0] > 0) { /* rewrite with all combinations of acat - bcat (-1 in cycle for null) */ for (i = -1; i < Cats->n_cats; i++) { /* line cats */ int j; if (i == -1 && Cats->n_cats > 0) continue; /* no need to make null */ for (j = -1; j < ACats->n_cats; j++) { if (j == -1 && ACats->n_cats > 0) continue; /* no need to make null */ if (ofield[0] > 0) Vect_cat_set(OCats, ofield[0], ncat); /* Attributes */ if (driver) { ATTR *at; sprintf(buf, "insert into %s values ( %d", Fi->table, ncat); db_set_string(&stmt, buf); /* cata */ if (i >= 0) { if (attr[0].columns) { at = find_attr(&(attr[0]), Cats->cat[i]); if (!at) G_fatal_error(_("Attribute not found")); if (at->values) db_append_string(&stmt, at->values); else db_append_string(&stmt, attr[0].null_values); } else { sprintf(buf, ", %d", Cats->cat[i]); db_append_string(&stmt, buf); } } else { if (attr[0].columns) { db_append_string(&stmt, attr[0].null_values); } else { sprintf(buf, ", null"); db_append_string(&stmt, buf); } } /* catb */ if (j >= 0) { if (attr[1].columns) { at = find_attr(&(attr[1]), ACats->cat[j]); if (!at) G_fatal_error(_("Attribute not found")); if (at->values) db_append_string(&stmt, at->values); else db_append_string(&stmt, attr[1].null_values); } else { sprintf(buf, ", %d", ACats->cat[j]); db_append_string(&stmt, buf); } } else { if (attr[1].columns) { db_append_string(&stmt, attr[1].null_values); } else { sprintf(buf, ", null"); db_append_string(&stmt, buf); } } db_append_string(&stmt, " )"); G_debug(3, "%s", db_get_string(&stmt)); if (db_execute_immediate(driver, &stmt) != DB_OK) G_warning(_("Unable to insert new record: '%s'"), db_get_string(&stmt)); } ncat++; } } } /* Add cats from input vectors */ if (ofield[1] > 0 && field[0] > 0) { for (i = 0; i < Cats->n_cats; i++) { if (Cats->field[i] == field[0]) Vect_cat_set(OCats, ofield[1], Cats->cat[i]); } } if (ofield[2] > 0 && field[1] > 0 && ofield[1] != ofield[2]) { for (i = 0; i < ACats->n_cats; i++) { if (ACats->field[i] == field[1]) Vect_cat_set(OCats, ofield[2], ACats->cat[i]); } } Vect_write_line(Out, ltype, Points, OCats); } } return 0; }
/*! \brief Read next feature from OGR layer. Skip empty features (level 1) This function implements sequential access. The action of this routine can be modified by: - Vect_read_constraint_region() - Vect_read_constraint_type() - Vect_remove_constraints() \param Map pointer to Map_info structure \param[out] line_p container used to store line points within \param[out] line_c container used to store line categories within \return feature type \return -2 no more features (EOF) \return -1 out of memory */ int V1_read_next_line_ogr(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c) { int itype; struct bound_box lbox, mbox; OGRFeatureH hFeature; OGRGeometryH hGeom; G_debug(3, "V1_read_next_line_ogr()"); if (line_p != NULL) Vect_reset_line(line_p); if (line_c != NULL) Vect_reset_cats(line_c); if (Map->Constraint_region_flag) Vect_get_constraint_box(Map, &mbox); while (TRUE) { /* Read feature to cache if necessary */ while (Map->fInfo.ogr.lines_next == Map->fInfo.ogr.lines_num) { hFeature = OGR_L_GetNextFeature(Map->fInfo.ogr.layer); if (hFeature == NULL) { return -2; } /* no more features */ hGeom = OGR_F_GetGeometryRef(hFeature); if (hGeom == NULL) { /* feature without geometry */ OGR_F_Destroy(hFeature); continue; } Map->fInfo.ogr.feature_cache_id = (int)OGR_F_GetFID(hFeature); if (Map->fInfo.ogr.feature_cache_id == OGRNullFID) { G_warning(_("OGR feature without ID")); } /* Cache the feature */ Map->fInfo.ogr.lines_num = 0; cache_feature(Map, hGeom, -1); G_debug(4, "%d lines read to cache", Map->fInfo.ogr.lines_num); OGR_F_Destroy(hFeature); Map->fInfo.ogr.lines_next = 0; /* next to be read from cache */ } /* Read next part of the feature */ G_debug(4, "read next cached line %d", Map->fInfo.ogr.lines_next); itype = Map->fInfo.ogr.lines_types[Map->fInfo.ogr.lines_next]; /* Constraint on Type of line * Default is all of Point, Line, Area and whatever else comes along */ if (Map->Constraint_type_flag) { if (!(itype & Map->Constraint_type)) { Map->fInfo.ogr.lines_next++; continue; } } /* Constraint on specified region */ if (Map->Constraint_region_flag) { Vect_line_box(Map->fInfo.ogr.lines[Map->fInfo.ogr.lines_next], &lbox); if (!Vect_box_overlap(&lbox, &mbox)) { Map->fInfo.ogr.lines_next++; continue; } } if (line_p != NULL) Vect_append_points(line_p, Map->fInfo.ogr.lines[Map->fInfo.ogr. lines_next], GV_FORWARD); if (line_c != NULL && Map->fInfo.ogr.feature_cache_id != OGRNullFID) Vect_cat_set(line_c, 1, Map->fInfo.ogr.feature_cache_id); Map->fInfo.ogr.lines_next++; G_debug(4, "next line read, type = %d", itype); return itype; } return -2; /* not reached */ }
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 Map_info In, Out, Buf; struct line_pnts *Points; struct line_cats *Cats, *BCats; char bufname[GNAME_MAX]; struct GModule *module; struct Option *in_opt, *out_opt, *type_opt, *dista_opt, *distb_opt, *angle_opt; struct Flag *straight_flag, *nocaps_flag; struct Option *tol_opt, *bufcol_opt, *scale_opt, *field_opt; int verbose; double da, db, dalpha, tolerance, unit_tolerance; int type; int i, ret, nareas, area, nlines, line; char *Areas, *Lines; int field; struct buf_contours *arr_bc; struct buf_contours_pts arr_bc_pts; int buffers_count = 0, line_id; struct spatial_index si; struct bound_box bbox; /* Attributes if sizecol is used */ int nrec, ctype; struct field_info *Fi; dbDriver *Driver; dbCatValArray cvarr; double size_val, scale; module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("geometry")); G_add_keyword(_("buffer")); module->description = _("Creates a buffer around vector features of given type."); in_opt = G_define_standard_option(G_OPT_V_INPUT); field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL); field_opt->guisection = _("Selection"); type_opt = G_define_standard_option(G_OPT_V_TYPE); type_opt->options = "point,line,boundary,centroid,area"; type_opt->answer = "point,line,area"; type_opt->guisection = _("Selection"); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); dista_opt = G_define_option(); dista_opt->key = "distance"; dista_opt->type = TYPE_DOUBLE; dista_opt->required = NO; dista_opt->description = _("Buffer distance along major axis in map units"); dista_opt->guisection = _("Distance"); distb_opt = G_define_option(); distb_opt->key = "minordistance"; distb_opt->type = TYPE_DOUBLE; distb_opt->required = NO; distb_opt->description = _("Buffer distance along minor axis in map units"); distb_opt->guisection = _("Distance"); angle_opt = G_define_option(); angle_opt->key = "angle"; angle_opt->type = TYPE_DOUBLE; angle_opt->required = NO; angle_opt->answer = "0"; angle_opt->description = _("Angle of major axis in degrees"); angle_opt->guisection = _("Distance"); bufcol_opt = G_define_standard_option(G_OPT_DB_COLUMN); bufcol_opt->key = "bufcolumn"; bufcol_opt->description = _("Name of column to use for buffer distances"); bufcol_opt->guisection = _("Distance"); scale_opt = G_define_option(); scale_opt->key = "scale"; scale_opt->type = TYPE_DOUBLE; scale_opt->required = NO; scale_opt->answer = "1.0"; scale_opt->description = _("Scaling factor for attribute column values"); scale_opt->guisection = _("Distance"); tol_opt = G_define_option(); tol_opt->key = "tolerance"; tol_opt->type = TYPE_DOUBLE; tol_opt->required = NO; tol_opt->answer = "0.01"; tol_opt->description = _("Maximum distance between theoretical arc and polygon segments as multiple of buffer"); tol_opt->guisection = _("Distance"); straight_flag = G_define_flag(); straight_flag->key = 's'; straight_flag->description = _("Make outside corners straight"); nocaps_flag = G_define_flag(); nocaps_flag->key = 'c'; nocaps_flag->description = _("Don't make caps at the ends of polylines"); G_gisinit(argv[0]); if (G_parser(argc, argv)) exit(EXIT_FAILURE); type = Vect_option_to_types(type_opt); if ((dista_opt->answer && bufcol_opt->answer) || (!(dista_opt->answer || bufcol_opt->answer))) G_fatal_error(_("Select a buffer distance/minordistance/angle " "or column, but not both.")); if (bufcol_opt->answer) G_warning(_("The bufcol option may contain bugs during the cleaning " "step. If you encounter problems, use the debug " "option or clean manually with v.clean tool=break; " "v.category step=0; v.extract -d type=area")); if (field_opt->answer) field = Vect_get_field_number(&In, field_opt->answer); else field = -1; if (bufcol_opt->answer && field == -1) G_fatal_error(_("The bufcol option requires a valid layer.")); tolerance = atof(tol_opt->answer); if (tolerance <= 0) G_fatal_error(_("The tolerance must be > 0.")); if (adjust_tolerance(&tolerance)) G_warning(_("The tolerance was reset to %g"), tolerance); scale = atof(scale_opt->answer); if (scale <= 0.0) G_fatal_error("Illegal scale value"); da = db = dalpha = 0; if (dista_opt->answer) { da = atof(dista_opt->answer); if (distb_opt->answer) db = atof(distb_opt->answer); else db = da; if (angle_opt->answer) dalpha = atof(angle_opt->answer); else dalpha = 0; unit_tolerance = tolerance * MIN(da, db); G_verbose_message(_("The tolerance in map units = %g"), unit_tolerance); } Vect_check_input_output_name(in_opt->answer, out_opt->answer, GV_FATAL_EXIT); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); BCats = Vect_new_cats_struct(); Vect_set_open_level(2); /* topology required */ if (1 > Vect_open_old2(&In, in_opt->answer, "", field_opt->answer)) G_fatal_error(_("Unable to open vector map <%s>"), in_opt->answer); if (0 > Vect_open_new(&Out, out_opt->answer, WITHOUT_Z)) { Vect_close(&In); G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer); } /* open tmp vector for buffers, needed for cleaning */ sprintf(bufname, "%s_tmp_%d", out_opt->answer, getpid()); if (0 > Vect_open_new(&Buf, bufname, 0)) { Vect_close(&In); Vect_close(&Out); Vect_delete(out_opt->answer); exit(EXIT_FAILURE); } Vect_build_partial(&Buf, GV_BUILD_BASE); /* check and load attribute column data */ if (bufcol_opt->answer) { db_CatValArray_init(&cvarr); Fi = Vect_get_field(&In, field); if (Fi == NULL) G_fatal_error(_("Database connection not defined for layer %d"), 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); /* Note do not check if the column exists in the table because it may be expression */ /* TODO: only select values we need instead of all in column */ nrec = db_select_CatValArray(Driver, Fi->table, Fi->key, bufcol_opt->answer, NULL, &cvarr); if (nrec < 0) G_fatal_error(_("Unable to select data from table <%s>"), Fi->table); G_debug(2, "%d records selected from table", nrec); ctype = cvarr.ctype; if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE) G_fatal_error(_("Column type not supported")); db_close_database_shutdown_driver(Driver); /* Output cats/values list */ for (i = 0; i < cvarr.n_values; i++) { if (ctype == DB_C_TYPE_INT) { G_debug(4, "cat = %d val = %d", cvarr.value[i].cat, cvarr.value[i].val.i); } else if (ctype == DB_C_TYPE_DOUBLE) { G_debug(4, "cat = %d val = %f", cvarr.value[i].cat, cvarr.value[i].val.d); } } } Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); /* Create buffers' boundaries */ nlines = nareas = 0; if ((type & GV_POINTS) || (type & GV_LINES)) nlines += Vect_get_num_primitives(&In, type); if (type & GV_AREA) nareas = Vect_get_num_areas(&In); if (nlines + nareas == 0) { G_warning(_("No features available for buffering. " "Check type option and features available in the input vector.")); exit(EXIT_SUCCESS); } buffers_count = 1; arr_bc = G_malloc((nlines + nareas + 1) * sizeof(struct buf_contours)); Vect_spatial_index_init(&si, 0); /* Lines (and Points) */ if ((type & GV_POINTS) || (type & GV_LINES)) { int ltype; if (nlines > 0) G_message(_("Buffering lines...")); for (line = 1; line <= nlines; line++) { int cat; G_debug(2, "line = %d", line); G_percent(line, nlines, 2); if (!Vect_line_alive(&In, line)) continue; ltype = Vect_read_line(&In, Points, Cats, line); if (!(ltype & type)) continue; if (field > 0 && !Vect_cat_get(Cats, field, &cat)) continue; if (bufcol_opt->answer) { ret = db_CatValArray_get_value_di(&cvarr, cat, &size_val); if (ret != DB_OK) { G_warning(_("No record for category %d in table <%s>"), cat, Fi->table); continue; } if (size_val < 0.0) { G_warning(_("Attribute is of invalid size (%.3f) for category %d"), size_val, cat); continue; } if (size_val == 0.0) continue; da = size_val * scale; db = da; dalpha = 0; unit_tolerance = tolerance * MIN(da, db); G_debug(2, " dynamic buffer size = %.2f", da); G_debug(2, _("The tolerance in map units: %g"), unit_tolerance); } Vect_line_prune(Points); if (ltype & GV_POINTS || Points->n_points == 1) { Vect_point_buffer2(Points->x[0], Points->y[0], da, db, dalpha, !(straight_flag->answer), unit_tolerance, &(arr_bc_pts.oPoints)); Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats); line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, Cats); Vect_destroy_line_struct(arr_bc_pts.oPoints); /* add buffer to spatial index */ Vect_get_line_box(&Buf, line_id, &bbox); Vect_spatial_index_add_item(&si, buffers_count, &bbox); arr_bc[buffers_count].outer = line_id; arr_bc[buffers_count].inner_count = 0; arr_bc[buffers_count].inner = NULL; buffers_count++; } else { Vect_line_buffer2(Points, da, db, dalpha, !(straight_flag->answer), !(nocaps_flag->answer), unit_tolerance, &(arr_bc_pts.oPoints), &(arr_bc_pts.iPoints), &(arr_bc_pts.inner_count)); Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats); line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, Cats); Vect_destroy_line_struct(arr_bc_pts.oPoints); /* add buffer to spatial index */ Vect_get_line_box(&Buf, line_id, &bbox); Vect_spatial_index_add_item(&si, buffers_count, &bbox); arr_bc[buffers_count].outer = line_id; arr_bc[buffers_count].inner_count = arr_bc_pts.inner_count; if (arr_bc_pts.inner_count > 0) { arr_bc[buffers_count].inner = G_malloc(arr_bc_pts.inner_count * sizeof(int)); for (i = 0; i < arr_bc_pts.inner_count; i++) { Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.iPoints[i], BCats); line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.iPoints[i], Cats); Vect_destroy_line_struct(arr_bc_pts.iPoints[i]); /* add buffer to spatial index */ Vect_get_line_box(&Buf, line_id, &bbox); Vect_spatial_index_add_item(&si, buffers_count, &bbox); arr_bc[buffers_count].inner[i] = line_id; } G_free(arr_bc_pts.iPoints); } buffers_count++; } } } /* Areas */ if (type & GV_AREA) { int centroid; if (nareas > 0) G_message(_("Buffering areas...")); for (area = 1; area <= nareas; area++) { int cat; G_percent(area, nareas, 2); if (!Vect_area_alive(&In, area)) continue; centroid = Vect_get_area_centroid(&In, area); if (centroid == 0) continue; Vect_read_line(&In, NULL, Cats, centroid); if (field > 0 && !Vect_cat_get(Cats, field, &cat)) continue; if (bufcol_opt->answer) { ret = db_CatValArray_get_value_di(&cvarr, cat, &size_val); if (ret != DB_OK) { G_warning(_("No record for category %d in table <%s>"), cat, Fi->table); continue; } if (size_val < 0.0) { G_warning(_("Attribute is of invalid size (%.3f) for category %d"), size_val, cat); continue; } if (size_val == 0.0) continue; da = size_val * scale; db = da; dalpha = 0; unit_tolerance = tolerance * MIN(da, db); G_debug(2, " dynamic buffer size = %.2f", da); G_debug(2, _("The tolerance in map units: %g"), unit_tolerance); } Vect_area_buffer2(&In, area, da, db, dalpha, !(straight_flag->answer), !(nocaps_flag->answer), unit_tolerance, &(arr_bc_pts.oPoints), &(arr_bc_pts.iPoints), &(arr_bc_pts.inner_count)); Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.oPoints, BCats); line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.oPoints, Cats); Vect_destroy_line_struct(arr_bc_pts.oPoints); /* add buffer to spatial index */ Vect_get_line_box(&Buf, line_id, &bbox); Vect_spatial_index_add_item(&si, buffers_count, &bbox); arr_bc[buffers_count].outer = line_id; arr_bc[buffers_count].inner_count = arr_bc_pts.inner_count; if (arr_bc_pts.inner_count > 0) { arr_bc[buffers_count].inner = G_malloc(arr_bc_pts.inner_count * sizeof(int)); for (i = 0; i < arr_bc_pts.inner_count; i++) { Vect_write_line(&Out, GV_BOUNDARY, arr_bc_pts.iPoints[i], BCats); line_id = Vect_write_line(&Buf, GV_BOUNDARY, arr_bc_pts.iPoints[i], Cats); Vect_destroy_line_struct(arr_bc_pts.iPoints[i]); /* add buffer to spatial index */ Vect_get_line_box(&Buf, line_id, &bbox); Vect_spatial_index_add_item(&si, buffers_count, &bbox); arr_bc[buffers_count].inner[i] = line_id; } G_free(arr_bc_pts.iPoints); } buffers_count++; } } verbose = G_verbose(); G_message(_("Cleaning buffers...")); /* Break lines */ G_message(_("Building parts of topology...")); Vect_build_partial(&Out, GV_BUILD_BASE); G_message(_("Snapping boundaries...")); Vect_snap_lines(&Out, GV_BOUNDARY, 1e-7, NULL); G_message(_("Breaking polygons...")); Vect_break_polygons(&Out, GV_BOUNDARY, NULL); G_message(_("Removing duplicates...")); Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL); do { G_message(_("Breaking boundaries...")); Vect_break_lines(&Out, GV_BOUNDARY, NULL); G_message(_("Removing duplicates...")); Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL); G_message(_("Cleaning boundaries at nodes")); } while (Vect_clean_small_angles_at_nodes(&Out, GV_BOUNDARY, NULL) > 0); /* Dangles and bridges don't seem to be necessary if snapping is small enough. */ /* Still needed for larger buffer distances ? */ /* G_message(_("Removing dangles...")); Vect_remove_dangles(&Out, GV_BOUNDARY, -1, NULL); G_message (_("Removing bridges...")); Vect_remove_bridges(&Out, NULL); */ G_message(_("Attaching islands...")); Vect_build_partial(&Out, GV_BUILD_ATTACH_ISLES); /* Calculate new centroids for all areas */ nareas = Vect_get_num_areas(&Out); Areas = (char *)G_calloc(nareas + 1, sizeof(char)); G_message(_("Calculating centroids for areas...")); G_percent(0, nareas, 2); for (area = 1; area <= nareas; area++) { double x, y; G_percent(area, nareas, 2); G_debug(3, "area = %d", area); if (!Vect_area_alive(&Out, area)) continue; ret = Vect_get_point_in_area(&Out, area, &x, &y); if (ret < 0) { G_warning(_("Cannot calculate area centroid")); continue; } ret = point_in_buffer(arr_bc, &si, &Buf, x, y); if (ret) { G_debug(3, " -> in buffer"); Areas[area] = 1; } } /* Make a list of boundaries to be deleted (both sides inside) */ nlines = Vect_get_num_lines(&Out); G_debug(3, "nlines = %d", nlines); Lines = (char *)G_calloc(nlines + 1, sizeof(char)); G_message(_("Generating list of boundaries to be deleted...")); for (line = 1; line <= nlines; line++) { int j, side[2], areas[2]; G_percent(line, nlines, 2); G_debug(3, "line = %d", line); if (!Vect_line_alive(&Out, line)) continue; Vect_get_line_areas(&Out, line, &side[0], &side[1]); for (j = 0; j < 2; j++) { if (side[j] == 0) { /* area/isle not build */ areas[j] = 0; } else if (side[j] > 0) { /* area */ areas[j] = side[j]; } else { /* < 0 -> island */ areas[j] = Vect_get_isle_area(&Out, abs(side[j])); } } G_debug(3, " areas = %d , %d -> Areas = %d, %d", areas[0], areas[1], Areas[areas[0]], Areas[areas[1]]); if (Areas[areas[0]] && Areas[areas[1]]) Lines[line] = 1; } G_free(Areas); /* Delete boundaries */ G_message(_("Deleting boundaries...")); for (line = 1; line <= nlines; line++) { G_percent(line, nlines, 2); if (!Vect_line_alive(&Out, line)) continue; if (Lines[line]) { G_debug(3, " delete line %d", line); Vect_delete_line(&Out, line); } else { /* delete incorrect boundaries */ int side[2]; Vect_get_line_areas(&Out, line, &side[0], &side[1]); if (!side[0] && !side[1]) Vect_delete_line(&Out, line); } } G_free(Lines); /* Create new centroids */ Vect_reset_cats(Cats); Vect_cat_set(Cats, 1, 1); nareas = Vect_get_num_areas(&Out); G_message(_("Calculating centroids for areas...")); for (area = 1; area <= nareas; area++) { double x, y; G_percent(area, nareas, 2); G_debug(3, "area = %d", area); if (!Vect_area_alive(&Out, area)) continue; ret = Vect_get_point_in_area(&Out, area, &x, &y); if (ret < 0) { G_warning(_("Cannot calculate area centroid")); continue; } ret = point_in_buffer(arr_bc, &si, &Buf, x, y); if (ret) { Vect_reset_line(Points); Vect_append_point(Points, x, y, 0.); Vect_write_line(&Out, GV_CENTROID, Points, Cats); } } /* free arr_bc[] */ /* will only slow down the module for (i = 0; i < buffers_count; i++) { Vect_destroy_line_struct(arr_bc[i].oPoints); for (j = 0; j < arr_bc[i].inner_count; j++) Vect_destroy_line_struct(arr_bc[i].iPoints[j]); G_free(arr_bc[i].iPoints); } */ Vect_spatial_index_destroy(&si); Vect_close(&Buf); Vect_delete(bufname); G_set_verbose(verbose); Vect_close(&In); Vect_build_partial(&Out, GV_BUILD_NONE); Vect_build(&Out); Vect_close(&Out); exit(EXIT_SUCCESS); }
/*------------------------------------------------------------------------------------------------*/ void P_Aux_to_Vector(struct Map_info *Map, struct Map_info *Out, dbDriver * driver, char *tab_name) { int more, line_num, type, count = 0; double coordX, coordY, coordZ; struct line_pnts *point; struct line_cats *cat; dbTable *table; dbColumn *column; dbValue *value; dbCursor cursor; dbString sql; char buf[1024]; point = Vect_new_line_struct(); cat = Vect_new_cats_struct(); db_init_string(&sql); db_zero_string(&sql); sprintf(buf, "select ID, X, Y, sum(Interp) from %s group by ID, X, Y", tab_name); db_append_string(&sql, buf); db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL); while (db_fetch(&cursor, DB_NEXT, &more) == DB_OK && more) { count++; table = db_get_cursor_table(&cursor); column = db_get_table_column(table, 0); type = db_sqltype_to_Ctype(db_get_column_sqltype(column)); if (type == DB_C_TYPE_INT) value = db_get_column_value(column); else continue; line_num = db_get_value_int(value); column = db_get_table_column(table, 1); type = db_sqltype_to_Ctype(db_get_column_sqltype(column)); if (type == DB_C_TYPE_DOUBLE) value = db_get_column_value(column); else continue; coordZ = db_get_value_double(value); column = db_get_table_column(table, 2); type = db_sqltype_to_Ctype(db_get_column_sqltype(column)); if (type == DB_C_TYPE_DOUBLE) value = db_get_column_value(column); else continue; coordX = db_get_value_double(value); column = db_get_table_column(table, 3); type = db_sqltype_to_Ctype(db_get_column_sqltype(column)); if (type == DB_C_TYPE_DOUBLE) value = db_get_column_value(column); else continue; coordY = db_get_value_double(value); Vect_copy_xyz_to_pnts(point, &coordX, &coordY, &coordZ, 1); Vect_reset_cats(cat); Vect_cat_set(cat, 1, 1); Vect_write_line(Out, GV_POINT, point, cat); } return; }
/* write_area - make table of area equivalences and write attribute file */ int write_area(struct area_table *a_list, /* list of areas */ struct equiv_table *e_list, /* list of equivalences between areas */ int n_areas, /* lengths of e_list, a_list */ int n_equiv) { struct line_pnts *points = Vect_new_line_struct(); int n, i; struct area_table *p; char *temp_buf; int cat; int catNum; double x, y; total_areas = 0; if (n_equiv < n_areas) { equivs = (int *)G_malloc(n_areas * sizeof(int)); n = n_equiv; } else { equivs = (int *)G_malloc(n_equiv * sizeof(int)); n = n_areas; } for (i = 0; i < n; i++) { if ((e_list + i)->mapped) equivs[i] = (e_list + i)->where; else { total_areas++; equivs[i] = i; } } if (n < n_areas) { for (i = n; i < n_areas; i++) { total_areas++; equivs[i] = i; } } catNum = 1; G_important_message(_("Writing areas...")); for (i = 0, p = a_list; i < n_areas; i++, p++) { G_percent(i, n_areas, 3); if (equivs[i] == i && p->width > 0 && !Rast_is_d_null_value(&(p->cat))) { char buf[1000]; if (value_flag) { /* raster value */ cat = (int)p->cat; } else { /* sequence */ cat = catNum; catNum++; } x = cell_head.west + (p->col + (p->width / 2.0)) * cell_head.ew_res; y = cell_head.north - (p->row + 0.5) * cell_head.ns_res; switch (data_type) { case CELL_TYPE: G_debug(3, "vector x = %.3f, y = %.3f, cat = %d; raster cat = %d", x, y, cat, (int)p->cat); break; case FCELL_TYPE: G_debug(3, "vector x = %.3f, y = %.3f, cat = %d; raster cat = %f", x, y, cat, (float)p->cat); break; case DCELL_TYPE: G_debug(3, "vector x = %.3f, y = %.3f, cat = %d; raster cat = %lf", x, y, cat, p->cat); break; } Vect_reset_line(points); Vect_append_point(points, x, y, 0.0); Vect_reset_cats(Cats); Vect_cat_set(Cats, 1, cat); Vect_write_line(&Map, GV_CENTROID, points, Cats); if (driver != NULL && !value_flag) { sprintf(buf, "insert into %s values (%d, ", Fi->table, cat); db_set_string(&sql, buf); switch (data_type) { case CELL_TYPE: sprintf(buf, "%d", (int)p->cat); break; case FCELL_TYPE: case DCELL_TYPE: sprintf(buf, "%f", p->cat); break; } db_append_string(&sql, buf); if (has_cats) { temp_buf = Rast_get_d_cat(&p->cat, &RastCats); db_set_string(&label, temp_buf); db_double_quote_string(&label); sprintf(buf, ", '%s'", db_get_string(&label)); db_append_string(&sql, buf); } db_append_string(&sql, ")"); G_debug(3, "%s", db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) G_fatal_error(_("Cannot insert new row: %s"), db_get_string(&sql)); } } } G_percent(1, 1, 1); return 0; }
int main(int argc, char *argv[]) { struct Map_info In, Out; static struct line_pnts *Points; struct line_cats *Cats; struct field_info *Fi; struct cat_list *Clist; int i, j, ret, option, otype, type, with_z, step, id; int n_areas, centr, new_centr, nmodified; int open_level; double x, y; int cat, ocat, scat, *fields, nfields, field; struct GModule *module; struct Option *in_opt, *out_opt, *option_opt, *type_opt; struct Option *cat_opt, *field_opt, *step_opt, *id_opt; struct Flag *shell, *notab; FREPORT **freps; int nfreps, rtype, fld; char *desc; module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("category")); G_add_keyword(_("layer")); module->description = _("Attaches, deletes or reports vector categories to map geometry."); in_opt = G_define_standard_option(G_OPT_V_INPUT); field_opt = G_define_standard_option(G_OPT_V_FIELD); field_opt->multiple = YES; field_opt->guisection = _("Selection"); type_opt = G_define_standard_option(G_OPT_V3_TYPE); type_opt->answer = "point,line,centroid,face"; type_opt->guisection = _("Selection"); id_opt = G_define_standard_option(G_OPT_V_IDS); id_opt->label = _("Feature ids (by default all features are processed)"); id_opt->guisection = _("Selection"); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); out_opt->required = NO; option_opt = G_define_option(); option_opt->key = "option"; option_opt->type = TYPE_STRING; option_opt->required = YES; option_opt->multiple = NO; option_opt->options = "add,del,chlayer,sum,report,print,layers,transfer"; option_opt->description = _("Action to be done"); desc = NULL; G_asprintf(&desc, "add;%s;" "del;%s;" "chlayer;%s;" "sum;%s;" "transfer;%s;" "report;%s;" "print;%s;" "layers;%s", _("add a category to features without category in the given layer"), _("delete category (cat=-1 to delete all categories of given layer)"), _("change layer number (e.g. layer=3,1 changes layer 3 to layer 1)"), _("add the value specified by cat option to the current category value"), _("copy values from one layer to another (e.g. layer=1,2,3 copies values from layer 1 to layer 2 and 3)"), _("print report (statistics), in shell style: layer type count min max"), _("print category values, layers are separated by '|', more cats in the same layer are separated by '/'"), _("print only layer numbers")); option_opt->descriptions = desc; cat_opt = G_define_standard_option(G_OPT_V_CAT); cat_opt->answer = "1"; step_opt = G_define_option(); step_opt->key = "step"; step_opt->type = TYPE_INTEGER; step_opt->required = NO; step_opt->multiple = NO; step_opt->answer = "1"; step_opt->description = _("Category increment"); shell = G_define_flag(); shell->key = 'g'; shell->label = _("Shell script style, currently only for report"); shell->description = _("Format: layer type count min max"); notab = G_define_standard_flag(G_FLG_V_TABLE); notab->description = _("Do not copy attribute table(s)"); G_gisinit(argv[0]); if (G_parser(argc, argv)) exit(EXIT_FAILURE); /* read options */ option = 0; switch (option_opt->answer[0]) { case ('a'): option = O_ADD; break; case ('d'): option = O_DEL; break; case ('c'): option = O_CHFIELD; G_warning(_("Database connection and attribute tables for concerned layers are not changed")); break; case ('s'): option = O_SUM; break; case ('t'): option = O_TRANS; break; case ('r'): option = O_REP; break; case ('p'): option = O_PRN; break; case ('l'): option = O_LYR; break; } if (option == O_LYR) { /* print vector layer numbers */ /* open vector on level 2 head only, this is why this option * is processed here, all other options need (?) to fully open * the input vector */ Vect_set_open_level(2); if (Vect_open_old_head2(&In, in_opt->answer, "", field_opt->answer) < 2) { G_fatal_error(_("Unable to open vector map <%s> at topological level %d"), Vect_get_full_name(&In), 2); } if (In.format == GV_FORMAT_NATIVE) { nfields = Vect_cidx_get_num_fields(&In); for (i = 0; i < nfields; i++) { if ((field = Vect_cidx_get_field_number(&In, i)) > 0) fprintf(stdout, "%d\n", field); } } else fprintf(stdout, "%s\n", field_opt->answer); Vect_close(&In); exit(EXIT_SUCCESS); } cat = atoi(cat_opt->answer); step = atoi(step_opt->answer); otype = Vect_option_to_types(type_opt); if (cat < 0 && option == O_ADD) G_fatal_error(_("Invalid category number (must be equal to or greater than 0). " "Normally category number starts at 1.")); /* collect ids */ if (id_opt->answer) { Clist = Vect_new_cat_list(); Clist->field = atoi(field_opt->answer); ret = Vect_str_to_cat_list(id_opt->answer, Clist); if (ret > 0) { G_warning(n_("%d error in id option", "%d errors in id option", ret), ret); } } else { Clist = NULL; } if ((option != O_REP) && (option != O_PRN) && (option != O_LYR)) { if (out_opt->answer == NULL) G_fatal_error(_("Output vector wasn't entered")); Vect_check_input_output_name(in_opt->answer, out_opt->answer, G_FATAL_EXIT); } Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); /* do we need topology ? */ if ((option == O_ADD && (otype & GV_AREA)) || (option == O_REP && (otype & GV_AREA)) || (option == O_TRANS) || /* topo for cidx check */ (option == O_LYR)) /* topo for cidx check */ open_level = 2; else open_level = 1; /* open input vector */ if (open_level > 1) { Vect_set_open_level(open_level); if (Vect_open_old2(&In, in_opt->answer, "", field_opt->answer) < open_level) { G_warning(_("Unable to open vector map <%s> at topological level %d"), Vect_get_full_name(&In), open_level); open_level = 1; } } if (open_level == 1) { Vect_set_open_level(open_level); if (Vect_open_old2(&In, in_opt->answer, "", field_opt->answer) < open_level) { G_fatal_error(_("Unable to open vector map <%s> at topological level %d"), Vect_get_full_name(&In), open_level); } } /* read fields */ i = nfields = 0; while (field_opt->answers[i++]) nfields++; fields = (int *)G_malloc(nfields * sizeof(int)); i = 0; while (field_opt->answers[i]) { fields[i] = Vect_get_field_number(&In, field_opt->answers[i]); i++; } if (nfields > 1 && option != O_PRN && option != O_CHFIELD && option != O_TRANS) G_fatal_error(_("Too many layers for this operation")); if (nfields != 2 && option == O_CHFIELD) G_fatal_error(_("2 layers must be specified")); if (option == O_TRANS && open_level == 1 && nfields < 2) { G_fatal_error(_("2 layers must be specified")); } if (option == O_TRANS && open_level > 1) { /* check if field[>0] already exists */ if (nfields > 1) { for(i = 1; i < nfields; i++) { if (Vect_cidx_get_field_index(&In, fields[i]) != -1) G_warning(_("Categories already exist in layer %d"), fields[i]); } } /* find next free layer number */ else if (nfields == 1) { int max = -1; for (i = 0; i < Vect_cidx_get_num_fields(&In); i++) { if (max < Vect_cidx_get_field_number(&In, i)) max = Vect_cidx_get_field_number(&In, i); } max++; nfields++; fields = (int *)G_realloc(fields, nfields * sizeof(int)); fields[nfields - 1] = max; } } if (otype & GV_AREA && option == O_TRANS && !(otype & GV_CENTROID)) otype |= GV_CENTROID; /* open output vector if needed */ if (option == O_ADD || option == O_DEL || option == O_CHFIELD || option == O_SUM || option == O_TRANS) { with_z = Vect_is_3d(&In); if (0 > Vect_open_new(&Out, out_opt->answer, with_z)) { Vect_close(&In); exit(EXIT_FAILURE); } Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); } id = 0; nmodified = 0; if (option == O_ADD || option == O_DEL || option == O_CHFIELD || option == O_SUM || option == O_TRANS) { G_message(_("Processing features...")); } switch (option) { case (O_ADD): /* Lines */ while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) { id++; if (type & otype && (!Clist || (Clist && Vect_cat_in_cat_list(id, Clist) == TRUE))) { if ((Vect_cat_get(Cats, fields[0], &ocat)) == 0) { if (ocat < 0) { if (Vect_cat_set(Cats, fields[0], cat) > 0) { nmodified++; } cat += step; } } } Vect_write_line(&Out, type, Points, Cats); } /* Areas */ if ((otype & GV_AREA) && open_level > 1) { n_areas = Vect_get_num_areas(&In); new_centr = 0; for (i = 1; i <= n_areas; i++) { centr = Vect_get_area_centroid(&In, i); if (centr > 0) continue; /* Centroid exists and may be processed as line */ ret = Vect_get_point_in_area(&In, i, &x, &y); if (ret < 0) { G_warning(_("Unable to calculate area centroid")); continue; } Vect_reset_line(Points); Vect_reset_cats(Cats); Vect_append_point(Points, x, y, 0.0); if (Vect_cat_set(Cats, fields[0], cat) > 0) { nmodified++; } cat += step; Vect_write_line(&Out, GV_CENTROID, Points, Cats); new_centr++; } if (new_centr > 0) G_message(n_("%d new centroid placed in output map", "%d new centroids placed in output map", new_centr), new_centr); } break; case (O_TRANS): /* Lines */ while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) { id++; if (type & otype && (!Clist || (Clist && Vect_cat_in_cat_list(id, Clist) == TRUE))) { int n = Cats->n_cats; scat = -1; for (i = 0; i < n; i++) { if (Cats->field[i] == fields[0]) { scat = Cats->cat[i]; for (j = 1; j < nfields; j++) { if (Vect_cat_set(Cats, fields[j], scat) > 0) { G_debug(4, "Copy cat %i of field %i to field %i", scat, fields[0], fields[j]); } } } } if (scat != -1) nmodified++; } Vect_write_line(&Out, type, Points, Cats); } break; case (O_DEL): while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) { id++; if (type & otype && (!Clist || (Clist && Vect_cat_in_cat_list(id, Clist) == TRUE))) { ret = Vect_field_cat_del(Cats, fields[0], cat); if (ret > 0) { nmodified++; } } Vect_write_line(&Out, type, Points, Cats); } break; case (O_CHFIELD): while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) { id++; if (type & otype && (!Clist || (Clist && Vect_cat_in_cat_list(id, Clist) == TRUE))) { i = 0; while (i < Cats->n_cats) { if (Cats->field[i] == fields[0]) { int found = -1; /* check if cat already exists in layer fields[1] */ for (j = 0; j < Cats->n_cats; j++) { if (Cats->field[j] == fields[1] && Cats->cat[j] == Cats->cat[i]) { found = j; break; } } /* does not exist, change layer */ if (found < 0) { Cats->field[i] = fields[1]; i++; } /* exists already in fields[1], delete from fields[0] */ else Vect_field_cat_del(Cats, fields[0], Cats->cat[found]); nmodified++; } } } Vect_write_line(&Out, type, Points, Cats); } break; case (O_SUM): while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) { id++; if (type & otype && (!Clist || (Clist && Vect_cat_in_cat_list(id, Clist) == TRUE))) { for (i = 0; i < Cats->n_cats; i++) { if (Cats->field[i] == fields[0]) { Cats->cat[i] += cat; } } nmodified++; } Vect_write_line(&Out, type, Points, Cats); } break; case (O_REP): nfreps = 0; freps = NULL; while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) { id++; if (Clist && Vect_cat_in_cat_list(id, Clist) == FALSE) continue; switch (type) { case (GV_POINT): rtype = FR_POINT; break; case (GV_LINE): rtype = FR_LINE; break; case (GV_BOUNDARY): rtype = FR_BOUNDARY; break; case (GV_CENTROID): rtype = FR_CENTROID; break; case (GV_FACE): rtype = FR_FACE; break; case (GV_KERNEL): rtype = FR_KERNEL; break; default: rtype = FR_UNKNOWN; } for (i = 0; i < Cats->n_cats; i++) { field = Cats->field[i]; cat = Cats->cat[i]; ret = FALSE; for (j = 0; j < nfreps; j++) { if (freps[j]->field == field) { fld = j; ret = TRUE; break; } } if (!ret) { /* field report doesn't exist */ nfreps++; freps = (FREPORT **) G_realloc(freps, nfreps * sizeof(FREPORT *)); fld = nfreps - 1; freps[fld] = (FREPORT *) G_calloc(1, sizeof(FREPORT)); freps[fld]->field = field; for (j = 0; j < FRTYPES; j++) { /* cat '0' is valid category number */ freps[fld]->min[j] = -1; } if ((Fi = Vect_get_field(&In, field)) != NULL) { freps[fld]->table = G_store(Fi->table); } else { freps[fld]->table = '\0'; } } freps[fld]->count[rtype]++; freps[fld]->count[FR_ALL]++; if (freps[fld]->min[rtype] == -1 || freps[fld]->min[rtype] > cat) freps[fld]->min[rtype] = cat; if ((freps[fld]->max[rtype] == 0) || freps[fld]->max[rtype] < cat) freps[fld]->max[rtype] = cat; if (freps[fld]->min[FR_ALL] == -1 || freps[fld]->min[FR_ALL] > cat) freps[fld]->min[FR_ALL] = cat; if ((freps[fld]->max[FR_ALL] == 0) || freps[fld]->max[FR_ALL] < cat) freps[fld]->max[FR_ALL] = cat; } } /* Areas */ if ((otype & GV_AREA) && open_level > 1 && !Clist) { n_areas = Vect_get_num_areas(&In); for (i = 1; i <= n_areas; i++) { int k; centr = Vect_get_area_centroid(&In, i); if (centr <= 0) continue; /* Area without centroid */ Vect_read_line(&In, NULL, Cats, centr); for (j = 0; j < Cats->n_cats; j++) { field = Cats->field[j]; cat = Cats->cat[j]; ret = FALSE; for (k = 0; k < nfreps; k++) { if (freps[k]->field == field) { fld = k; ret = TRUE; break; } } if (!ret) { /* field report doesn't exist */ nfreps++; freps = (FREPORT **) G_realloc(freps, nfreps * sizeof(FREPORT *)); fld = nfreps - 1; freps[fld] = (FREPORT *) G_calloc(1, sizeof(FREPORT)); freps[fld]->field = field; for (j = 0; j < FRTYPES; j++) { /* cat '0' is valid category number */ freps[fld]->min[k] = -1; } if ((Fi = Vect_get_field(&In, field)) != NULL) { freps[fld]->table = G_store(Fi->table); } else { freps[fld]->table = '\0'; } } freps[fld]->count[FR_AREA]++; if (freps[fld]->min[FR_AREA] == -1 || freps[fld]->min[FR_AREA] > cat) freps[fld]->min[FR_AREA] = cat; if ((freps[fld]->max[FR_AREA] == 0) || freps[fld]->max[FR_AREA] < cat) freps[fld]->max[FR_AREA] = cat; } } } for (i = 0; i < nfreps; i++) { if (shell->answer) { if (freps[i]->count[FR_POINT] > 0) fprintf(stdout, "%d point %d %d %d\n", freps[i]->field, freps[i]->count[FR_POINT], (freps[i]->min[FR_POINT] < 0 ? 0 : freps[i]->min[FR_POINT]), freps[i]->max[FR_POINT]); if (freps[i]->count[FR_LINE] > 0) fprintf(stdout, "%d line %d %d %d\n", freps[i]->field, freps[i]->count[FR_LINE], (freps[i]->min[FR_LINE] < 0 ? 0 : freps[i]->min[FR_LINE]), freps[i]->max[FR_LINE]); if (freps[i]->count[FR_BOUNDARY] > 0) fprintf(stdout, "%d boundary %d %d %d\n", freps[i]->field, freps[i]->count[FR_BOUNDARY], (freps[i]->min[FR_BOUNDARY] < 0 ? 0 : freps[i]->min[FR_BOUNDARY]), freps[i]->max[FR_BOUNDARY]); if (freps[i]->count[FR_CENTROID] > 0) fprintf(stdout, "%d centroid %d %d %d\n", freps[i]->field, freps[i]->count[FR_CENTROID], (freps[i]->min[FR_BOUNDARY] < 0 ? 0 : freps[i]->min[FR_BOUNDARY]), freps[i]->max[FR_CENTROID]); if (freps[i]->count[FR_AREA] > 0) fprintf(stdout, "%d area %d %d %d\n", freps[i]->field, freps[i]->count[FR_AREA], (freps[i]->min[FR_AREA] < 0 ? 0 : freps[i]->min[FR_AREA]), freps[i]->max[FR_AREA]); if (freps[i]->count[FR_FACE] > 0) fprintf(stdout, "%d face %d %d %d\n", freps[i]->field, freps[i]->count[FR_FACE], (freps[i]->min[FR_FACE] < 0 ? 0 : freps[i]->min[FR_FACE]), freps[i]->max[FR_FACE]); if (freps[i]->count[FR_KERNEL] > 0) fprintf(stdout, "%d kernel %d %d %d\n", freps[i]->field, freps[i]->count[FR_KERNEL], (freps[i]->min[FR_KERNEL] < 0 ? 0 : freps[i]->min[FR_KERNEL]), freps[i]->max[FR_KERNEL]); if (freps[i]->count[FR_ALL] > 0) fprintf(stdout, "%d all %d %d %d\n", freps[i]->field, freps[i]->count[FR_ALL], (freps[i]->min[FR_ALL] < 0 ? 0 : freps[i]->min[FR_ALL]), freps[i]->max[FR_ALL]); } else { if (freps[i]->table != '\0') { fprintf(stdout, "%s: %d/%s\n", _("Layer/table"), freps[i]->field, freps[i]->table); } else { fprintf(stdout, "%s: %d\n", _("Layer"), freps[i]->field); } fprintf(stdout, _("type count min max\n")); fprintf(stdout, "%s %7d %10d %10d\n", _("point"), freps[i]->count[FR_POINT], (freps[i]->min[FR_POINT] < 0) ? 0 : freps[i]->min[FR_POINT], freps[i]->max[FR_POINT]); fprintf(stdout, "%s %7d %10d %10d\n", _("line"), freps[i]->count[FR_LINE], (freps[i]->min[FR_LINE] < 0) ? 0 : freps[i]->min[FR_LINE], freps[i]->max[FR_LINE]); fprintf(stdout, "%s %7d %10d %10d\n", _("boundary"), freps[i]->count[FR_BOUNDARY], (freps[i]->min[FR_BOUNDARY] < 0) ? 0 : freps[i]->min[FR_BOUNDARY], freps[i]->max[FR_BOUNDARY]); fprintf(stdout, "%s %7d %10d %10d\n", _("centroid"), freps[i]->count[FR_CENTROID], (freps[i]->min[FR_CENTROID] < 0) ? 0 : freps[i]->min[FR_CENTROID], freps[i]->max[FR_CENTROID]); fprintf(stdout, "%s %7d %10d %10d\n", _("area"), freps[i]->count[FR_AREA], (freps[i]->min[FR_AREA] < 0) ? 0 : freps[i]->min[FR_AREA], freps[i]->max[FR_AREA]); fprintf(stdout, "%s %7d %10d %10d\n", _("face"), freps[i]->count[FR_FACE], (freps[i]->min[FR_FACE] < 0) ? 0 : freps[i]->min[FR_FACE], freps[i]->max[FR_FACE]); fprintf(stdout, "%s %7d %10d %10d\n", _("kernel"), freps[i]->count[FR_KERNEL], (freps[i]->min[FR_KERNEL] < 0) ? 0 : freps[i]->min[FR_KERNEL], freps[i]->max[FR_KERNEL]); fprintf(stdout, "%s %7d %10d %10d\n", _("all"), freps[i]->count[FR_ALL], (freps[i]->min[FR_ALL] < 0) ? 0 : freps[i]->min[FR_ALL], freps[i]->max[FR_ALL]); } } break; case (O_PRN): while ((type = Vect_read_next_line(&In, Points, Cats)) > 0) { id++; int has = 0; if (!(type & otype)) continue; if (Clist && Vect_cat_in_cat_list(id, Clist) == FALSE) continue; /* Check if the line has at least one cat */ for (i = 0; i < nfields; i++) { for (j = 0; j < Cats->n_cats; j++) { if (Cats->field[j] == fields[i]) { has = 1; break; } } } if (!has) continue; for (i = 0; i < nfields; i++) { int first = 1; if (i > 0) fprintf(stdout, "|"); for (j = 0; j < Cats->n_cats; j++) { if (Cats->field[j] == fields[i]) { if (!first) fprintf(stdout, "/"); fprintf(stdout, "%d", Cats->cat[j]); first = 0; } } } fprintf(stdout, "\n"); } break; } if (option == O_ADD || option == O_DEL || option == O_CHFIELD || option == O_SUM || option == O_TRANS){ if (!notab->answer){ G_message(_("Copying attribute table(s)...")); if (Vect_copy_tables(&In, &Out, 0)) G_warning(_("Failed to copy attribute table to output map")); } Vect_build(&Out); Vect_close(&Out); } if (option == O_TRANS && nmodified > 0) for(i = 1; i < nfields; i++) G_important_message(_("Categories copied from layer %d to layer %d"), fields[0], fields[i]); if (option != O_REP && option != O_PRN) G_done_msg(n_("%d feature modified.", "%d features modified.", nmodified), nmodified); Vect_close(&In); exit(EXIT_SUCCESS); }
int write_line(PAD_ENT_HDR adenhd, int type, int level) { int i, l; double x, y, z, r, ang; adSeekLayer(dwghandle, adenhd->entlayerobjhandle, Layer); /* Transformation, go up through all levels of transformation */ /* not sure what is the right order of transformation */ for (l = level; l >= 0; l--) { for (i = 0; i < Points->n_points; i++) { /* scale */ x = Points->x[i] * Trans[l].xscale; y = Points->y[i] * Trans[l].yscale; z = Points->z[i] * Trans[l].zscale; /* rotate */ r = sqrt(x * x + y * y); ang = atan2(y, x) + Trans[l].rotang; x = r * cos(ang); y = r * sin(ang); /* move */ x += Trans[l].dx; y += Trans[l].dy; z += Trans[l].dz; Points->x[i] = x; Points->y[i] = y; Points->z[i] = z; } } Vect_reset_cats(Cats); Vect_cat_set(Cats, 1, cat); Vect_write_line(&Map, type, Points, Cats); /* Cat */ sprintf(buf, "insert into %s values ( %d", Fi->table, cat); db_set_string(&sql, buf); /* Entity name */ getEntTypeName(adenhd, buf2); sprintf(buf, ", '%s'", buf2); db_append_string(&sql, buf); /* Color */ sprintf(buf, ", %d", adenhd->entcolor); db_append_string(&sql, buf); /* Weight */ sprintf(buf, ", %d", adenhd->lineweight); db_append_string(&sql, buf); /* Layer name */ if (!Layer->purgedflag && Layer->name != NULL) { db_set_string(&str, Layer->name); db_double_quote_string(&str); sprintf(buf, ", '%s'", db_get_string(&str)); } else { sprintf(buf, ", ''"); } db_append_string(&sql, buf); /* Block name */ if (Block != NULL) { db_set_string(&str, Block); db_double_quote_string(&str); } else { db_set_string(&str, ""); } sprintf(buf, ", '%s'", db_get_string(&str)); db_append_string(&sql, buf); /* Text */ if (Txt != NULL) { db_set_string(&str, Txt); db_double_quote_string(&str); } else { db_set_string(&str, ""); } sprintf(buf, ", '%s'", db_get_string(&str)); 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)); } cat++; return 0; }
/* merge a given line with all other lines of the same type and * with the same categories */ static int merge_line(struct Map_info *Map, int line, struct line_pnts *MPoints, struct line_cats *MCats) { int nlines, i, first, last, next_line, curr_line; int merged = 0, newl = 0; int next_node, direction, node_n_lines, type, ltype, lines_type; static struct ilist *List = NULL; static struct line_pnts *Points = NULL; static struct line_cats *Cats = NULL; type = GV_LINE; nlines = Vect_get_num_lines(Map); if (!Points) Points = Vect_new_line_struct(); if (!Cats) Cats = Vect_new_cats_struct(); if (!List) List = Vect_new_list(); Vect_reset_line(Points); Vect_reset_cats(Cats); Vect_reset_cats(MCats); Vect_reset_list(List); if (!Vect_line_alive(Map, line)) return 0; ltype = Vect_get_line_type(Map, line); if (!(ltype & type)) return 0; Vect_read_line(Map, MPoints, MCats, line); /* special cases: * - loop back to start boundary via several other boundaries * - one boundary forming closed loop * - node with 3 entries but only 2 boundaries, one of them connecting twice, * the other one must then be topologically incorrect in case of boundary */ /* go backward as long as there is only one other line/boundary at the current node */ G_debug(3, "go backward"); Vect_get_line_nodes(Map, line, &next_node, NULL); first = -line; while (1) { node_n_lines = Vect_get_node_n_lines(Map, next_node); /* count lines/boundaries at this node */ lines_type = 0; next_line = first; for (i = 0; i < node_n_lines; i++) { curr_line = Vect_get_node_line(Map, next_node, i); if ((Vect_get_line_type(Map, abs(curr_line)) & GV_LINES)) lines_type++; if ((Vect_get_line_type(Map, abs(curr_line)) == ltype)) { if (abs(curr_line) != abs(first)) { Vect_read_line(Map, NULL, Cats, abs(curr_line)); /* catgories must be identical */ if (compare_cats(MCats, Cats) == 0) next_line = curr_line; } } } if (lines_type == 2 && abs(next_line) != abs(first) && abs(next_line) != line) { first = next_line; if (first < 0) { Vect_get_line_nodes(Map, -first, &next_node, NULL); } else { Vect_get_line_nodes(Map, first, NULL, &next_node); } } else break; } /* go forward as long as there is only one other line/boundary at the current node */ G_debug(3, "go forward"); /* reverse direction */ last = -first; if (last < 0) { Vect_get_line_nodes(Map, -last, &next_node, NULL); } else { Vect_get_line_nodes(Map, last, NULL, &next_node); } Vect_reset_list(List); while (1) { G_ilist_add(List, last); node_n_lines = Vect_get_node_n_lines(Map, next_node); lines_type = 0; next_line = last; for (i = 0; i < node_n_lines; i++) { curr_line = Vect_get_node_line(Map, next_node, i); if ((Vect_get_line_type(Map, abs(curr_line)) & GV_LINES)) lines_type++; if ((Vect_get_line_type(Map, abs(curr_line)) == ltype)) { if (abs(curr_line) != abs(last)) { Vect_read_line(Map, NULL, Cats, abs(curr_line)); if (compare_cats(MCats, Cats) == 0) next_line = curr_line; } } } if (lines_type == 2 && abs(next_line) != abs(last) && abs(next_line) != abs(first)) { last = next_line; if (last < 0) { Vect_get_line_nodes(Map, -last, &next_node, NULL); } else { Vect_get_line_nodes(Map, last, NULL, &next_node); } } else break; } /* merge lines */ G_debug(3, "merge %d lines", List->n_values); Vect_reset_line(MPoints); for (i = 0; i < List->n_values; i++) { Vect_reset_line(Points); Vect_read_line(Map, Points, Cats, abs(List->value[i])); direction = (List->value[i] < 0 ? GV_BACKWARD : GV_FORWARD); Vect_append_points(MPoints, Points, direction); MPoints->n_points--; Vect_delete_line(Map, abs(List->value[i])); } MPoints->n_points++; merged += List->n_values; newl++; return merged; }
int main(int argc, char **argv) { int line; struct line_pnts *points; struct line_cats *Cats; struct Map_info map, Out; struct GModule *module; struct Option *input; struct Option *output; struct Option *cats; struct Option *type_opt; char *desc; int polyline; int *lines_visited; int points_in_polyline; int start_line; int nlines; int write_cats, copy_tables; int type, ltype; /* Initialize the GIS calls */ G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("topology")); G_add_keyword(_("geometry")); G_add_keyword(_("line")); G_add_keyword(_("node")); G_add_keyword(_("vertex")); module->description = _("Builds polylines from lines or boundaries."); /* Define the options */ input = G_define_standard_option(G_OPT_V_INPUT); output = G_define_standard_option(G_OPT_V_OUTPUT); cats = G_define_option(); cats->key = "cats"; cats->type = TYPE_STRING; cats->description = _("Category number mode"); cats->options = "no,first,multi,same"; desc = NULL; G_asprintf(&desc, "no;%s;first;%s;multi;%s;same;%s", _("Do not assign any category number to polyline"), _("Assign category number of first line to polyline"), _("Assign multiple category numbers to polyline"), _("Create polyline from lines with same categories")); cats->descriptions = desc; cats->answer = "no"; type_opt = G_define_standard_option(G_OPT_V_TYPE); type_opt->options = "line,boundary"; type_opt->answer = "line,boundary"; if (G_parser(argc, argv)) exit(EXIT_FAILURE); Vect_check_input_output_name(input->answer, output->answer, G_FATAL_EXIT); /* Open binary vector map at level 2 */ Vect_set_open_level(2); if (Vect_open_old(&map, input->answer, "") < 0) G_fatal_error(_("Unable to open vector map <%s>"), input->answer); /* Open new vector */ G_find_vector2(output->answer, ""); if (Vect_open_new(&Out, output->answer, Vect_is_3d(&map)) < 0) G_fatal_error(_("Unable to create vector map <%s>"), output->answer); /* Copy header info. */ Vect_copy_head_data(&map, &Out); /* History */ Vect_hist_copy(&map, &Out); Vect_hist_command(&Out); /* Get the number of lines in the binary map and set up record of lines visited */ lines_visited = (int *)G_calloc(Vect_get_num_lines(&map) + 1, sizeof(int)); /* Set up points structure and coordinate arrays */ points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); /* Write cats */ if (strcmp(cats->answer, "no") == 0) write_cats = NO_CATS; else if (strcmp(cats->answer, "first") == 0) write_cats = ONE_CAT; else write_cats = MULTI_CATS; if (type_opt->answer) type = Vect_option_to_types(type_opt); else type = GV_LINES; /* Step over all lines in binary map */ polyline = 0; nlines = 0; copy_tables = (write_cats != NO_CATS); for (line = 1; line <= Vect_get_num_lines(&map); line++) { Vect_reset_cats(Cats); ltype = Vect_read_line(&map, NULL, NULL, line); if ((ltype & GV_LINES) && (ltype & type)) nlines++; else { /* copy points to output as they are, with cats */ Vect_read_line(&map, points, Cats, line); Vect_write_line(&Out, ltype, points, Cats); if (Cats->n_cats > 0) copy_tables = 1; continue; } /* Skip line if already visited from another */ if (lines_visited[line]) continue; /* Only get here if line is not previously visited */ /* Find start of this polyline */ start_line = walk_back(&map, line, ltype); G_debug(1, "Polyline %d: start line = %d", polyline, start_line); /* Walk forward and pick up coordinates */ points_in_polyline = walk_forward_and_pick_up_coords(&map, start_line, ltype, points, lines_visited, Cats, write_cats); /* Write the line (type of the first line is used) */ Vect_write_line(&Out, ltype, points, Cats); polyline++; } G_verbose_message(n_("%d line or boundaries found in input vector map", "%d lines or boundaries found in input vector map", nlines), nlines, Vect_get_name(&map), Vect_get_mapset(&map)); G_verbose_message(n_("%d polyline stored in output vector map", "%d polylines stored in output vector map", polyline), polyline, Vect_get_name(&Out), Vect_get_mapset(&Out)); /* Copy (all linked) tables if needed */ if (copy_tables) { if (Vect_copy_tables(&map, &Out, 0)) G_warning(_("Failed to copy attribute table to output map")); } /* Tidy up */ Vect_destroy_line_struct(points); Vect_destroy_cats_struct(Cats); G_free(lines_visited); Vect_close(&map); Vect_build(&Out); Vect_close(&Out); exit(EXIT_SUCCESS); }