int rmdac(struct Map_info *Out, struct Map_info *Err) { int i, type, area, ndupl, nlines; struct line_pnts *Points; struct line_cats *Cats; nlines = Vect_get_num_lines(Out); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); G_debug(1, "nlines = %d", nlines); ndupl = 0; for (i = 1; i <= nlines; i++) { G_percent(i, nlines, 2); if (!Vect_line_alive(Out, i)) continue; type = Vect_read_line(Out, Points, Cats, i); if (!(type & GV_CENTROID)) continue; area = Vect_get_centroid_area(Out, i); G_debug(3, " area = %d", area); if (area < 0) { Vect_delete_line(Out, i); ndupl++; if (Err) { Vect_write_line(Err, type, Points, Cats); } } } G_verbose_message(_("Duplicate area centroids: %d"), ndupl); Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(Cats); return ndupl; }
int main(int argc, char **argv) { struct GModule *module; struct Option *map_opt, *field_opt, *fs_opt, *vs_opt, *nv_opt, *col_opt, *where_opt, *file_opt; struct Flag *c_flag, *v_flag, *r_flag; dbDriver *driver; dbString sql, value_string; dbCursor cursor; dbTable *table; dbColumn *column; dbValue *value; struct field_info *Fi; int ncols, col, more; struct Map_info Map; char query[1024]; struct ilist *list_lines; struct bound_box *min_box, *line_box; int i, line, area, init_box, cat; module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("database")); G_add_keyword(_("attribute table")); module->description = _("Prints vector map attributes."); map_opt = G_define_standard_option(G_OPT_V_MAP); field_opt = G_define_standard_option(G_OPT_V_FIELD); col_opt = G_define_standard_option(G_OPT_DB_COLUMNS); where_opt = G_define_standard_option(G_OPT_DB_WHERE); fs_opt = G_define_standard_option(G_OPT_F_SEP); fs_opt->description = _("Output field separator"); fs_opt->guisection = _("Format"); vs_opt = G_define_standard_option(G_OPT_F_SEP); vs_opt->key = "vs"; vs_opt->description = _("Output vertical record separator"); vs_opt->answer = NULL; vs_opt->guisection = _("Format"); nv_opt = G_define_option(); nv_opt->key = "nv"; nv_opt->type = TYPE_STRING; nv_opt->required = NO; nv_opt->description = _("Null value indicator"); nv_opt->guisection = _("Format"); file_opt = G_define_standard_option(G_OPT_F_OUTPUT); file_opt->key = "file"; file_opt->required = NO; file_opt->description = _("Name for output file (if omitted or \"-\" output to stdout)"); r_flag = G_define_flag(); r_flag->key = 'r'; r_flag->description = _("Print minimal region extent of selected vector features instead of attributes"); c_flag = G_define_flag(); c_flag->key = 'c'; c_flag->description = _("Do not include column names in output"); c_flag->guisection = _("Format"); v_flag = G_define_flag(); v_flag->key = 'v'; v_flag->description = _("Vertical output (instead of horizontal)"); v_flag->guisection = _("Format"); G_gisinit(argv[0]); if (G_parser(argc, argv)) exit(EXIT_FAILURE); /* set input vector map name and mapset */ if (file_opt->answer && strcmp(file_opt->answer, "-") != 0) { if (NULL == freopen(file_opt->answer, "w", stdout)) { G_fatal_error(_("Unable to open file <%s> for writing"), file_opt->answer); } } if (r_flag->answer) { min_box = (struct bound_box *) G_malloc(sizeof(struct bound_box)); G_zero((void *)min_box, sizeof(struct bound_box)); line_box = (struct bound_box *) G_malloc(sizeof(struct bound_box)); list_lines = Vect_new_list(); } else { min_box = line_box = NULL; list_lines = NULL; } db_init_string(&sql); db_init_string(&value_string); /* open input vector */ if (!r_flag->answer) Vect_open_old_head2(&Map, map_opt->answer, "", field_opt->answer); else { if (2 > Vect_open_old2(&Map, map_opt->answer, "", field_opt->answer)) { Vect_close(&Map); G_fatal_error(_("Unable to open vector map <%s> at topology level. " "Flag '%c' requires topology level."), map_opt->answer, r_flag->key); } } if ((Fi = Vect_get_field2(&Map, field_opt->answer)) == NULL) G_fatal_error(_("Database connection not defined for layer <%s>"), field_opt->answer); driver = db_start_driver_open_database(Fi->driver, Fi->database); if (!driver) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Fi->database, Fi->driver); if (col_opt->answer) sprintf(query, "SELECT %s FROM ", col_opt->answer); else sprintf(query, "SELECT * FROM "); db_set_string(&sql, query); db_append_string(&sql, Fi->table); if (where_opt->answer) { char *buf = NULL; buf = G_malloc((strlen(where_opt->answer) + 8)); sprintf(buf, " WHERE %s", where_opt->answer); db_append_string(&sql, buf); G_free(buf); } if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) G_fatal_error(_("Unable to open select cursor")); table = db_get_cursor_table(&cursor); ncols = db_get_table_number_of_columns(table); /* column names if horizontal output (ignore for -r) */ if (!v_flag->answer && !c_flag->answer && !r_flag->answer) { for (col = 0; col < ncols; col++) { column = db_get_table_column(table, col); if (col) fprintf(stdout, "%s", fs_opt->answer); fprintf(stdout, "%s", db_get_column_name(column)); } fprintf(stdout, "\n"); } init_box = 1; /* fetch the data */ while (1) { if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) G_fatal_error(_("Unable to fetch data from table <%s>"), Fi->table); if (!more) break; cat = -1; for (col = 0; col < ncols; col++) { column = db_get_table_column(table, col); value = db_get_column_value(column); if (cat < 0 && strcmp(Fi->key, db_get_column_name(column)) == 0) { cat = db_get_value_int(value); if (r_flag->answer) break; } if (r_flag->answer) continue; db_convert_column_value_to_string(column, &value_string); if (!c_flag->answer && v_flag->answer) fprintf(stdout, "%s%s", db_get_column_name(column), fs_opt->answer); if (col && !v_flag->answer) fprintf(stdout, "%s", fs_opt->answer); if (nv_opt->answer && db_test_value_isnull(value)) fprintf(stdout, "%s", nv_opt->answer); else fprintf(stdout, "%s", db_get_string(&value_string)); if (v_flag->answer) fprintf(stdout, "\n"); } if (r_flag->answer) { /* get minimal region extent */ Vect_cidx_find_all(&Map, Vect_get_field_number(&Map, field_opt->answer), -1, cat, list_lines); for (i = 0; i < list_lines->n_values; i++) { line = list_lines->value[i]; area = Vect_get_centroid_area(&Map, line); if (area > 0) { if (!Vect_get_area_box(&Map, area, line_box)) G_fatal_error(_("Unable to get bounding box of area %d"), area); } else { if (!Vect_get_line_box(&Map, line, line_box)) G_fatal_error(_("Unable to get bounding box of line %d"), line); } if (init_box) { Vect_box_copy(min_box, line_box); init_box = 0; } else { Vect_box_extend(min_box, line_box); } } } else { if (!v_flag->answer) fprintf(stdout, "\n"); else if (vs_opt->answer) fprintf(stdout, "%s\n", vs_opt->answer); } } if (r_flag->answer) { fprintf(stdout, "n=%f\n", min_box->N); fprintf(stdout, "s=%f\n", min_box->S); fprintf(stdout, "w=%f\n", min_box->W); fprintf(stdout, "e=%f\n", min_box->E); if (Vect_is_3d(&Map)) { fprintf(stdout, "t=%f\n", min_box->T); fprintf(stdout, "b=%f\n", min_box->B); } fflush(stdout); G_free((void *)min_box); G_free((void *)line_box); Vect_destroy_list(list_lines); } db_close_cursor(&cursor); db_close_database_shutdown_driver(driver); Vect_close(&Map); exit(EXIT_SUCCESS); }
int export_areas_single(struct Map_info *In, int field, int donocat, OGRFeatureDefnH Ogr_featuredefn,OGRLayerH Ogr_layer, struct field_info *Fi, dbDriver *driver, int ncol, int *colctype, const char **colname, int doatt, int nocat, int *n_noatt, int *n_nocat) { int i, j; int centroid, cat, area, n_areas; int n_exported; struct line_pnts *Points; struct line_cats *Cats; OGRGeometryH Ogr_geometry; OGRFeatureH Ogr_feature; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); n_exported = 0; n_areas = Vect_get_num_areas(In); for (i = 1; i <= n_areas; i++) { G_percent(i, n_areas, 5); /* get centroid's category */ centroid = Vect_get_area_centroid(In, i); cat = -1; if (centroid > 0) { Vect_read_line(In, NULL, Cats, centroid); Vect_cat_get(Cats, field, &cat); } G_debug(3, "area = %d centroid = %d ncats = %d", i, centroid, Cats->n_cats); if (cat < 0 && !donocat) { (*n_nocat)++; continue; /* skip areas without category, do not export * not labeled */ } /* find correspoding area */ area = Vect_get_centroid_area(In, centroid); if (area == 0) continue; /* create polygon from area */ Ogr_geometry = create_polygon(In, area, Points); /* add feature */ Ogr_feature = OGR_F_Create(Ogr_featuredefn); OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); /* output one feature for each category */ for (j = -1; j < Cats->n_cats; j++) { if (j == -1) { if (cat >= 0) continue; /* cat(s) exists */ (*n_nocat)++; } else { if (Cats->field[j] == field) cat = Cats->cat[j]; else continue; } mk_att(cat, Fi, driver, ncol, colctype, colname, doatt, nocat, Ogr_feature, n_noatt); OGR_L_CreateFeature(Ogr_layer, Ogr_feature); n_exported++; } OGR_G_DestroyGeometry(Ogr_geometry); OGR_F_Destroy(Ogr_feature); } Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(Cats); return n_exported; }
int export_areas_multi(struct Map_info *In, int field, int donocat, OGRFeatureDefnH Ogr_featuredefn,OGRLayerH Ogr_layer, struct field_info *Fi, dbDriver *driver, int ncol, int *colctype, const char **colname, int doatt, int nocat, int *n_noatt, int *n_nocat) { int i, n_exported, area; int cat, ncats_field, line, type, findex, ipart; struct line_pnts *Points; struct line_cats *Cats; struct ilist *cat_list, *line_list, *lcats; OGRGeometryH Ogr_geometry, Ogr_geometry_part; OGRFeatureH Ogr_feature; OGRwkbGeometryType wkbtype, wkbtype_part; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); cat_list = Vect_new_list(); line_list = Vect_new_list(); lcats = Vect_new_list(); n_exported = 0; /* check if category index is available for given field */ findex = Vect_cidx_get_field_index(In, field); if (findex == -1) G_fatal_error(_("Unable to export multi-features. No category index for layer %d."), field); /* determine type */ wkbtype_part = wkbPolygon; wkbtype = get_multi_wkbtype(wkbtype_part); ncats_field = Vect_cidx_get_unique_cats_by_index(In, findex, cat_list); G_debug(1, "n_cats = %d for layer %d", ncats_field, field); if (donocat) G_message(_("Exporting features with category...")); for (i = 0; i < cat_list->n_values; i++) { G_percent(i, cat_list->n_values - 1, 5); cat = cat_list->value[i]; /* find all centroids with given category */ Vect_cidx_find_all(In, field, GV_CENTROID, cat, line_list); /* create multi-feature */ Ogr_geometry = OGR_G_CreateGeometry(wkbtype); /* build simple features geometry, go through all parts */ for (ipart = 0; ipart < line_list->n_values; ipart++) { line = line_list->value[ipart]; G_debug(3, "cat=%d, line=%d -> part=%d", cat, line, ipart); /* get centroid's category */ Vect_read_line(In, NULL, Cats, line); /* check for category consistency */ Vect_field_cat_get(Cats, field, lcats); if (!Vect_val_in_list(lcats, cat)) G_fatal_error(_("Unable to create multi-feature. " "Category %d not found in line %d, field %d"), cat, line, field); /* find correspoding area */ area = Vect_get_centroid_area(In, line); if (area == 0) continue; /* create polygon from area */ Ogr_geometry_part = create_polygon(In, area, Points); /* add part */ OGR_G_AddGeometryDirectly(Ogr_geometry, Ogr_geometry_part); } if (!OGR_G_IsEmpty(Ogr_geometry)) { /* write multi-feature */ Ogr_feature = OGR_F_Create(Ogr_featuredefn); OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); mk_att(cat, Fi, driver, ncol, colctype, colname, doatt, nocat, Ogr_feature, n_noatt); OGR_L_CreateFeature(Ogr_layer, Ogr_feature); OGR_F_Destroy(Ogr_feature); n_exported++; } else { /* skip empty features */ G_debug(3, "multi-feature is empty -> skipped"); } OGR_G_DestroyGeometry(Ogr_geometry); } if (donocat) G_message(_("Exporting features without category...")); /* check lines without category, if -c flag is given write them as * one multi-feature */ Ogr_geometry = OGR_G_CreateGeometry(wkbtype); Vect_rewind(In); Vect_set_constraint_type(In, GV_CENTROID); while(TRUE) { type = Vect_read_next_line(In, NULL, Cats); if (type < 0) break; /* get centroid's category */ Vect_cat_get(Cats, field, &cat); if (cat > 0) continue; /* skip features with category */ if (cat < 0 && !donocat) { (*n_nocat)++; continue; /* skip lines without category, do not export * not labeled */ } /* find correspoding area */ line = Vect_get_next_line_id(In); area = Vect_get_centroid_area(In, line); if (area == 0) continue; /* create polygon from area */ Ogr_geometry_part = create_polygon(In, area, Points); /* add part */ OGR_G_AddGeometryDirectly(Ogr_geometry, Ogr_geometry_part); (*n_nocat)++; } if (!OGR_G_IsEmpty(Ogr_geometry)) { /* write multi-feature */ Ogr_feature = OGR_F_Create(Ogr_featuredefn); OGR_F_SetGeometry(Ogr_feature, Ogr_geometry); mk_att(cat, Fi, driver, ncol, colctype, colname, doatt, nocat, Ogr_feature, n_noatt); OGR_L_CreateFeature(Ogr_layer, Ogr_feature); OGR_F_Destroy(Ogr_feature); n_exported++; } else { /* skip empty features */ G_debug(3, "multi-feature is empty -> skipped"); } OGR_G_DestroyGeometry(Ogr_geometry); Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(Cats); Vect_destroy_list(cat_list); Vect_destroy_list(line_list); Vect_destroy_list(lcats); return n_exported; }
/*! \brief Draw one feature */ struct robject *draw_line(struct Map_info *Map, int line, int draw_flag) { int draw; struct robject *obj; if (!state.Points) state.Points = Vect_new_line_struct(); if (!Vect_line_alive(Map, line)) return NULL; state.type = Vect_read_line(Map, state.Points, NULL, line); obj = (struct robject *)G_malloc(sizeof(struct robject)); obj->fid = line; draw = FALSE; if (state.type & GV_LINES) { if (state.type == GV_LINE) { obj->type = TYPE_LINE; draw = draw_flag & DRAW_LINE; } else if (state.type == GV_BOUNDARY) { int left, right; Vect_get_line_areas(Map, line, &left, &right); if (left == 0 && right == 0) { obj->type = TYPE_BOUNDARYNO; draw = draw_flag & DRAW_BOUNDARYNO; } else if (left > 0 && right > 0) { obj->type = TYPE_BOUNDARYTWO; draw = draw_flag & DRAW_BOUNDARYTWO; } else { obj->type = TYPE_BOUNDARYONE; draw = draw_flag & DRAW_BOUNDARYONE; } } } else if (state.type & GV_POINTS) { if (state.type == GV_POINT) { obj->type = TYPE_POINT; draw = draw_flag & DRAW_POINT; } else if (state.type == GV_CENTROID) { int cret = Vect_get_centroid_area(Map, line); if (cret > 0) { /* -> area */ obj->type = TYPE_CENTROIDIN; draw = draw_flag & DRAW_CENTROIDIN; } else if (cret == 0) { obj->type = TYPE_CENTROIDOUT; draw = draw_flag & DRAW_CENTROIDOUT; } else { obj->type = TYPE_CENTROIDDUP; draw = draw_flag & DRAW_CENTROIDDUP; } } } G_debug(3, " draw_line(): type=%d rtype=%d npoints=%d draw=%d", state.type, obj->type, state.Points->n_points, draw); if (!draw) return NULL; obj->npoints = state.Points->n_points; obj->point = (struct rpoint *)G_malloc(obj->npoints * sizeof(struct rpoint)); robj_points(obj, state.Points); return obj; }
int main(int argc, char **argv) { int i; int **cats, *ncats, nfields, *fields; struct Flag *line_flag; /* struct Flag *all_flag; */ struct Option *in_opt, *out_opt; struct Flag *table_flag; struct GModule *module; struct line_pnts *Points; struct line_cats *Cats; int node, nnodes; COOR *coor; int ncoor, acoor; int line, nlines, type, ctype, area, nareas; int err_boundaries, err_centr_out, err_centr_dupl, err_nocentr; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("geometry")); G_add_keyword(_("triangulation")); module->description = _("Creates a Voronoi diagram from an input vector " "map containing points or centroids."); in_opt = G_define_standard_option(G_OPT_V_INPUT); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); /* all_flag = G_define_flag (); all_flag->key = 'a'; all_flag->description = _("Use all points (do not limit to current region)"); */ line_flag = G_define_flag(); line_flag->key = 'l'; line_flag->description = _("Output tessellation as a graph (lines), not areas"); table_flag = G_define_flag(); table_flag->key = 't'; table_flag->description = _("Do not create attribute table"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); if (line_flag->answer) Type = GV_LINE; else Type = GV_BOUNDARY; All = 0; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); /* open files */ Vect_set_open_level(2); Vect_open_old(&In, in_opt->answer, ""); if (Vect_open_new(&Out, out_opt->answer, 0) < 0) G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); /* initialize working region */ G_get_window(&Window); Vect_region_box(&Window, &Box); Box.T = 0.5; Box.B = -0.5; freeinit(&sfl, sizeof(struct Site)); G_message(_("Reading sites...")); readsites(); siteidx = 0; geominit(); triangulate = 0; plot = 0; debug = 0; G_message(_("Voronoi triangulation...")); voronoi(triangulate, nextone); /* Close free ends by current region */ Vect_build_partial(&Out, GV_BUILD_BASE); ncoor = 0; acoor = 100; coor = (COOR *) G_malloc(sizeof(COOR) * acoor); nnodes = Vect_get_num_nodes(&Out); for (node = 1; node <= nnodes; node++) { double x, y; if (Vect_get_node_n_lines(&Out, node) < 2) { /* add coordinates */ Vect_get_node_coor(&Out, node, &x, &y, NULL); if (ncoor == acoor - 5) { /* always space for 5 region corners */ acoor += 100; coor = (COOR *) G_realloc(coor, sizeof(COOR) * acoor); } coor[ncoor].x = x; coor[ncoor].y = y; ncoor++; } } /* Add region corners */ coor[ncoor].x = Box.W; coor[ncoor].y = Box.S; ncoor++; coor[ncoor].x = Box.E; coor[ncoor].y = Box.S; ncoor++; coor[ncoor].x = Box.E; coor[ncoor].y = Box.N; ncoor++; coor[ncoor].x = Box.W; coor[ncoor].y = Box.N; ncoor++; /* Sort */ qsort(coor, ncoor, sizeof(COOR), (void *)cmp); /* add last (first corner) */ coor[ncoor].x = Box.W; coor[ncoor].y = Box.S; ncoor++; for (i = 1; i < ncoor; i++) { if (coor[i].x == coor[i - 1].x && coor[i].y == coor[i - 1].y) continue; /* duplicate */ Vect_reset_line(Points); Vect_append_point(Points, coor[i].x, coor[i].y, 0.0); Vect_append_point(Points, coor[i - 1].x, coor[i - 1].y, 0.0); Vect_write_line(&Out, Type, Points, Cats); } G_free(coor); /* Copy input points as centroids */ nfields = Vect_cidx_get_num_fields(&In); cats = (int **)G_malloc(nfields * sizeof(int *)); ncats = (int *)G_malloc(nfields * sizeof(int)); fields = (int *)G_malloc(nfields * sizeof(int)); for (i = 0; i < nfields; i++) { ncats[i] = 0; cats[i] = (int *)G_malloc(Vect_cidx_get_num_cats_by_index(&In, i) * sizeof(int)); fields[i] = Vect_cidx_get_field_number(&In, i); } if (line_flag->answer) ctype = GV_POINT; else ctype = GV_CENTROID; nlines = Vect_get_num_lines(&In); G_message(_("Writing sites to output...")); for (line = 1; line <= nlines; line++) { G_percent(line, nlines, 2); type = Vect_read_line(&In, Points, Cats, line); if (!(type & GV_POINTS)) continue; if (!Vect_point_in_box(Points->x[0], Points->y[0], 0.0, &Box)) continue; Vect_write_line(&Out, ctype, Points, Cats); for (i = 0; i < Cats->n_cats; i++) { int f, j; f = -1; for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == Cats->field[i]) { f = j; break; } } if (f > -1) { cats[f][ncats[f]] = Cats->cat[i]; ncats[f]++; } } } /* Copy tables */ if (!(table_flag->answer)) { int ttype, ntabs = 0; struct field_info *IFi, *OFi; /* Number of output tabs */ for (i = 0; i < Vect_get_num_dblinks(&In); i++) { int f, j; IFi = Vect_get_dblink(&In, i); f = -1; for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == IFi->number) { f = j; break; } } if (f > -1) { if (ncats[f] > 0) ntabs++; } } if (ntabs > 1) ttype = GV_MTABLE; else ttype = GV_1TABLE; for (i = 0; i < nfields; i++) { int ret; if (fields[i] == 0) continue; G_message(_("Layer %d"), fields[i]); /* Make a list of categories */ IFi = Vect_get_field(&In, fields[i]); if (!IFi) { /* no table */ G_message(_("No table")); continue; } OFi = Vect_default_field_info(&Out, IFi->number, IFi->name, ttype); ret = db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table, OFi->driver, Vect_subst_var(OFi->database, &Out), OFi->table, IFi->key, cats[i], ncats[i]); if (ret == DB_FAILED) { G_warning(_("Cannot copy table")); } else { Vect_map_add_dblink(&Out, OFi->number, OFi->name, OFi->table, IFi->key, OFi->database, OFi->driver); } } } Vect_close(&In); /* cleaning part 1: count errors */ Vect_build_partial(&Out, GV_BUILD_CENTROIDS); err_boundaries = err_centr_out = err_centr_dupl = err_nocentr = 0; nlines = Vect_get_num_lines(&Out); for (line = 1; line <= nlines; line++) { if (!Vect_line_alive(&Out, line)) continue; type = Vect_get_line_type(&Out, line); if (type == GV_BOUNDARY) { int left, right; Vect_get_line_areas(&Out, line, &left, &right); if (left == 0 || right == 0) { G_debug(3, "line = %d left = %d right = %d", line, left, right); err_boundaries++; } } if (type == GV_CENTROID) { area = Vect_get_centroid_area(&Out, line); if (area == 0) err_centr_out++; else if (area < 0) err_centr_dupl++; } } err_nocentr = 0; nareas = Vect_get_num_areas(&Out); for (area = 1; area <= nareas; area++) { if (!Vect_area_alive(&Out, area)) continue; line = Vect_get_area_centroid(&Out, area); if (line == 0) err_nocentr++; } /* cleaning part 2: snap */ if (err_nocentr || err_centr_dupl || err_centr_out) { int nmod; G_important_message(_("Output needs topological cleaning")); Vect_snap_lines(&Out, GV_BOUNDARY, 1e-7, NULL); do { Vect_break_lines(&Out, GV_BOUNDARY, NULL); Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL); nmod = Vect_clean_small_angles_at_nodes(&Out, GV_BOUNDARY, NULL); } while (nmod > 0); err_boundaries = 0; nlines = Vect_get_num_lines(&Out); for (line = 1; line <= nlines; line++) { if (!Vect_line_alive(&Out, line)) continue; type = Vect_get_line_type(&Out, line); if (type == GV_BOUNDARY) { int left, right; Vect_get_line_areas(&Out, line, &left, &right); if (left == 0 || right == 0) { G_debug(3, "line = %d left = %d right = %d", line, left, right); err_boundaries++; } } } } /* cleaning part 3: remove remaining incorrect boundaries */ if (err_boundaries) { G_important_message(_("Removing incorrect boundaries from output")); nlines = Vect_get_num_lines(&Out); for (line = 1; line <= nlines; line++) { if (!Vect_line_alive(&Out, line)) continue; type = Vect_get_line_type(&Out, line); if (type == GV_BOUNDARY) { int left, right; Vect_get_line_areas(&Out, line, &left, &right); /* &&, not ||, no typo */ if (left == 0 && right == 0) { G_debug(3, "line = %d left = %d right = %d", line, left, right); Vect_delete_line(&Out, line); } } } } /* build clean topology */ Vect_build_partial(&Out, GV_BUILD_NONE); Vect_build(&Out); Vect_close(&Out); G_done_msg(" "); exit(EXIT_SUCCESS); }