int QgsGrassVectorMapLayer::cidxFieldNumCats() { if ( !mMap->map() || cidxFieldIndex() < 0 ) { return 0; } return Vect_cidx_get_num_cats_by_index( mMap->map(), cidxFieldIndex() ); }
/*! \brief Write (dump) category index in text form to file \param Map pointer to Map_info structure \param[out] out output file \return 1 on success \return 0 on error */ int Vect_cidx_dump(const struct Map_info *Map, FILE * out) { int i, field, nfields, ntypes; G_debug(2, "Vect_cidx_dump()"); check_status(Map); nfields = Vect_cidx_get_num_fields(Map); fprintf(out, "---------- CATEGORY INDEX DUMP: Number of layers: %d " "--------------------------------------\n", nfields); for (i = 0; i < nfields; i++) { int j, nucats, ncats; field = Vect_cidx_get_field_number(Map, i); nucats = Vect_cidx_get_num_unique_cats_by_index(Map, i); ncats = Vect_cidx_get_num_cats_by_index(Map, i); ntypes = Vect_cidx_get_num_types_by_index(Map, i); fprintf(out, "Layer %6d number of unique cats: %7d number of " "cats: %7d number of types: %d\n", field, nucats, ncats, ntypes); fprintf(out, SEP); fprintf(out, " type | count\n"); for (j = 0; j < ntypes; j++) { int type, count; Vect_cidx_get_type_count_by_index(Map, i, j, &type, &count); fprintf(out, " %5d | %9d\n", type, count); } fprintf(out, " category | type | line/area\n"); for (j = 0; j < ncats; j++) { int cat, type, id; Vect_cidx_get_cat_by_index(Map, i, j, &cat, &type, &id); fprintf(out, "%9d | %4d | %9d\n", cat, type, id); } fprintf(out, SEP); } return 1; }
void QgsGrassVectorMapLayer::load() { clear(); if ( !mMap ) { return; } // Attributes are not loaded for topo layers in which case field == 0 if ( mField == 0 ) { return; } QgsDebugMsg( QString( "cidxFieldIndex() = %1 cidxFieldNumCats() = %2" ).arg( cidxFieldIndex() ).arg( cidxFieldNumCats() ) ); mFieldInfo = Vect_get_field( mMap->map(), mField ); // should work also with field = 0 if ( !mFieldInfo ) { QgsDebugMsg( "No field info -> no attribute table" ); } else { QgsDebugMsg( "Field info found -> open database" ); QFileInfo di( mMap->grassObject().mapsetPath() + "/vector/" + mMap->grassObject().name() + "/dbln" ); mLastLoaded = di.lastModified(); QString error; dbDriver *databaseDriver = openDriver( error ); if ( !databaseDriver || !error.isEmpty() ) { QgsDebugMsg( error ); } else { QgsDebugMsg( "Database opened -> open select cursor" ); QgsGrass::lock(); // not sure if lock is necessary dbString dbstr; db_init_string( &dbstr ); db_set_string( &dbstr, ( char * )"select * from " ); db_append_string( &dbstr, mFieldInfo->table ); QgsDebugMsg( QString( "SQL: %1" ).arg( db_get_string( &dbstr ) ) ); dbCursor databaseCursor; if ( db_open_select_cursor( databaseDriver, &dbstr, &databaseCursor, DB_SCROLL ) != DB_OK ) { db_close_database_shutdown_driver( databaseDriver ); QgsGrass::warning( "Cannot select attributes from table '" + QString( mFieldInfo->table ) + "'" ); } else { #ifdef QGISDEBUG int nRecords = db_get_num_rows( &databaseCursor ); QgsDebugMsg( QString( "Number of records: %1" ).arg( nRecords ) ); #endif dbTable *databaseTable = db_get_cursor_table( &databaseCursor ); int nColumns = db_get_table_number_of_columns( databaseTable ); // Read columns' description for ( int i = 0; i < nColumns; i++ ) { QPair<double, double> minMax( DBL_MAX, -DBL_MAX ); dbColumn *column = db_get_table_column( databaseTable, i ); int ctype = db_sqltype_to_Ctype( db_get_column_sqltype( column ) ); QVariant::Type qtype = QVariant::String; //default to string QgsDebugMsg( QString( "column = %1 ctype = %2" ).arg( db_get_column_name( column ) ).arg( ctype ) ); QString ctypeStr; switch ( ctype ) { case DB_C_TYPE_INT: ctypeStr = QStringLiteral( "integer" ); qtype = QVariant::Int; break; case DB_C_TYPE_DOUBLE: ctypeStr = QStringLiteral( "double" ); qtype = QVariant::Double; break; case DB_C_TYPE_STRING: ctypeStr = QStringLiteral( "string" ); qtype = QVariant::String; break; case DB_C_TYPE_DATETIME: ctypeStr = QStringLiteral( "datetime" ); qtype = QVariant::String; break; } mTableFields.append( QgsField( db_get_column_name( column ), qtype, ctypeStr, db_get_column_length( column ), db_get_column_precision( column ) ) ); mMinMax << minMax; if ( G_strcasecmp( db_get_column_name( column ), mFieldInfo->key ) == 0 ) { mKeyColumn = i; } } if ( mKeyColumn < 0 ) { mTableFields.clear(); QgsGrass::warning( QObject::tr( "Key column '%1' not found in the table '%2'" ).arg( mFieldInfo->key, mFieldInfo->table ) ); } else { mHasTable = true; // Read attributes to the memory for ( ;; ) { int more; if ( db_fetch( &databaseCursor, DB_NEXT, &more ) != DB_OK ) { QgsDebugMsg( "Cannot fetch DB record" ); break; } if ( !more ) { break; // no more records } // Check cat value dbColumn *column = db_get_table_column( databaseTable, mKeyColumn ); dbValue *value = db_get_column_value( column ); if ( db_test_value_isnull( value ) ) { continue; } int cat = db_get_value_int( value ); if ( cat < 0 ) { continue; } QList<QVariant> values; for ( int i = 0; i < nColumns; i++ ) { column = db_get_table_column( databaseTable, i ); int sqltype = db_get_column_sqltype( column ); int ctype = db_sqltype_to_Ctype( sqltype ); value = db_get_column_value( column ); db_convert_value_to_string( value, sqltype, &dbstr ); QgsDebugMsgLevel( QString( "column = %1 value = %2" ).arg( db_get_column_name( column ), db_get_string( &dbstr ) ), 3 ); QVariant variant; if ( !db_test_value_isnull( value ) ) { int iv; double dv; //layer.mAttributes[layer.nAttributes].values[i] = strdup( db_get_string( &dbstr ) ); switch ( ctype ) { case DB_C_TYPE_INT: iv = db_get_value_int( value ); variant = QVariant( iv ); mMinMax[i].first = std::min( mMinMax[i].first, ( double )iv ); mMinMax[i].second = std::min( mMinMax[i].second, ( double )iv ); break; case DB_C_TYPE_DOUBLE: dv = db_get_value_double( value ); variant = QVariant( dv ); mMinMax[i].first = std::min( mMinMax[i].first, dv ); mMinMax[i].second = std::min( mMinMax[i].second, dv ); break; case DB_C_TYPE_STRING: // Store as byte array so that codec may be used later variant = QVariant( QByteArray( db_get_value_string( value ) ) ); break; case DB_C_TYPE_DATETIME: variant = QVariant( QByteArray( db_get_string( &dbstr ) ) ); break; default: variant = QVariant( QByteArray( db_get_string( &dbstr ) ) ); } } QgsDebugMsgLevel( QString( "column = %1 variant = %2" ).arg( db_get_column_name( column ), variant.toString() ), 3 ); values << variant; } mAttributes.insert( cat, values ); } } mValid = true; db_close_cursor( &databaseCursor ); db_close_database_shutdown_driver( databaseDriver ); db_free_string( &dbstr ); QgsDebugMsg( QString( "mTableFields.size = %1" ).arg( mTableFields.size() ) ); QgsDebugMsg( QString( "number of attributes = %1" ).arg( mAttributes.size() ) ); } QgsGrass::unlock(); } } // Add cat if no attribute fields exist (otherwise qgis crashes) if ( mTableFields.size() == 0 ) { mKeyColumn = 0; mTableFields.append( QgsField( QStringLiteral( "cat" ), QVariant::Int, QStringLiteral( "integer" ) ) ); QPair<double, double> minMax( 0, 0 ); if ( cidxFieldIndex() >= 0 ) { int ncats, cat, type, id; ncats = Vect_cidx_get_num_cats_by_index( mMap->map(), cidxFieldIndex() ); if ( ncats > 0 ) { Vect_cidx_get_cat_by_index( mMap->map(), cidxFieldIndex(), 0, &cat, &type, &id ); minMax.first = cat; Vect_cidx_get_cat_by_index( mMap->map(), cidxFieldIndex(), ncats - 1, &cat, &type, &id ); minMax.second = cat; } } mMinMax << minMax; } mFields = mTableFields; mAttributeFields = mTableFields; QgsDebugMsg( QString( "layer loaded mTableFields.size() = %1 mAttributes.size() = %2" ).arg( mTableFields.size() ).arg( mAttributes.size() ) ); mValid = true; }
int main(int argc, char *argv[]) { struct GModule *module; struct Option *in_opt, *out_opt, *feature_opt, *column_name; struct Flag *smooth_flg, *value_flg, *z_flg, *no_topol; int feature; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("raster")); G_add_keyword(_("conversion")); G_add_keyword(_("geometry")); G_add_keyword(_("vectorization")); module->description = _("Converts a raster map into a vector map."); in_opt = G_define_standard_option(G_OPT_R_INPUT); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); feature_opt = G_define_standard_option(G_OPT_V_TYPE); feature_opt->required = YES; feature_opt->multiple = NO; feature_opt->options = "point,line,area"; feature_opt->answer = NULL; column_name = G_define_standard_option(G_OPT_DB_COLUMN); column_name->label = _("Name of attribute column to store value"); column_name->description = _("Name must be SQL compliant"); column_name->answer = "value"; smooth_flg = G_define_flag(); smooth_flg->key = 's'; smooth_flg->description = _("Smooth corners of area features"); value_flg = G_define_flag(); value_flg->key = 'v'; value_flg->description = _("Use raster values as categories instead of unique sequence (CELL only)"); value_flg->guisection = _("Attributes"); z_flg = G_define_flag(); z_flg->key = 'z'; z_flg->label = _("Write raster values as z coordinate"); z_flg->description = _("Table is not created. " "Currently supported only for points."); z_flg->guisection = _("Attributes"); no_topol = G_define_flag(); no_topol->key = 'b'; no_topol->label = _("Do not build vector topology"); no_topol->description = _("Recommended for massive point conversion"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); feature = Vect_option_to_types(feature_opt); smooth_flag = (smooth_flg->answer) ? SMOOTH : NO_SMOOTH; value_flag = value_flg->answer; if (z_flg->answer && (feature != GV_POINT)) G_fatal_error(_("z flag is supported only for points")); /* Open files */ input_fd = Rast_open_old(in_opt->answer, ""); data_type = Rast_get_map_type(input_fd); data_size = Rast_cell_size(data_type); G_get_window(&cell_head); if (value_flag && data_type != CELL_TYPE) { G_warning(_("Raster is not CELL, '-v' flag ignored, raster values will be written to the table.")); value_flag = 0; } if (z_flg->answer) Vect_open_new(&Map, out_opt->answer, 1); else Vect_open_new(&Map, out_opt->answer, 0); Vect_hist_command(&Map); Cats = Vect_new_cats_struct(); /* Open category labels */ if (data_type == CELL_TYPE) { if (0 == Rast_read_cats(in_opt->answer, "", &RastCats)) has_cats = 1; } else has_cats = 0; db_init_string(&sql); db_init_string(&label); /* Create table */ if ((feature & (GV_AREA | GV_POINT | GV_LINE)) && (!value_flag || (value_flag && has_cats)) && !(z_flg->answer)) { char buf[1000]; Fi = Vect_default_field_info(&Map, 1, NULL, GV_1TABLE); Vect_map_add_dblink(&Map, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database, Fi->driver); driver = db_start_driver_open_database(Fi->driver, Vect_subst_var(Fi->database, &Map)); if (driver == NULL) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Fi->database, Fi->driver); /* Create new table */ db_zero_string(&sql); sprintf(buf, "create table %s ( cat integer", Fi->table); db_append_string(&sql, buf); if (!value_flag) { /* add value to the table */ if (data_type == CELL_TYPE) { db_append_string(&sql, ", "); db_append_string(&sql, column_name->answer); db_append_string(&sql, " integer"); } else { db_append_string(&sql, ","); db_append_string(&sql, column_name->answer); db_append_string(&sql, " double precision"); } } if (has_cats) { int i, len; int clen = 0; /* Get maximum column length */ for (i = 0; i < RastCats.ncats; i++) { len = strlen(RastCats.labels[i]); if (len > clen) clen = len; } clen += 10; sprintf(buf, ", label varchar(%d)", clen); db_append_string(&sql, buf); } db_append_string(&sql, ")"); G_debug(3, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) G_fatal_error(_("Unable to create table: %s"), db_get_string(&sql)); if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK) G_warning(_("Unable to create index")); if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Unable to grant privileges on table <%s>"), Fi->table); db_begin_transaction(driver); } else { driver = NULL; } /* init variables for lines and areas */ first_read = 1; last_read = 0; direction = FORWARD; row_length = cell_head.cols; n_rows = cell_head.rows; row_count = 0; if (feature == GV_LINE) { alloc_lines_bufs(row_length + 2); extract_lines(); } else if (feature == GV_AREA) { alloc_areas_bufs(row_length + 2); extract_areas(); } else { /* GV_POINT */ extract_points(z_flg->answer); } Rast_close(input_fd); if (!no_topol->answer) Vect_build(&Map); /* insert cats and optionally labels if raster cats were used */ if (driver && value_flag) { char buf[1000]; int c, i, cat, fidx, ncats, lastcat, tp, id; fidx = Vect_cidx_get_field_index(&Map, 1); if (fidx >= 0) { ncats = Vect_cidx_get_num_cats_by_index(&Map, fidx); lastcat = -1; for (c = 0; c < ncats; c++) { Vect_cidx_get_cat_by_index(&Map, fidx, c, &cat, &tp, &id); if (lastcat == cat) continue; /* find label, slow -> TODO faster */ db_set_string(&label, ""); for (i = 0; i < RastCats.ncats; i++) { if (cat == (int)RastCats.q.table[i].dLow) { /* cats are in dLow/High not in cLow/High !!! */ db_set_string(&label, RastCats.labels[i]); db_double_quote_string(&label); break; } } G_debug(3, "cat = %d label = %s", cat, db_get_string(&label)); sprintf(buf, "insert into %s values ( %d, '%s')", Fi->table, cat, db_get_string(&label)); db_set_string(&sql, buf); G_debug(3, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) G_fatal_error(_("Unable to insert into table: %s"), db_get_string(&sql)); lastcat = cat; } } } if (has_cats) Rast_free_cats(&RastCats); if (driver != NULL) { db_commit_transaction(driver); db_close_database_shutdown_driver(driver); } Vect_close(&Map); G_done_msg(" "); exit(EXIT_SUCCESS); }
bool OGRGRASSLayer::SetQueryMatch() { CPLDebug ( "GRASS", "SetQueryMatch" ); // NOTE: we don't have to call ResetSequentialCursor() first because // this method is called immediately after OpenSequentialCursor() if ( !bCursorOpened ) { CPLError( CE_Failure, CPLE_AppDefined, "Cursor is not opened."); return false; } int more; int cidx = 0; // index to category index int fidx = 0; // index to feature index (paFeatureIndex) // number of categories in category index int ncats = Vect_cidx_get_num_cats_by_index ( poMap, iLayerIndex ); dbTable *table = db_get_cursor_table ( poCursor ); while ( true ) { if( db_fetch ( poCursor, DB_NEXT, &more) != DB_OK ) { CPLError( CE_Failure, CPLE_AppDefined, "Cannot fetch attributes."); return false; } if ( !more ) break; dbColumn *column = db_get_table_column ( table, iCatField ); dbValue *value = db_get_column_value ( column ); int cat = db_get_value_int ( value ); // NOTE: because of bug in GRASS library it is impossible to use // Vect_cidx_find_next // Go through category index until first record of current category // is found or a category > current is found int cidxcat, type, id; while ( cidx < ncats ) { Vect_cidx_get_cat_by_index ( poMap, iLayerIndex, cidx, &cidxcat, &type, &id ); if ( cidxcat < cat ) { cidx++; continue; } if ( cidxcat > cat ) break; // Not found // We have the category we want, check type if ( !(type & (GV_POINT|GV_LINES|GV_AREA)) ) { cidx++; continue; } // Both category and type match -> find feature and set it on while ( true ) { if ( fidx > nTotalCount || paFeatureIndex[fidx] > cidx ) { // should not happen break; } if ( paFeatureIndex[fidx] == cidx ) { paQueryMatch[fidx] = 1; fidx++; break; } fidx++; } cidx++; } if ( id < 0 ) continue; // not found } return true; }
/** * \brief Consolidate network arcs (edge) based on given point vector map (nodes) * * If there is no connection between network edge and point, new edge * is added, the line broken, and new point added to nfield layer * * \param In,Points input vector maps * \param Out output vector map * \param nfield nodes layer * \param thresh threshold value to find neareast line * * \return number of new arcs */ int connect_arcs(struct Map_info *In, struct Map_info *Pnts, struct Map_info *Out, int afield, int nfield, double thresh, int snap) { int narcs; int type, line, seg, i, ltype, broken; double px, py, pz, spdist, dist; struct line_pnts *Points, *Pline, *Pout; struct line_cats *Cats, *Cline, *Cnew; int maxcat, findex, ncats; narcs = 0; Points = Vect_new_line_struct(); Pline = Vect_new_line_struct(); Pout = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); Cline = Vect_new_cats_struct(); Cnew = Vect_new_cats_struct(); /* rewrite all primitives to output file */ Vect_copy_map_lines(In, Out); Vect_build_partial(Out, GV_BUILD_BASE); findex = Vect_cidx_get_field_index(In, afield); ncats = Vect_cidx_get_num_cats_by_index(In, findex); Vect_cidx_get_cat_by_index(In, findex, ncats - 1, &maxcat, &type, &line); /* go thorough all points in point map and write a new arcs if missing */ while ((type = Vect_read_next_line(Pnts, Points, Cats)) >= 0) { if (type != GV_POINT) continue; /* find the nearest line in given threshold */ line = Vect_find_line(Out, Points->x[0], Points->y[0], Points->z[0], GV_LINES, thresh, WITHOUT_Z, 0); if (line < 1 || !Vect_line_alive(Out, line)) continue; ltype = Vect_read_line(Out, Pline, Cline, line); /* find point on the line */ seg = Vect_line_distance(Pline, Points->x[0], Points->y[0], Points->z[0], WITHOUT_Z, &px, &py, &pz, &dist, &spdist, NULL); if (seg == 0) G_fatal_error(_("Failed to find intersection segment")); /* break the line */ broken = 0; Vect_reset_line(Pout); for (i = 0; i < seg; i++) { Vect_append_point(Pout, Pline->x[i], Pline->y[i], Pline->z[i]); } Vect_append_point(Pout, px, py, pz); Vect_line_prune(Pout); if (Pout->n_points > 1) { Vect_rewrite_line(Out, line, ltype, Pout, Cline); broken++; } Vect_reset_line(Pout); Vect_append_point(Pout, px, py, pz); for (i = seg; i < Pline->n_points; i++) { Vect_append_point(Pout, Pline->x[i], Pline->y[i], Pline->z[i]); } Vect_line_prune(Pout); if (Pout->n_points > 1) { if (broken) Vect_write_line(Out, ltype, Pout, Cline); else Vect_rewrite_line(Out, line, ltype, Pout, Cline); broken++; } if (broken == 2) narcs++; if (dist > 0.0) { if (snap) { /* snap point */ Points->x[0] = px; Points->y[0] = py; Points->z[0] = pz; } else { /* write new arc */ Vect_reset_line(Pout); Vect_append_point(Pout, px, py, pz); Vect_append_point(Pout, Points->x[0], Points->y[0], Points->z[0]); maxcat++; Vect_reset_cats(Cnew); Vect_cat_set(Cnew, afield, maxcat); Vect_write_line(Out, ltype, Pout, Cnew); narcs++; } } /* add points to 'nfield' layer */ for (i = 0; i < Cats->n_cats; i++) { Cats->field[i] = nfield; /* all points to 'nfield' layer */ } Vect_write_line(Out, type, Points, Cats); } Vect_destroy_line_struct(Points); Vect_destroy_line_struct(Pline); Vect_destroy_line_struct(Pout); Vect_destroy_cats_struct(Cats); Vect_destroy_cats_struct(Cline); Vect_destroy_cats_struct(Cnew); return narcs; }
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); }
/* TODO: The collection of categories is horrible in current version! * Everything repeats many times. We need some data structure * implementing set! */ int copy_tables_by_cats(struct Map_info *In, struct Map_info *Out) { /* this is the (mostly) code from v.extract, it should be moved to * some vector library (probably) */ int nlines, line, nfields; int ttype, ntabs = 0; struct field_info *IFi, *OFi; struct line_cats *Cats; int **ocats, *nocats, *fields; int i; /* Collect list of output cats */ Cats = Vect_new_cats_struct(); nfields = Vect_cidx_get_num_fields(In); ocats = (int **)G_malloc(nfields * sizeof(int *)); nocats = (int *)G_malloc(nfields * sizeof(int)); fields = (int *)G_malloc(nfields * sizeof(int)); for (i = 0; i < nfields; i++) { nocats[i] = 0; ocats[i] = (int *)G_malloc(Vect_cidx_get_num_cats_by_index(In, i) * sizeof(int)); fields[i] = Vect_cidx_get_field_number(In, i); } nlines = Vect_get_num_lines(Out); for (line = 1; line <= nlines; line++) { Vect_read_line(Out, NULL, Cats, line); for (i = 0; i < Cats->n_cats; i++) { int f = 0, j; for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == Cats->field[i]) { f = j; break; } } ocats[f][nocats[f]] = Cats->cat[i]; nocats[f]++; } } /* Copy tables */ G_message(_("Writing attributes...")); /* Number of output tabs */ for (i = 0; i < Vect_get_num_dblinks(In); i++) { int j, f = -1; IFi = Vect_get_dblink(In, i); for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == IFi->number) { f = j; break; } } if (f >= 0 && nocats[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; if (nocats[i] == 0) continue; /* if ( fields[i] == field && new_cat != -1 ) continue; */ G_message(_("Layer %d"), fields[i]); /* Make a list of categories */ IFi = Vect_get_field(In, fields[i]); if (!IFi) { /* no table */ G_warning(_("Database connection not defined for layer %d"), 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, ocats[i], nocats[i]); if (ret == DB_FAILED) { G_warning(_("Unable to copy table <%s>"), IFi->table); } else { Vect_map_add_dblink(Out, OFi->number, OFi->name, OFi->table, IFi->key, OFi->database, OFi->driver); } } for (i = 0; i < nfields; i++) G_free(ocats[i]); G_free(ocats); G_free(nocats); G_free(fields); 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); }