void Vect_break_lines(struct Map_info *Map, int type, struct Map_info *Err) { Vect_break_lines_list(Map, NULL, NULL, type, Err); return; }
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; }
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 GModule *module; struct GParams params; struct Map_info Map; struct Map_info **BgMap; /* backgroud vector maps */ int nbgmaps; /* number of registrated background maps */ enum mode action_mode; FILE *ascii; int i; int move_first, snap; int ret, layer; double move_x, move_y, move_z, thresh[3]; struct line_pnts *coord; struct ilist *List; struct cat_list *Clist; ascii = NULL; List = NULL; BgMap = NULL; nbgmaps = 0; coord = NULL; Clist = NULL; G_gisinit(argv[0]); module = G_define_module(); module->overwrite = TRUE; G_add_keyword(_("vector")); G_add_keyword(_("editing")); G_add_keyword(_("geometry")); module->description = _("Edits a vector map, allows adding, deleting " "and modifying selected vector features."); if (!parser(argc, argv, ¶ms, &action_mode)) exit(EXIT_FAILURE); /* get list of categories */ Clist = Vect_new_cat_list(); if (params.cat->answer && Vect_str_to_cat_list(params.cat->answer, Clist)) { G_fatal_error(_("Unable to get category list <%s>"), params.cat->answer); } /* open input file */ if (params.in->answer) { if (strcmp(params.in->answer, "-") != 0) { ascii = fopen(params.in->answer, "r"); if (ascii == NULL) G_fatal_error(_("Unable to open file <%s>"), params.in->answer); } else { ascii = stdin; } } if (!ascii && action_mode == MODE_ADD) G_fatal_error(_("Required parameter <%s> not set"), params.in->key); if (action_mode == MODE_CREATE) { int overwrite; overwrite = G_check_overwrite(argc, argv); if (G_find_vector2(params.map->answer, G_mapset())) { if (!overwrite) G_fatal_error(_("Vector map <%s> already exists"), params.map->answer); } /* 3D vector maps? */ ret = Vect_open_new(&Map, params.map->answer, WITHOUT_Z); if (Vect_maptype(&Map) == GV_FORMAT_OGR_DIRECT) { int type; type = Vect_option_to_types(params.type); if (type != GV_POINT && type != GV_LINE && type != GV_BOUNDARY) G_fatal_error(_("Supported feature type for OGR layer: " "%s, %s or %s"), "point", "line", "boundary"); V2_open_new_ogr(&Map, type); } if (ret == -1) { G_fatal_error(_("Unable to create vector map <%s>"), params.map->answer); } G_debug(1, "Map created"); if (ascii) { /* also add new vector features */ action_mode = MODE_ADD; } } else { /* open selected vector file */ if (action_mode == MODE_ADD) /* write */ ret = Vect_open_update2(&Map, params.map->answer, G_mapset(), params.fld->answer); else /* read-only -- select features */ ret = Vect_open_old2(&Map, params.map->answer, G_mapset(), params.fld->answer); if (ret < 2) G_fatal_error(_("Unable to open vector map <%s> at topological level %d"), params.map->answer, 2); } G_debug(1, "Map opened"); /* open backgroud maps */ if (params.bmaps->answer) { i = 0; while (params.bmaps->answers[i]) { const char *bmap = params.bmaps->answers[i]; const char *mapset = G_find_vector2(bmap, ""); if (!mapset) G_fatal_error(_("Vector map <%s> not found"), bmap); if (strcmp( G_fully_qualified_name(params.map->answer, G_mapset()), G_fully_qualified_name(bmap, mapset)) == 0) { G_fatal_error(_("Unable to open vector map <%s> as the background map. " "It is given as vector map to be edited."), bmap); } nbgmaps++; BgMap = (struct Map_info **)G_realloc( BgMap, nbgmaps * sizeof(struct Map_info *)); BgMap[nbgmaps - 1] = (struct Map_info *)G_malloc(sizeof(struct Map_info)); if (Vect_open_old(BgMap[nbgmaps - 1], bmap, "") == -1) G_fatal_error(_("Unable to open vector map <%s>"), bmap); G_verbose_message(_("Background vector map <%s> registered"), bmap); i++; } } layer = Vect_get_field_number(&Map, params.fld->answer); i = 0; while (params.maxdist->answers[i]) { switch (i) { case THRESH_COORDS: thresh[THRESH_COORDS] = max_distance(atof(params.maxdist->answers[THRESH_COORDS])); thresh[THRESH_SNAP] = thresh[THRESH_QUERY] = thresh[THRESH_COORDS]; break; case THRESH_SNAP: thresh[THRESH_SNAP] = max_distance(atof(params.maxdist->answers[THRESH_SNAP])); break; case THRESH_QUERY: thresh[THRESH_QUERY] = atof(params.maxdist->answers[THRESH_QUERY]); break; default: break; } i++; } move_first = params.move_first->answer ? 1 : 0; snap = NO_SNAP; if (strcmp(params.snap->answer, "node") == 0) snap = SNAP; else if (strcmp(params.snap->answer, "vertex") == 0) snap = SNAPVERTEX; if (snap != NO_SNAP && thresh[THRESH_SNAP] <= 0) { G_warning(_("Threshold for snapping must be > 0. No snapping applied.")); snap = NO_SNAP; } if (action_mode != MODE_CREATE && action_mode != MODE_ADD) { /* select lines */ List = Vect_new_list(); G_message(_("Selecting features...")); if (action_mode == MODE_COPY && BgMap && BgMap[0]) { List = select_lines(BgMap[0], action_mode, ¶ms, thresh, List); } else { List = select_lines(&Map, action_mode, ¶ms, thresh, List); } } if ((action_mode != MODE_CREATE && action_mode != MODE_ADD && action_mode != MODE_SELECT)) { if (List->n_values < 1) { G_warning(_("No features selected, nothing to edit")); action_mode = MODE_NONE; ret = 0; } else { /* reopen the map for updating */ if (action_mode == MODE_ZBULK && !Vect_is_3d(&Map)) { Vect_close(&Map); G_fatal_error(_("Vector map <%s> is not 3D. Tool '%s' requires 3D vector map. " "Please convert the vector map " "to 3D using e.g. %s."), params.map->answer, params.tool->answer, "v.extrude"); } Vect_close(&Map); Vect_open_update2(&Map, params.map->answer, G_mapset(), params.fld->answer); } } /* coords option -> array */ if (params.coord->answers) { coord = Vect_new_line_struct(); int i = 0; double east, north; while (params.coord->answers[i]) { east = atof(params.coord->answers[i]); north = atof(params.coord->answers[i + 1]); Vect_append_point(coord, east, north, 0.0); i += 2; } } /* perform requested editation */ switch (action_mode) { case MODE_CREATE: break; case MODE_ADD: if (!params.header->answer) Vect_read_ascii_head(ascii, &Map); int num_lines; num_lines = Vect_get_num_lines(&Map); ret = Vect_read_ascii(ascii, &Map); G_message(_("%d features added"), ret); if (ret > 0) { int iline; struct ilist *List_added; List_added = Vect_new_list(); for (iline = num_lines + 1; iline <= Vect_get_num_lines(&Map); iline++) Vect_list_append(List_added, iline); G_verbose_message(_("Threshold value for snapping is %.2f"), thresh[THRESH_SNAP]); if (snap != NO_SNAP) { /* apply snapping */ /* snap to vertex ? */ Vedit_snap_lines(&Map, BgMap, nbgmaps, List_added, thresh[THRESH_SNAP], snap == SNAP ? FALSE : TRUE); } if (params.close->answer) { /* close boundaries */ int nclosed; nclosed = close_lines(&Map, GV_BOUNDARY, thresh[THRESH_SNAP]); G_message(_("%d boundaries closed"), nclosed); } Vect_destroy_list(List_added); } break; case MODE_DEL: ret = Vedit_delete_lines(&Map, List); G_message(_("%d features deleted"), ret); break; case MODE_MOVE: move_x = atof(params.move->answers[0]); move_y = atof(params.move->answers[1]); move_z = atof(params.move->answers[2]); G_verbose_message(_("Threshold value for snapping is %.2f"), thresh[THRESH_SNAP]); ret = Vedit_move_lines(&Map, BgMap, nbgmaps, List, move_x, move_y, move_z, snap, thresh[THRESH_SNAP]); G_message(_("%d features moved"), ret); break; case MODE_VERTEX_MOVE: move_x = atof(params.move->answers[0]); move_y = atof(params.move->answers[1]); move_z = atof(params.move->answers[2]); G_verbose_message(_("Threshold value for snapping is %.2f"), thresh[THRESH_SNAP]); ret = Vedit_move_vertex(&Map, BgMap, nbgmaps, List, coord, thresh[THRESH_COORDS], thresh[THRESH_SNAP], move_x, move_y, move_z, move_first, snap); G_message(_("%d vertices moved"), ret); break; case MODE_VERTEX_ADD: ret = Vedit_add_vertex(&Map, List, coord, thresh[THRESH_COORDS]); G_message(_("%d vertices added"), ret); break; case MODE_VERTEX_DELETE: ret = Vedit_remove_vertex(&Map, List, coord, thresh[THRESH_COORDS]); G_message(_("%d vertices removed"), ret); break; case MODE_BREAK: if (params.coord->answer) { ret = Vedit_split_lines(&Map, List, coord, thresh[THRESH_COORDS], NULL); } else { ret = Vect_break_lines_list(&Map, List, NULL, GV_LINES, NULL); } G_message(_("%d lines broken"), ret); break; case MODE_CONNECT: G_verbose_message(_("Threshold value for snapping is %.2f"), thresh[THRESH_SNAP]); ret = Vedit_connect_lines(&Map, List, thresh[THRESH_SNAP]); G_message(_("%d lines connected"), ret); break; case MODE_MERGE: ret = Vedit_merge_lines(&Map, List); G_message(_("%d lines merged"), ret); break; case MODE_SELECT: ret = print_selected(List); break; case MODE_CATADD: ret = Vedit_modify_cats(&Map, List, layer, 0, Clist); G_message(_("%d features modified"), ret); break; case MODE_CATDEL: ret = Vedit_modify_cats(&Map, List, layer, 1, Clist); G_message(_("%d features modified"), ret); break; case MODE_COPY: if (BgMap && BgMap[0]) { if (nbgmaps > 1) G_warning(_("Multiple background maps were given. " "Selected features will be copied only from " "vector map <%s>."), Vect_get_full_name(BgMap[0])); ret = Vedit_copy_lines(&Map, BgMap[0], List); } else { ret = Vedit_copy_lines(&Map, NULL, List); } G_message(_("%d features copied"), ret); break; case MODE_SNAP: G_verbose_message(_("Threshold value for snapping is %.2f"), thresh[THRESH_SNAP]); ret = snap_lines(&Map, List, thresh[THRESH_SNAP]); break; case MODE_FLIP: ret = Vedit_flip_lines(&Map, List); G_message(_("%d lines flipped"), ret); break; case MODE_NONE: break; case MODE_ZBULK:{ double start, step; double x1, y1, x2, y2; start = atof(params.zbulk->answers[0]); step = atof(params.zbulk->answers[1]); x1 = atof(params.bbox->answers[0]); y1 = atof(params.bbox->answers[1]); x2 = atof(params.bbox->answers[2]); y2 = atof(params.bbox->answers[3]); ret = Vedit_bulk_labeling(&Map, List, x1, y1, x2, y2, start, step); G_message(_("%d lines labeled"), ret); break; } case MODE_CHTYPE:{ ret = Vedit_chtype_lines(&Map, List); if (ret > 0) { G_message(_("%d features converted"), ret); } else { G_message(_("No feature modified")); } break; } default: G_warning(_("Operation not implemented")); ret = -1; break; } Vect_hist_command(&Map); /* build topology only if requested or if tool!=select */ if (!(action_mode == MODE_SELECT || params.topo->answer == 1 || !MODE_NONE)) { Vect_build_partial(&Map, GV_BUILD_NONE); Vect_build(&Map); } if (List) Vect_destroy_list(List); Vect_close(&Map); G_debug(1, "Map closed"); /* close background maps */ for (i = 0; i < nbgmaps; i++) { Vect_close(BgMap[i]); G_free((void *)BgMap[i]); } G_free((void *)BgMap); if (coord) Vect_destroy_line_struct(coord); if (Clist) Vect_destroy_cat_list(Clist); G_done_msg(" "); if (ret > -1) { exit(EXIT_SUCCESS); } else { exit(EXIT_FAILURE); } }