/*************************************************************** * * MODULE: v.to.points * * AUTHOR(S): Radim Blazek * * PURPOSE: Create points along lines * * COPYRIGHT: (C) 2002 by the GRASS Development Team * * This program is free software under the * GNU General Public License (>=v2). * Read the file COPYING that comes with GRASS * for details. * **************************************************************/ #include #include #include #include #include #include #include static int point_cat; static struct line_cats *PCats; static struct line_pnts *PPoints; static dbString stmt; static dbDriver *driver; static struct field_info *Fi; void write_point ( struct Map_info *Out, double x, double y, double z, int line_cat, double along, int table ) { char buf[2000]; G_debug ( 3, "write_point()" ); Vect_reset_line ( PPoints ); Vect_reset_cats ( PCats ); /* Write point */ Vect_append_point ( PPoints, x, y, z ); Vect_cat_set (PCats, 1, line_cat); Vect_cat_set (PCats, 2, point_cat); Vect_write_line ( Out, GV_POINT, PPoints, PCats ); /* Attributes */ if ( !table ) { db_zero_string ( &stmt ); sprintf (buf, "insert into %s values ( %d, %d, %.15g )", Fi->table, point_cat, line_cat, along ); db_append_string ( &stmt, buf); if (db_execute_immediate (driver, &stmt) != DB_OK ) { G_warning ( _("Cannot insert new row: %s"), db_get_string ( &stmt ) ); } } point_cat++; } void write_line ( struct Map_info *Out, struct line_pnts *LPoints, int cat, int vertex, int interpolate, double dmax, int table ) { if ( vertex ) { /* use line vertices */ double along; int vert; along = 0; for ( vert = 0; vert < LPoints->n_points; vert++ ) { G_debug ( 3, "vert = %d", vert ); write_point ( Out, LPoints->x[vert], LPoints->y[vert], LPoints->z[vert], cat, along, table ); if ( vert < LPoints->n_points - 1) { double dx, dy, dz, len; dx = LPoints->x[vert+1] - LPoints->x[vert]; dy = LPoints->y[vert+1] - LPoints->y[vert]; dz = LPoints->z[vert+1] - LPoints->z[vert]; len = hypot ( hypot (dx, dy), dz ); /* interpolate segment */ if ( interpolate && vert < ( LPoints->n_points - 1) ) { int i, n; double x, y, z, dlen; if ( len > dmax ) { n = len / dmax + 1; /* number of segments */ dx /= n; dy /= n; dz /= n; dlen = len / n; for ( i = 1; i < n; i++ ) { x = LPoints->x[vert] + i * dx; y = LPoints->y[vert] + i * dy; z = LPoints->z[vert] + i * dz; write_point ( Out, x, y, z, cat, along + i * dlen, table); } } } along += len; } } } else { /* do not use vertices */ int i, n; double len, dlen, along, x, y, z; len = Vect_line_length ( LPoints ); n = len / dmax + 1; /* number of segments */ dlen = len / n; /* length of segment */ G_debug ( 3, "n = %d len = %f dlen = %f", n, len, dlen ); for ( i = 0; i <= n; i++ ) { if ( i > 0 && i < n ) { along = i * dlen; Vect_point_on_line ( LPoints, along, &x, &y, &z, NULL, NULL ); } else { /* first and last vertex */ if ( i == 0 ) { along = 0; x = LPoints->x[0]; y = LPoints->y[0]; z = LPoints->z[0]; } else { /* last */ along = len; x = LPoints->x[LPoints->n_points-1]; y = LPoints->y[LPoints->n_points-1]; z = LPoints->z[LPoints->n_points-1]; } } G_debug ( 3, " i = %d along = %f", i, along ); write_point ( Out, x, y, z, cat, along, table ); } } } int main(int argc, char **argv) { int field, type; double dmax; struct Option *in_opt, *out_opt, *type_opt, *dmax_opt, *lfield_opt; struct Flag *inter_flag, *vertex_flag, *table_flag; struct GModule *module; char *mapset; struct Map_info In, Out; struct line_cats *LCats; struct line_pnts *LPoints; char buf[2000]; G_gisinit (argv[0]) ; module = G_define_module(); module->keywords = _("vector"); module->description = _("Create points along input lines."); in_opt = G_define_standard_option(G_OPT_V_INPUT); in_opt->description = _("Input map containing lines"); type_opt = G_define_standard_option(G_OPT_V_TYPE) ; type_opt->answer = "point,line,boundary,centroid"; out_opt = G_define_standard_option(G_OPT_V_OUTPUT); out_opt->description = _("Output map where points will be written"); lfield_opt = G_define_standard_option(G_OPT_V_FIELD); lfield_opt->key = "llayer"; lfield_opt->answer = "1"; lfield_opt->description = "Line layer"; vertex_flag = G_define_flag (); vertex_flag->key = 'v'; vertex_flag->description = _("Write line vertices."); inter_flag = G_define_flag (); inter_flag->key = 'i'; inter_flag->description = _("Interpolate points between line vertices."); dmax_opt = G_define_option (); dmax_opt->key = "dmax"; dmax_opt->type = TYPE_DOUBLE; dmax_opt->required = NO; dmax_opt->answer = "100"; dmax_opt->description = _("Maximum distance between points in map units."); 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); LCats = Vect_new_cats_struct (); PCats = Vect_new_cats_struct (); LPoints = Vect_new_line_struct (); PPoints = Vect_new_line_struct (); db_init_string (&stmt); field = atoi (lfield_opt->answer); type = Vect_option_to_types ( type_opt ); dmax = atof ( dmax_opt->answer ); Vect_check_input_output_name ( in_opt->answer, out_opt->answer, GV_FATAL_EXIT ); /* Open input lines */ mapset = G_find_vector2 (in_opt->answer, NULL); if(mapset == NULL) G_fatal_error ( _("Could not find input %s\n"), in_opt->answer); Vect_set_open_level ( 2 ); Vect_open_old (&In, in_opt->answer, mapset); /* Open output segments */ Vect_open_new ( &Out, out_opt->answer, Vect_is_3d (&In) ); Vect_copy_head_data (&In, &Out); Vect_hist_copy (&In, &Out); Vect_hist_command ( &Out ); /* Table */ if ( !table_flag->answer ) { struct field_info *Fin; /* copy input table */ Fin = Vect_get_field ( &In, field ); if ( Fin ) { /* table defined */ int ret; Fi = Vect_default_field_info ( &Out, 1, NULL, GV_MTABLE ); Vect_map_add_dblink ( &Out, 1, NULL, Fi->table, Fin->key, Fi->database, Fi->driver); ret = db_copy_table ( Fin->driver, Fin->database, Fin->table, Fi->driver, Vect_subst_var(Fi->database,&Out), Fi->table ); if ( ret == DB_FAILED ) { G_fatal_error ( _("Cannot copy table") ); } } Fi = Vect_default_field_info ( &Out, 2, NULL, GV_MTABLE ); Vect_map_add_dblink ( &Out, 2, NULL, Fi->table, "cat", Fi->database, Fi->driver); /* Open driver */ driver = db_start_driver_open_database ( Fi->driver, Fi->database ); if ( driver == NULL ) G_fatal_error ( _("Cannot open database %s by driver %s"), Fi->database, Fi->driver ); sprintf ( buf, "create table %s ( cat int, lcat int, along double precision )", Fi->table ); db_append_string ( &stmt, buf); if (db_execute_immediate (driver, &stmt) != DB_OK ) { db_close_database_shutdown_driver ( driver ); G_fatal_error ( _("Cannot create table: %s"), db_get_string ( &stmt ) ); } if ( db_create_index2(driver, Fi->table, "cat" ) != DB_OK ) G_warning ( _("Cannot create index") ); if (db_grant_on_table (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP|DB_PUBLIC ) != DB_OK ) G_fatal_error ( _("Cannot grant privileges on table %s"), Fi->table ); db_begin_transaction ( driver ); } point_cat = 1; if ( type & (GV_POINTS | GV_LINES) ) { int line, nlines; nlines = Vect_get_num_lines (&In); for ( line = 1; line <= nlines; line++ ) { int ltype, cat; G_debug ( 3, "line = %d", line ); ltype = Vect_read_line (&In, LPoints, LCats, line); if ( !(ltype & type ) ) continue; Vect_cat_get ( LCats, field, &cat ); if ( LPoints->n_points <= 1 ) { write_point ( &Out, LPoints->x[0], LPoints->y[0], LPoints->z[0], cat, 0.0, table_flag->answer); } else { /* lines */ write_line ( &Out, LPoints, cat, vertex_flag->answer, inter_flag->answer, dmax, table_flag->answer ); } } } if ( type == GV_AREA ) { int area, nareas, centroid, cat; nareas = Vect_get_num_areas (&In); for ( area = 1; area <= nareas; area++ ) { int i, isle, nisles; centroid = Vect_get_area_centroid ( &In, area ); cat = -1; if ( centroid > 0 ) { Vect_read_line (&In, NULL, LCats, centroid ); Vect_cat_get (LCats, field, &cat); } Vect_get_area_points ( &In, area, LPoints ); write_line ( &Out, LPoints, cat, vertex_flag->answer, inter_flag->answer, dmax, table_flag->answer ); nisles = Vect_get_area_num_isles (&In, area); for ( i = 0; i < nisles; i++ ) { isle = Vect_get_area_isle (&In, area, i); Vect_get_isle_points ( &In, isle, LPoints ); write_line ( &Out, LPoints, cat, vertex_flag->answer, inter_flag->answer, dmax, table_flag->answer ); } } } if ( !table_flag->answer ) { db_commit_transaction ( driver ); db_close_database_shutdown_driver ( driver ); } Vect_build (&Out, stderr); /* Free, close ... */ Vect_close(&In); Vect_close(&Out); G_message ( _("%d points written to output map\n"), point_cat - 1); exit(EXIT_SUCCESS); }