bool OGRGRASSLayer::SetSpatialMatch() { CPLDebug ( "GRASS", "SetSpatialMatch" ); if ( !paSpatialMatch ) { paSpatialMatch = (char *) CPLMalloc ( nTotalCount ); } memset ( paSpatialMatch, 0x0, nTotalCount ); OGRGeometry *geom; OGRLineString *lstring = new OGRLineString(); lstring->setNumPoints ( 5 ); geom = lstring; for ( int i = 0; i < nTotalCount; i++ ) { int cidx = paFeatureIndex[i]; int cat, type, id; Vect_cidx_get_cat_by_index ( poMap, iLayerIndex, cidx, &cat, &type, &id ); BOUND_BOX box; switch ( type ) { case GV_POINT: case GV_LINE: case GV_BOUNDARY: Vect_get_line_box ( poMap, id, &box ); break; case GV_AREA: Vect_get_area_box ( poMap, id, &box ); break; } lstring->setPoint( 0, box.W, box.N, 0. ); lstring->setPoint( 1, box.W, box.S, 0. ); lstring->setPoint( 2, box.E, box.S, 0. ); lstring->setPoint( 3, box.E, box.N, 0. ); lstring->setPoint( 4, box.W, box.N, 0. ); if ( FilterGeometry(geom) ) { CPLDebug ( "GRASS", "Feature %d in filter", i ); paSpatialMatch[i] = 1; } } delete lstring; return true; }
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 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 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); }
static int geom2ring(GEOSGeometry *geom, struct Map_info *Out, struct Map_info *Buf, struct spatial_index *si, struct line_cats *Cats, struct buf_contours **arr_bc, int *buffers_count, int *arr_bc_alloc) { int i, nrings, ngeoms, line_id; const GEOSGeometry *geom2; struct bound_box bbox; static struct line_pnts *Points = NULL; static struct line_cats *BCats = NULL; struct buf_contours *p = *arr_bc; G_debug(3, "geom2ring(): GEOS %s", GEOSGeomType(geom)); if (!Points) Points = Vect_new_line_struct(); if (!BCats) BCats = Vect_new_cats_struct(); if (GEOSGeomTypeId(geom) == GEOS_LINESTRING || GEOSGeomTypeId(geom) == GEOS_LINEARRING) { if (!ring2pts(geom, Points)) return 0; Vect_write_line(Out, GV_BOUNDARY, Points, BCats); line_id = Vect_write_line(Buf, GV_BOUNDARY, Points, Cats); /* add buffer to spatial index */ Vect_get_line_box(Buf, line_id, &bbox); Vect_spatial_index_add_item(si, *buffers_count, &bbox); p[*buffers_count].outer = line_id; p[*buffers_count].inner_count = 0; *buffers_count += 1; if (*buffers_count >= *arr_bc_alloc) { *arr_bc_alloc += 100; p = G_realloc(p, *arr_bc_alloc * sizeof(struct buf_contours)); *arr_bc = p; } } else if (GEOSGeomTypeId(geom) == GEOS_POLYGON) { geom2 = GEOSGetExteriorRing(geom); if (!ring2pts(geom2, Points)) return 0; Vect_write_line(Out, GV_BOUNDARY, Points, BCats); line_id = Vect_write_line(Buf, GV_BOUNDARY, Points, Cats); /* add buffer to spatial index */ Vect_get_line_box(Buf, line_id, &bbox); Vect_spatial_index_add_item(si, *buffers_count, &bbox); p[*buffers_count].outer = line_id; p[*buffers_count].inner_count = 0; nrings = GEOSGetNumInteriorRings(geom); if (nrings > 0) { p[*buffers_count].inner_count = nrings; p[*buffers_count].inner = G_malloc(nrings * sizeof(int)); for (i = 0; i < nrings; i++) { geom2 = GEOSGetInteriorRingN(geom, i); if (!ring2pts(geom2, Points)) { G_fatal_error(_("Corrupt GEOS geometry")); } Vect_write_line(Out, GV_BOUNDARY, Points, BCats); line_id = Vect_write_line(Buf, GV_BOUNDARY, Points, BCats); p[*buffers_count].inner[i] = line_id; } } *buffers_count += 1; if (*buffers_count >= *arr_bc_alloc) { *arr_bc_alloc += 100; p = G_realloc(p, *arr_bc_alloc * sizeof(struct buf_contours)); *arr_bc = p; } } else if (GEOSGeomTypeId(geom) == GEOS_MULTILINESTRING || GEOSGeomTypeId(geom) == GEOS_MULTIPOLYGON || GEOSGeomTypeId(geom) == GEOS_GEOMETRYCOLLECTION) { G_debug(3, "GEOS %s", GEOSGeomType(geom)); ngeoms = GEOSGetNumGeometries(geom); for (i = 0; i < ngeoms; i++) { geom2 = GEOSGetGeometryN(geom, i); geom2ring((GEOSGeometry *)geom2, Out, Buf, si, Cats, arr_bc, buffers_count, arr_bc_alloc); } } else G_fatal_error(_("Unknown GEOS geometry type")); return 1; }
int main(int argc, char *argv[]) { int i, iopt; int operator; int aline, nalines, nskipped; int ltype, itype[2], ifield[2]; int **cats, *ncats, nfields, *fields; char *mapset[2], *pre[2]; struct GModule *module; struct GParm parm; struct GFlag flag; struct Map_info In[2], Out; struct field_info *IFi, *OFi; struct line_pnts *APoints, *BPoints; struct line_cats *ACats, *BCats; int *ALines; /* List of lines: 0 do not output, 1 - write to output */ struct ilist *List, *TmpList, *BoundList; G_gisinit(argv[0]); pre[0] = "a"; pre[1] = "b"; module = G_define_module(); module->keywords = _("vector, spatial query"); module->description = _("Selects features from vector map (A) by features from other vector map (B)."); parse_options(&parm, &flag); if (G_parser(argc, argv)) exit(EXIT_FAILURE); if (parm.operator->answer[0] == 'e') operator = OP_EQUALS; else if (parm.operator->answer[0] == 'd') { /* operator = OP_DISJOINT; */ operator = OP_INTERSECTS; flag.reverse->answer = YES; } else if (parm.operator->answer[0] == 'i') operator = OP_INTERSECTS; else if (parm.operator->answer[0] == 't') operator = OP_TOUCHES; else if (parm.operator->answer[0] == 'c' && parm.operator->answer[1] == 'r') operator = OP_CROSSES; else if (parm.operator->answer[0] == 'w') operator = OP_WITHIN; else if (parm.operator->answer[0] == 'c' && parm.operator->answer[1] == 'o') operator = OP_CONTAINS; else if (parm.operator->answer[0] == 'o') { if (strcmp(parm.operator->answer, "overlaps") == 0) operator = OP_OVERLAPS; else operator = OP_OVERLAP; } else if (parm.operator->answer[0] == 'r') operator = OP_RELATE; else G_fatal_error(_("Unknown operator")); if (operator == OP_RELATE && !parm.relate->answer) { G_fatal_error(_("Required parameter <%s> not set"), parm.relate->key); } for (iopt = 0; iopt < 2; iopt++) { itype[iopt] = Vect_option_to_types(parm.type[iopt]); ifield[iopt] = atoi(parm.field[iopt]->answer); Vect_check_input_output_name(parm.input[iopt]->answer, parm.output->answer, GV_FATAL_EXIT); if ((mapset[iopt] = G_find_vector2(parm.input[iopt]->answer, NULL)) == NULL) { G_fatal_error(_("Vector map <%s> not found"), parm.input[iopt]->answer); } Vect_set_open_level(2); Vect_open_old(&(In[iopt]), parm.input[iopt]->answer, mapset[iopt]); } /* Read field info */ IFi = Vect_get_field(&(In[0]), ifield[0]); APoints = Vect_new_line_struct(); BPoints = Vect_new_line_struct(); ACats = Vect_new_cats_struct(); BCats = Vect_new_cats_struct(); List = Vect_new_list(); TmpList = Vect_new_list(); BoundList = Vect_new_list(); /* Open output */ Vect_open_new(&Out, parm.output->answer, Vect_is_3d(&(In[0]))); Vect_set_map_name(&Out, _("Output from v.select")); Vect_set_person(&Out, G_whoami()); Vect_copy_head_data(&(In[0]), &Out); Vect_hist_copy(&(In[0]), &Out); Vect_hist_command(&Out); nskipped = 0; nalines = Vect_get_num_lines(&(In[0])); #ifdef HAVE_GEOS initGEOS(G_message, G_fatal_error); GEOSGeometry *AGeom = NULL; #else void *AGeom = NULL; #endif /* Alloc space for input lines array */ ALines = (int *)G_calloc(nalines + 1, sizeof(int)); G_message(_("Building spatial index...")); Vect_build_spatial_index(&In[0]); Vect_build_spatial_index(&In[1]); /* Lines in A. Go through all lines and mark those that meets condition */ if (itype[0] & (GV_POINTS | GV_LINES)) { G_message(_("Processing features...")); for (aline = 1; aline <= nalines; aline++) { BOUND_BOX abox; G_debug(3, "aline = %d", aline); G_percent(aline, nalines, 2); /* must be before any continue */ /* Check category */ if (!flag.cat->answer && Vect_get_line_cat(&(In[0]), aline, ifield[0]) < 0) { nskipped++; continue; } /* Read line and check type */ if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS AGeom = Vect_read_line_geos(&(In[0]), aline, <ype); #endif if (!(ltype & (GV_POINT | GV_LINE))) continue; if (!AGeom) G_fatal_error(_("Unable to read line id %d from vector map <%s>"), aline, Vect_get_full_name(&(In[0]))); } else { ltype = Vect_read_line(&(In[0]), APoints, NULL, aline); } if (!(ltype & itype[0])) continue; Vect_get_line_box(&(In[0]), aline, &abox); abox.T = PORT_DOUBLE_MAX; abox.B = -PORT_DOUBLE_MAX; /* Check if this line overlaps any feature in B */ /* x Lines in B */ if (itype[1] & (GV_POINTS | GV_LINES)) { int i; int found = 0; /* Lines */ Vect_select_lines_by_box(&(In[1]), &abox, itype[1], List); for (i = 0; i < List->n_values; i++) { int bline; bline = List->value[i]; G_debug(3, " bline = %d", bline); /* Check category */ if (!flag.cat->answer && Vect_get_line_cat(&(In[1]), bline, ifield[1]) < 0) { nskipped++; continue; } if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS if(line_relate_geos(&(In[1]), AGeom, bline, operator, parm.relate->answer)) { found = 1; break; } #endif } else { Vect_read_line(&(In[1]), BPoints, NULL, bline); if (Vect_line_check_intersection(APoints, BPoints, 0)) { found = 1; break; } } } if (found) { ALines[aline] = 1; continue; /* Go to next A line */ } } /* x Areas in B. */ if (itype[1] & GV_AREA) { int i; Vect_select_areas_by_box(&(In[1]), &abox, List); for (i = 0; i < List->n_values; i++) { int barea; barea = List->value[i]; G_debug(3, " barea = %d", barea); if (Vect_get_area_cat(&(In[1]), barea, ifield[1]) < 0) { nskipped++; continue; } if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS if(area_relate_geos(&(In[1]), AGeom, barea, operator, parm.relate->answer)) { ALines[aline] = 1; break; } #endif } else { if (line_overlap_area(&(In[0]), aline, &(In[1]), barea)) { ALines[aline] = 1; break; } } } } if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS GEOSGeom_destroy(AGeom); #endif AGeom = NULL; } } } /* Areas in A. */ if (itype[0] & GV_AREA) { int aarea, naareas; G_message(_("Processing areas...")); naareas = Vect_get_num_areas(&(In[0])); for (aarea = 1; aarea <= naareas; aarea++) { BOUND_BOX abox; G_percent(aarea, naareas, 2); /* must be before any continue */ if (Vect_get_area_cat(&(In[0]), aarea, ifield[0]) < 0) { nskipped++; continue; } Vect_get_area_box(&(In[0]), aarea, &abox); abox.T = PORT_DOUBLE_MAX; abox.B = -PORT_DOUBLE_MAX; if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS AGeom = Vect_read_area_geos(&(In[0]), aarea); #endif if (!AGeom) G_fatal_error(_("Unable to read area id %d from vector map <%s>"), aline, Vect_get_full_name(&(In[0]))); } /* x Lines in B */ if (itype[1] & (GV_POINTS | GV_LINES)) { Vect_select_lines_by_box(&(In[1]), &abox, itype[1], List); for (i = 0; i < List->n_values; i++) { int bline; bline = List->value[i]; if (!flag.cat->answer && Vect_get_line_cat(&(In[1]), bline, ifield[1]) < 0) { nskipped++; continue; } if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS if(line_relate_geos(&(In[1]), AGeom, bline, operator, parm.relate->answer)) { add_aarea(&(In[0]), aarea, ALines); break; } #endif } else { if (line_overlap_area(&(In[1]), bline, &(In[0]), aarea)) { add_aarea(&(In[0]), aarea, ALines); continue; } } } } /* x Areas in B */ if (itype[1] & GV_AREA) { int naisles; int found = 0; /* List of areas B */ /* Make a list of features forming area A */ Vect_reset_list(List); Vect_get_area_boundaries(&(In[0]), aarea, BoundList); for (i = 0; i < BoundList->n_values; i++) { Vect_list_append(List, abs(BoundList->value[i])); } naisles = Vect_get_area_num_isles(&(In[0]), aarea); for (i = 0; i < naisles; i++) { int j, aisle; aisle = Vect_get_area_isle(&(In[0]), aarea, i); Vect_get_isle_boundaries(&(In[0]), aisle, BoundList); for (j = 0; j < BoundList->n_values; j++) { Vect_list_append(List, BoundList->value[j]); } } Vect_select_areas_by_box(&(In[1]), &abox, TmpList); for (i = 0; i < List->n_values; i++) { int j, aline; aline = abs(List->value[i]); for (j = 0; j < TmpList->n_values; j++) { int barea, bcentroid; barea = TmpList->value[j]; G_debug(3, " barea = %d", barea); if (Vect_get_area_cat(&(In[1]), barea, ifield[1]) < 0) { nskipped++; continue; } /* Check if any centroid of area B is in area A. * This test is important in if area B is completely within area A */ bcentroid = Vect_get_area_centroid(&(In[1]), barea); Vect_read_line(&(In[1]), BPoints, NULL, bcentroid); if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS if(area_relate_geos(&(In[1]), AGeom, barea, operator, parm.relate->answer)) { found = 1; break; } #endif } else { if (Vect_point_in_area(&(In[0]), aarea, BPoints->x[0], BPoints->y[0])) { found = 1; break; } /* Check intersectin of lines from List with area B */ if (line_overlap_area(&(In[0]), aline, &(In[1]), barea)) { found = 1; break; } } } if (found) { add_aarea(&(In[0]), aarea, ALines); break; } } } if (operator != OP_OVERLAP) { #ifdef HAVE_GEOS GEOSGeom_destroy(AGeom); #endif AGeom = NULL; } } } Vect_close(&(In[1])); #ifdef HAVE_GEOS finishGEOS(); #endif /* Write lines */ nfields = Vect_cidx_get_num_fields(&(In[0])); cats = (int **)G_malloc(nfields * sizeof(int *)); ncats = (int *)G_malloc(nfields * sizeof(int)); fields = (int *)G_malloc(nfields * sizeof(int)); for (i = 0; i < nfields; i++) { ncats[i] = 0; cats[i] = (int *)G_malloc(Vect_cidx_get_num_cats_by_index(&(In[0]), i) * sizeof(int)); fields[i] = Vect_cidx_get_field_number(&(In[0]), i); } G_message(_("Writing selected features...")); for (aline = 1; aline <= nalines; aline++) { int atype; G_debug(4, "aline = %d ALines[aline] = %d", aline, ALines[aline]); G_percent(aline, nalines, 2); if ((!flag.reverse->answer && !(ALines[aline])) || (flag.reverse->answer && ALines[aline])) continue; atype = Vect_read_line(&(In[0]), APoints, ACats, aline); Vect_write_line(&Out, atype, APoints, ACats); if (!(flag.table->answer) && (IFi != NULL)) { for (i = 0; i < ACats->n_cats; i++) { int f, j; for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == ACats->field[i]) { f = j; break; } } cats[f][ncats[f]] = ACats->cat[i]; ncats[f]++; } } } /* Copy tables */ if (!(flag.table->answer)) { int ttype, ntabs = 0; G_message(_("Writing attributes...")); /* Number of output tabs */ for (i = 0; i < Vect_get_num_dblinks(&(In[0])); i++) { int f, j; IFi = Vect_get_dblink(&(In[0]), i); for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == IFi->number) { f = j; break; } } if (ncats[f] > 0) ntabs++; } if (ntabs > 1) ttype = GV_MTABLE; else ttype = GV_1TABLE; for (i = 0; i < nfields; i++) { int ret; if (fields[i] == 0) continue; /* Make a list of categories */ IFi = Vect_get_field(&(In[0]), fields[i]); if (!IFi) { /* no table */ G_warning(_("Layer %d - no table"), fields[i]); continue; } OFi = Vect_default_field_info(&Out, IFi->number, IFi->name, ttype); ret = db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table, OFi->driver, Vect_subst_var(OFi->database, &Out), OFi->table, IFi->key, cats[i], ncats[i]); if (ret == DB_FAILED) { G_warning(_("Layer %d - unable to copy table"), fields[i]); } else { Vect_map_add_dblink(&Out, OFi->number, OFi->name, OFi->table, IFi->key, OFi->database, OFi->driver); } } } Vect_close(&(In[0])); Vect_build(&Out); Vect_close(&Out); if (nskipped > 0) { G_warning(_("%d features without category skipped"), nskipped); } G_done_msg(_("%d features written to output."), Vect_get_num_lines(&Out)); exit(EXIT_SUCCESS); }