/* create paths for area and islands */ static int plot_area(struct Map_info *P_map, int area, double shift) { struct line_pnts *Points; int j, ret, ni, island; /* allocate memory for coordinates */ Points = Vect_new_line_struct(); /* plot areas */ if (0 > (ret = Vect_get_area_points(P_map, area, Points))) { if (ret == -1) G_warning(_("Read error in vector map")); return 0; } construct_path(Points, shift, WHOLE_PATH); /* plot islands */ ni = Vect_get_area_num_isles(P_map, area); for (j = 0; j < ni; j++) { island = Vect_get_area_isle(P_map, area, j); if (0 > (ret = Vect_get_isle_points(P_map, island, Points))) { if (ret == -1) G_warning(_("Read error in vector map")); return -1; } construct_path(Points, shift, WHOLE_PATH); } return 1; }
OGRGeometryH create_polygon(struct Map_info *In, int area, struct line_pnts *Points) { int j, k; OGRGeometryH Ogr_geometry, ring; Vect_get_area_points(In, area, Points); Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon); ring = OGR_G_CreateGeometry(wkbLinearRing); /* Area */ for (j = 0; j < Points->n_points; j++) { OGR_G_AddPoint(ring, Points->x[j], Points->y[j], Points->z[j]); } OGR_G_AddGeometryDirectly(Ogr_geometry, ring); /* Isles */ for (k = 0; k < Vect_get_area_num_isles(In, area); k++) { Vect_get_isle_points(In, Vect_get_area_isle(In, area, k), Points); ring = OGR_G_CreateGeometry(wkbLinearRing); for (j = 0; j < Points->n_points; j++) { OGR_G_AddPoint(ring, Points->x[j], Points->y[j], Points->z[j]); } OGR_G_AddGeometryDirectly(Ogr_geometry, ring); } return Ogr_geometry; }
/*! \brief Creates buffer around area. \param Map vector map \param area area id \param da distance along major axis \param db distance along minor axis \param dalpha angle between 0x and major axis \param round make corners round \param caps add caps at line ends \param tol maximum distance between theoretical arc and output segments \param[out] oPoints output polygon outer border (ccw order) \param[out] inner_count number of holes \param[out] iPoints array of output polygon's holes (cw order) */ void Vect_area_buffer2(struct Map_info *Map, int area, double da, double db, double dalpha, int round, int caps, double tol, struct line_pnts **oPoints, struct line_pnts ***iPoints, int *inner_count) { struct line_pnts *tPoints, *outer; struct line_pnts **isles; int isles_count = 0, n_isles; int i, isle; int more = 8; int isles_allocated = 0; G_debug(2, "Vect_area_buffer()"); /* initializations */ tPoints = Vect_new_line_struct(); n_isles = Vect_get_area_num_isles(Map, area); isles_allocated = n_isles; isles = G_malloc(isles_allocated * sizeof(struct line_pnts *)); /* outer contour */ outer = Vect_new_line_struct(); Vect_get_area_points(Map, area, outer); /* does not work with zero length line segments */ Vect_line_prune(outer); /* inner contours */ for (i = 0; i < n_isles; i++) { isle = Vect_get_area_isle(Map, area, i); Vect_get_isle_points(Map, isle, tPoints); /* Check if the isle is big enough */ /* if (Vect_line_length(tPoints) < 2*PI*max) continue; */ /* does not work with zero length line segments */ Vect_line_prune(tPoints); add_line_to_array(tPoints, &isles, &isles_count, &isles_allocated, more); tPoints = Vect_new_line_struct(); } buffer_lines(outer, isles, isles_count, 0, da, db, dalpha, round, caps, tol, oPoints, iPoints, inner_count); Vect_destroy_line_struct(tPoints); Vect_destroy_line_struct(outer); destroy_lines_array(isles, isles_count); return; }
/*! \brief Draw area */ void draw_area(struct Map_info *Map, int area, struct robject_list *list) { int i, centroid, isle; int num_isles; struct line_pnts *ipoints; struct robject *robj; if (!state.Points) state.Points = Vect_new_line_struct(); if (!Vect_area_alive(Map, area)) return; /* check for other centroids -- only area with one centroid is valid */ centroid = Vect_get_area_centroid(Map, area); if (centroid <= 0) return; ipoints = Vect_new_line_struct(); /* get area's boundary */ Vect_get_area_points(Map, area, state.Points); robj = robj_alloc(TYPE_AREA, state.Points->n_points); robj_points(robj, state.Points); list_append(list, robj); /* check for isles */ num_isles = Vect_get_area_num_isles(Map, area); for (i = 0; i < num_isles; i++) { isle = Vect_get_area_isle(Map, area, i); if (!Vect_isle_alive(Map, isle)) continue; Vect_get_isle_points(Map, isle, ipoints); robj = robj_alloc(TYPE_ISLE, ipoints->n_points); robj_points(robj, ipoints); list_append(list, robj); } Vect_destroy_line_struct(ipoints); }
void QgsGrassFeatureIterator::setFeatureGeometry( QgsFeature& feature, int id, int type ) { unsigned char *wkb; int wkbsize; // TODO int may be 64 bits (memcpy) if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) || mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) /* points or lines */ { if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { double x, y, z; Vect_get_node_coor( mSource->mMap, id, &x, &y, &z ); Vect_reset_line( mPoints ); Vect_append_point( mPoints, x, y, z ); } else { Vect_read_line( mSource->mMap, mPoints, 0, id ); } int npoints = mPoints->n_points; if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { wkbsize = 1 + 4 + 2 * 8; } else if ( type & GV_POINTS ) { wkbsize = 1 + 4 + 2 * 8; } else if ( type & GV_LINES ) { wkbsize = 1 + 4 + 4 + npoints * 2 * 8; } else // GV_FACE { wkbsize = 1 + 4 + 4 + 4 + npoints * 2 * 8; } wkb = new unsigned char[wkbsize]; unsigned char *wkbp = wkb; wkbp[0] = ( unsigned char ) QgsApplication::endian(); wkbp += 1; /* WKB type */ memcpy( wkbp, &mSource->mQgisType, 4 ); wkbp += 4; /* Number of rings */ if ( type & GV_FACE ) { int nrings = 1; memcpy( wkbp, &nrings, 4 ); wkbp += 4; } /* number of points */ if ( type & ( GV_LINES | GV_FACE ) ) { QgsDebugMsg( QString( "set npoints = %1" ).arg( npoints ) ); memcpy( wkbp, &npoints, 4 ); wkbp += 4; } for ( int i = 0; i < npoints; i++ ) { memcpy( wkbp, &( mPoints->x[i] ), 8 ); memcpy( wkbp + 8, &( mPoints->y[i] ), 8 ); wkbp += 16; } } else // GV_AREA { Vect_get_area_points( mSource->mMap, id, mPoints ); int npoints = mPoints->n_points; wkbsize = 1 + 4 + 4 + 4 + npoints * 2 * 8; // size without islands wkb = new unsigned char[wkbsize]; wkb[0] = ( unsigned char ) QgsApplication::endian(); int offset = 1; /* WKB type */ memcpy( wkb + offset, &mSource->mQgisType, 4 ); offset += 4; /* Number of rings */ int nisles = Vect_get_area_num_isles( mSource->mMap, id ); int nrings = 1 + nisles; memcpy( wkb + offset, &nrings, 4 ); offset += 4; /* Outer ring */ memcpy( wkb + offset, &npoints, 4 ); offset += 4; for ( int i = 0; i < npoints; i++ ) { memcpy( wkb + offset, &( mPoints->x[i] ), 8 ); memcpy( wkb + offset + 8, &( mPoints->y[i] ), 8 ); offset += 16; } /* Isles */ for ( int i = 0; i < nisles; i++ ) { Vect_get_isle_points( mSource->mMap, Vect_get_area_isle( mSource->mMap, id, i ), mPoints ); npoints = mPoints->n_points; // add space wkbsize += 4 + npoints * 2 * 8; wkb = ( unsigned char * ) realloc( wkb, wkbsize ); memcpy( wkb + offset, &npoints, 4 ); offset += 4; for ( int i = 0; i < npoints; i++ ) { memcpy( wkb + offset, &( mPoints->x[i] ), 8 ); memcpy( wkb + offset + 8, &( mPoints->y[i] ), 8 ); offset += 16; } } } feature.setGeometryAndOwnership( wkb, wkbsize ); }
int main(int argc, char *argv[]) { int i, j, precision, field, type, nlines; int do_attr = 0, attr_cols[8], attr_size = 0, db_open = 0, cnt = 0; double width, radius; struct Option *in_opt, *out_opt, *prec_opt, *type_opt, *attr_opt, *field_opt; struct GModule *module; struct Map_info In; struct bound_box box; /* vector */ struct line_pnts *Points; struct line_cats *Cats; /* attribs */ dbDriver *Driver = NULL; dbHandle handle; dbTable *Table; dbString dbstring; struct field_info *Fi; /* init */ G_gisinit(argv[0]); /* parse command-line */ module = G_define_module(); module->description = _("Exports a vector map to SVG file."); G_add_keyword(_("vector")); G_add_keyword(_("export")); in_opt = G_define_standard_option(G_OPT_V_INPUT); field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL); out_opt = G_define_standard_option(G_OPT_F_OUTPUT); out_opt->description = _("Name for SVG output file"); type_opt = G_define_option(); type_opt->key = "type"; type_opt->type = TYPE_STRING; type_opt->required = YES; type_opt->multiple = NO; type_opt->answer = "poly"; type_opt->options = "poly,line,point"; type_opt->label = _("Output type"); type_opt->description = _("Defines which feature-type will be extracted"); prec_opt = G_define_option(); prec_opt->key = "precision"; prec_opt->type = TYPE_INTEGER; prec_opt->required = NO; prec_opt->answer = "6"; prec_opt->multiple = NO; prec_opt->description = _("Coordinate precision"); attr_opt = G_define_standard_option(G_OPT_DB_COLUMNS); attr_opt->key = "attribute"; attr_opt->required = NO; attr_opt->multiple = YES; attr_opt->description = _("Attribute(s) to include in output SVG"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); if (type_opt->answer[0] == 'l') { type = TYPE_LINE; } else { if (type_opt->answer[2] == 'l') type = TYPE_POLY; else type = TYPE_POINT; } /* override coordinate precision if any */ precision = atof(prec_opt->answer); if (precision < 0) { G_fatal_error(_("Precision must not be negative")); } if (precision > 15) { G_fatal_error(_("Precision must not be higher than 15")); } /* open input vector */ Vect_set_open_level(2); if (Vect_open_old2(&In, in_opt->answer, "", field_opt->answer) < 0) G_fatal_error(_("Unable to open vector map <%s>"), in_opt->answer); /* parse field number */ field = Vect_get_field_number(&In, field_opt->answer); /* open db-driver to attribs */ db_init_string(&dbstring); /* check for requested field */ Fi = Vect_get_field(&In, field); if (Fi != NULL) { Driver = db_start_driver(Fi->driver); if (Driver == NULL) { G_fatal_error(_("Unable to start driver <%s>"), Fi->driver); } /* open db */ db_init_handle(&handle); db_set_handle(&handle, Fi->database, NULL); if (db_open_database(Driver, &handle) != DB_OK) { G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Fi->database, Fi->driver); } db_set_string(&dbstring, Fi->table); if (db_describe_table(Driver, &dbstring, &Table) != DB_OK) { G_fatal_error(_("Unable to describe table <%s>"), Fi->table); } /* define column-indices for columns to extract */ dbColumn *Column; for (i = 0; i < db_get_table_number_of_columns(Table); i++) { Column = db_get_table_column(Table, i); if (attr_opt->answer != NULL) { for (j = 0; attr_opt->answers[j] != NULL; j++) { if (G_strcasecmp(attr_opt->answers[j], db_get_column_name(Column)) == 0) { attr_cols[attr_size] = i; attr_size += 1; break; } } } } do_attr = 1; db_open = 1; } /* parse bounding box and define default stroke-width, radius */ Vect_get_map_box(&In, &box); if ((box.E - box.W) >= (box.N - box.S)) { radius = (box.E - box.W) * RADIUS_SCALE; width = (box.E - box.W) * WIDTH_SCALE; } else { radius = (box.N - box.S) * RADIUS_SCALE; width = (box.N - box.S) * WIDTH_SCALE; } /* open output SVG-file and print SVG-header with viewBox and Namenspaces */ if ((fpsvg = fopen(out_opt->answer, "w")) == NULL) { G_fatal_error(_("Unable to create SVG file <%s>"), out_opt->answer); } fprintf(fpsvg, "<svg xmlns=\"%s\" xmlns:xlink=\"%s\" xmlns:gg=\"%s\" ", SVG_NS, XLINK_NS, GRASS_NS); fprintf(fpsvg, "viewBox=\"%.*f %.*f %.*f %.*f\">\n", precision, box.W, precision, box.N * -1, precision, box.E - box.W, precision, box.N - box.S); fprintf(fpsvg, "<title>v.out.svg %s %s</title>\n", in_opt->answer, out_opt->answer); nlines = Vect_get_num_lines(&In); /* extract areas if any or requested */ if (type == TYPE_POLY) { if (Vect_get_num_areas(&In) == 0) { G_warning(_("No areas found, skipping %s"), "type=poly"); } else { int nareas; nareas = Vect_get_num_areas(&In); /* extract area as paths */ fprintf(fpsvg, " <g id=\"%s\" fill=\"#CCC\" stroke=\"#000\" stroke-width=\"%.*f\" >\n", G_Areas, precision, width); for (i = 1; i <= nareas; i++) { G_percent(i, nareas, 5); /* skip areas without centroid */ if (Vect_get_area_centroid(&In, i) == 0) { G_warning(_("Skipping area %d without centroid"), i); continue; } /* extract attribs, parse area */ Vect_get_area_cats(&In, i, Cats); fprintf(fpsvg, " <path "); if (Cats->n_cats > 0) { mk_attribs(Cats->cat[0], Fi, Driver, Table, attr_cols, attr_size, do_attr); } fprintf(fpsvg, "d=\""); Vect_get_area_points(&In, i, Points); mk_path(Points, precision); /* append islands if any within current path */ for (j = 0; j < Vect_get_area_num_isles(&In, i); j++) { Vect_get_isle_points(&In, Vect_get_area_isle(&In, i, j), Points); mk_path(Points, precision); } fprintf(fpsvg, "\" />\n"); cnt += 1; } fprintf(fpsvg, " </g>\n"); G_message(_("%d areas extracted"), cnt); } } /* extract points if requested */ if (type == TYPE_POINT) { if (Vect_get_num_primitives(&In, GV_POINTS) == 0) { G_warning(_("No points found, skipping %s"), "type=point"); } else { /* extract points as circles */ fprintf(fpsvg, " <g id=\"%s\" fill=\"#FC0\" stroke=\"#000\" " "stroke-width=\"%.*f\" >\n", G_Points, precision, width); for (i = 1; i <= nlines; i++) { G_percent(i, nlines, 5); if (!(Vect_read_line(&In, Points, Cats, i) & GV_POINTS)) continue; if (field != -1 && !Vect_cat_get(Cats, field, NULL)) continue; for (j = 0; j < Points->n_points; j++) { fprintf(fpsvg, " <circle "); if (Cats->n_cats > 0) { mk_attribs(Cats->cat[j], Fi, Driver, Table, attr_cols, attr_size, do_attr); } fprintf(fpsvg, "cx=\"%.*f\" cy=\"%.*f\" r=\"%.*f\" />\n", precision, Points->x[j], precision, Points->y[j] * -1, precision, radius); cnt += 1; } } fprintf(fpsvg, " </g>\n"); G_message(_("%d points extracted"), cnt); } } /* extract lines if requested */ if (type == TYPE_LINE) { if (Vect_get_num_primitives(&In, GV_LINES) == 0) { G_warning(_("No lines found, skipping %s"), "type=line"); } else { /* extract lines as paths */ fprintf(fpsvg, " <g id=\"%s\" fill=\"none\" stroke=\"#000\" " "stroke-width=\"%.*f\" >\n", G_Lines, precision, width); for (i = 1; i <= nlines; i++) { G_percent(i, nlines, 5); if (!(Vect_read_line(&In, Points, Cats, i) & GV_LINES)) continue; if (field != -1 && !Vect_cat_get(Cats, field, NULL)) continue; fprintf(fpsvg, " <path "); if (Cats->n_cats > 0) { mk_attribs(Cats->cat[0], Fi, Driver, Table, attr_cols, attr_size, do_attr); } fprintf(fpsvg, "d=\""); mk_path(Points, precision); fprintf(fpsvg, "\" />\n"); cnt += 1; } fprintf(fpsvg, " </g>\n"); G_message(_("%d lines extracted"), cnt); } } /* finish code */ fprintf(fpsvg, "</svg>\n"); if (db_open == 1) { /* close database handle */ db_close_database(Driver); db_shutdown_driver(Driver); } /* close SVG-file */ fclose(fpsvg); exit(EXIT_SUCCESS); }
OGRGeometry *OGRGRASSLayer::GetFeatureGeometry ( long nFeatureId, int *cat ) { CPLDebug ( "GRASS", "OGRGRASSLayer::GetFeatureGeometry nFeatureId = %d", nFeatureId ); int cidx = paFeatureIndex[(int)nFeatureId]; int type, id; Vect_cidx_get_cat_by_index ( poMap, iLayerIndex, cidx, cat, &type, &id ); //CPLDebug ( "GRASS", "cat = %d type = %d id = %d", *cat, type, id ); OGRGeometry *poOGR = NULL; int bIs3D = Vect_is_3d(poMap); switch ( type ) { case GV_POINT: { Vect_read_line ( poMap, poPoints, poCats, id); if (bIs3D) poOGR = new OGRPoint( poPoints->x[0], poPoints->y[0], poPoints->z[0] ); else poOGR = new OGRPoint( poPoints->x[0], poPoints->y[0] ); } break; case GV_LINE: case GV_BOUNDARY: { Vect_read_line ( poMap, poPoints, poCats, id); OGRLineString *poOGRLine = new OGRLineString(); if (bIs3D) poOGRLine->setPoints( poPoints->n_points, poPoints->x, poPoints->y, poPoints->z ); else poOGRLine->setPoints( poPoints->n_points, poPoints->x, poPoints->y ); poOGR = poOGRLine; } break; case GV_AREA: { Vect_get_area_points ( poMap, id, poPoints ); OGRPolygon *poOGRPoly; poOGRPoly = new OGRPolygon(); OGRLinearRing *poRing; poRing = new OGRLinearRing(); if (bIs3D) poRing->setPoints( poPoints->n_points, poPoints->x, poPoints->y, poPoints->z ); else poRing->setPoints( poPoints->n_points, poPoints->x, poPoints->y ); poOGRPoly->addRingDirectly( poRing ); // Islands int nisles = Vect_get_area_num_isles ( poMap, id ); for ( int i = 0; i < nisles; i++ ) { int isle = Vect_get_area_isle ( poMap, id, i ); Vect_get_isle_points ( poMap, isle, poPoints ); poRing = new OGRLinearRing(); if (bIs3D) poRing->setPoints( poPoints->n_points, poPoints->x, poPoints->y, poPoints->z ); else poRing->setPoints( poPoints->n_points, poPoints->x, poPoints->y ); poOGRPoly->addRingDirectly( poRing ); } poOGR = poOGRPoly; } break; default: // Should not happen { CPLError( CE_Failure, CPLE_AppDefined, "Unknown GRASS feature type."); return NULL; } } return poOGR; }
int main(int argc, char **argv) { int field, type, vertex_type; double dmax; char buf[DB_SQL_MAX]; struct { struct Option *input, *output, *type, *dmax, *lfield, *use; } opt; struct { struct Flag *table, *inter; } flag; struct GModule *module; struct Map_info In, Out; struct line_cats *LCats; struct line_pnts *LPoints; dbDriver *driver; struct field_info *Fi; dbString stmt; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("geometry")); G_add_keyword("3D"); G_add_keyword(_("node")); G_add_keyword(_("vertex")); module->description = _("Creates points along input lines in new vector map with 2 layers."); opt.input = G_define_standard_option(G_OPT_V_INPUT); opt.lfield = G_define_standard_option(G_OPT_V_FIELD); opt.lfield->key = "llayer"; opt.lfield->answer = "1"; opt.lfield->label = "Line layer number or name"; opt.lfield->guisection = _("Selection"); opt.type = G_define_standard_option(G_OPT_V3_TYPE); opt.type->answer = "point,line,boundary,centroid,face"; opt.type->guisection = _("Selection"); opt.output = G_define_standard_option(G_OPT_V_OUTPUT); opt.use = G_define_option(); opt.use->key = "use"; opt.use->type = TYPE_STRING; opt.use->required = NO; opt.use->description = _("Use line nodes or vertices only"); opt.use->options = "node,vertex"; opt.dmax = G_define_option(); opt.dmax->key = "dmax"; opt.dmax->type = TYPE_DOUBLE; opt.dmax->required = NO; opt.dmax->answer = "100"; opt.dmax->description = _("Maximum distance between points in map units"); flag.inter = G_define_flag(); flag.inter->key = 'i'; flag.inter->description = _("Interpolate points between line vertices (only for use=vertex)"); flag.table = G_define_standard_flag(G_FLG_V_TABLE); if (G_parser(argc, argv)) exit(EXIT_FAILURE); LCats = Vect_new_cats_struct(); LPoints = Vect_new_line_struct(); db_init_string(&stmt); type = Vect_option_to_types(opt.type); dmax = atof(opt.dmax->answer); vertex_type = 0; if (opt.use->answer) { if (opt.use->answer[0] == 'n') vertex_type = GV_NODE; else vertex_type = GV_VERTEX; } Vect_check_input_output_name(opt.input->answer, opt.output->answer, G_FATAL_EXIT); /* Open input lines */ Vect_set_open_level(2); if (Vect_open_old2(&In, opt.input->answer, "", opt.lfield->answer) < 0) G_fatal_error(_("Unable to open vector map <%s>"), opt.input->answer); Vect_set_error_handler_io(&In, &Out); field = Vect_get_field_number(&In, opt.lfield->answer); /* Open output segments */ if (Vect_open_new(&Out, opt.output->answer, Vect_is_3d(&In)) < 0) G_fatal_error(_("Unable to create vector map <%s>"), opt.output->answer); Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); /* Table */ Fi = NULL; if (!flag.table->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(_("Unable to copy table <%s>"), Fin->table); } } Fi = Vect_default_field_info(&Out, 2, NULL, GV_MTABLE); Vect_map_add_dblink(&Out, 2, NULL, Fi->table, GV_KEY_COLUMN, Fi->database, Fi->driver); /* Open driver */ 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); db_set_error_handler_driver(driver); if (field == -1) sprintf(buf, "create table %s ( cat int, along double precision )", Fi->table); else 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) { G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&stmt)); } if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK) G_warning(_("Unable to create index for table <%s>, key <%s>"), Fi->table, GV_KEY_COLUMN); 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); } if (type & (GV_POINTS | GV_LINES | GV_FACE)) { int line, nlines, nskipped; nskipped = 0; nlines = Vect_get_num_lines(&In); for (line = 1; line <= nlines; line++) { int ltype, cat; G_debug(3, "line = %d", line); G_percent(line, nlines, 2); ltype = Vect_read_line(&In, LPoints, LCats, line); if (!(ltype & type)) continue; if (!Vect_cat_get(LCats, field, &cat) && field != -1) { nskipped++; continue; } /* Assign CAT for layer 0 objects (i.e. boundaries) */ if (field == -1) cat = -1; if (LPoints->n_points <= 1) { write_point(&Out, LPoints->x[0], LPoints->y[0], LPoints->z[0], cat, 0.0, driver, Fi); } else { /* lines */ write_line(&Out, LPoints, cat, vertex_type, flag.inter->answer, dmax, driver, Fi); } } if (nskipped > 0) G_warning(_("%d features without category in layer <%d> skipped. " "Note that features without category (usually boundaries) are not " "skipped when '%s=-1' is given."), nskipped, field, opt.lfield->key); } 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; G_percent(area, nareas, 2); centroid = Vect_get_area_centroid(&In, area); cat = -1; if (centroid > 0) { Vect_read_line(&In, NULL, LCats, centroid); if (!Vect_cat_get(LCats, field, &cat)) continue; } Vect_get_area_points(&In, area, LPoints); write_line(&Out, LPoints, cat, vertex_type, flag.inter->answer, dmax, driver, Fi); 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_type, flag.inter->answer, dmax, driver, Fi); } } } if (!flag.table->answer) { db_commit_transaction(driver); db_close_database_shutdown_driver(driver); } Vect_build(&Out); /* Free, close ... */ Vect_close(&In); G_done_msg(_("%d points written to output vector map."), Vect_get_num_primitives(&Out, GV_POINT)); Vect_close(&Out); exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { int field, type, vertex_type; double dmax; struct Option *in_opt, *out_opt, *type_opt, *dmax_opt, *lfield_opt; struct Flag *inter_flag, *vertex_flag, *table_flag, *node_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, geometry"); module->description = _("Create points along input lines in new vector with 2 layers."); in_opt = G_define_standard_option(G_OPT_V_INPUT); in_opt->description = _("Input vector map containing lines"); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); out_opt->description = _("Output vector map where points will be written"); type_opt = G_define_standard_option(G_OPT_V_TYPE); type_opt->answer = "point,line,boundary,centroid"; lfield_opt = G_define_standard_option(G_OPT_V_FIELD); lfield_opt->key = "llayer"; lfield_opt->answer = "1"; lfield_opt->description = "Line layer"; node_flag = G_define_flag(); node_flag->key = 'n'; node_flag->description = _("Write line nodes"); 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); if (node_flag->answer && vertex_flag->answer) G_fatal_error(_("Use either -n or -v flag, not both")); if (node_flag->answer) vertex_type = GV_NODE; else if (vertex_flag->answer) vertex_type = GV_VERTEX; else vertex_type = 0; 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(_("Vector map <%s> not found"), 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(_("Unable to copy table <%s>"), Fin->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(_("Unable to 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(_("Unable to create table: '%s'"), db_get_string(&stmt)); } if (db_create_index2(driver, Fi->table, "cat") != DB_OK) G_warning(_("Unable to create index for table <%s>, key <%s>"), Fi->table, "cat"); 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); } 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_type, inter_flag->answer, dmax, table_flag->answer); } G_percent(line, nlines, 2); } } 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_type, 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_type, inter_flag->answer, dmax, table_flag->answer); } G_percent(area, nareas, 2); } } if (!table_flag->answer) { db_commit_transaction(driver); db_close_database_shutdown_driver(driver); } Vect_build(&Out); /* Free, close ... */ Vect_close(&In); Vect_close(&Out); G_done_msg(_("%d points written to output vector map"), point_cat - 1); exit(EXIT_SUCCESS); }
/*! \brief Write data to GRASS ASCII vector format Prints message if some features without category are skipped. \param[out] ascii pointer to the output ASCII file \param[out] att att file (< version 5 only) \param Map pointer to Map_info structure \param ver version number 4 or 5 \param format format GV_ASCII_FORMAT_POINT or GV_ASCII_FORMAT_STD \param dp number of significant digits \param fs field separator \param region_flag check region \param type feature type filter \param field field number \param Clist list of categories to filter features or NULL \param where SQL select where statement to filter features or NULL \param column_names array of columns to be included to the output or NULL "*" as the first item in the array indicates all columns \param header TRUE to print also header \return number of written features \return -1 on error */ int Vect_write_ascii(FILE *ascii, FILE *att, struct Map_info *Map, int ver, int format, int dp, char *fs, int region_flag, int type, int field, const struct cat_list *Clist, const char* where, const char **column_names, int header) { int ltype, ctype, i, cat, line, left, right, found; double *xptr, *yptr, *zptr, x, y; static struct line_pnts *Points; struct line_cats *Cats, *ACats; char *xstring, *ystring, *zstring; size_t xsize, ysize, zsize; struct Cell_head window; struct ilist *fcats; int count, n_skipped; /* where || columns */ struct field_info *Fi; dbDriver *driver; dbValue value; dbHandle handle; int *cats, ncats, more; dbTable *Table; dbString dbstring; dbColumn *Column; dbValue *Value; char *buf; size_t bufsize; dbCursor cursor; /* columns */ char **columns; int *coltypes; char *all_columns; Fi = NULL; driver = NULL; columns = NULL; coltypes = NULL; all_columns = NULL; G_zero(&value, sizeof(dbValue)); db_init_string(&dbstring); xstring = NULL; ystring = NULL; zstring = NULL; xsize = 0; ysize = 0; zsize = 0; buf = NULL; bufsize = 0; /* get the region */ G_get_window(&window); count = ncats = 0; xstring = ystring = zstring = NULL; cats = NULL; if (field > 0 && (where || column_names)) { Fi = Vect_get_field(Map, field); if (!Fi) { G_fatal_error(_("Database connection not defined for layer %d"), field); } driver = db_start_driver(Fi->driver); if (!driver) G_fatal_error(_("Unable to start driver <%s>"), Fi->driver); db_init_handle(&handle); db_set_handle(&handle, Fi->database, NULL); if (db_open_database(driver, &handle) != DB_OK) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Fi->database, Fi->driver); /* select cats (sorted array) */ ncats = db_select_int(driver, Fi->table, Fi->key, where, &cats); G_debug(3, "%d categories selected from table <%s>", ncats, Fi->table); if (!column_names) { db_close_database(driver); db_shutdown_driver(driver); } else { int icol, ncols; const char *col_name; int len_all = 0; db_set_string(&dbstring, Fi->table); if (db_describe_table(driver, &dbstring, &Table) != DB_OK) { G_warning(_("Unable to describe table <%s>"), Fi->table); return -1; } ncols = db_get_table_number_of_columns(Table); columns = (char **) G_malloc((ncols + 1) * sizeof(char *)); if (column_names[0] && strcmp(column_names[0], "*") == 0) { /* all columns */ icol = 0; for (i = 0; i < ncols; i++) { col_name = db_get_column_name(db_get_table_column(Table, i)); /* key column skipped */ if (strcmp(Fi->key, col_name) != 0) columns[icol++] = G_store(col_name); } columns[icol] = NULL; } else { int j; icol = 0; i = 0; while (column_names[i]) { /* key column skipped */ if (strcmp(Fi->key, column_names[i]) != 0) { found = 0; for (j = 0; j < ncols; j++) { col_name = db_get_column_name(db_get_table_column(Table, j)); if (strcmp(col_name, column_names[i]) == 0) { columns[icol++] = G_store(col_name); found = 1; break; } } if (!found) { G_warning(_("Column <%s> does not exist"), column_names[i]); G_important_message(_("Available columns:")); for (j = 0; j < ncols; j++) { col_name = db_get_column_name(db_get_table_column(Table, j)); G_important_message("%s", col_name); } G_warning(_("Export cancelled")); db_close_database(driver); db_shutdown_driver(driver); return -1; } } i++; } columns[icol] = NULL; } db_zero_string(&dbstring); db_free_table(Table); Table = NULL; if (columns[0]) { /* selected columns only */ i = 0; while (columns[i]) len_all += strlen(columns[i++]); coltypes = G_malloc(i * sizeof(int)); all_columns = G_malloc(len_all + i + 2); i = 0; strcpy(all_columns, columns[0]); while (columns[i]) { /* get column types */ coltypes[i] = db_column_Ctype(driver, Fi->table, columns[i]); if (coltypes[i] < 0) { db_close_database(driver); db_shutdown_driver(driver); G_warning(_("Unknown type of column <%s>, export cancelled"), columns[i]); return -1; } if (i > 0) { strcat(all_columns, ","); strcat(all_columns, columns[i]); } i++; } } else { /* no column or only key column selected */ G_free(columns); columns = NULL; db_close_database(driver); db_shutdown_driver(driver); } } } if (format == GV_ASCII_FORMAT_POINT && header) { /* print header */ if (Map->head.with_z) fprintf(ascii, "east%snorth%sheight%scat", fs, fs, fs); else fprintf(ascii, "east%snorth%scat", fs, fs); if (columns) { for (i = 0; columns[i]; i++) { if (db_select_value (driver, Fi->table, Fi->key, cat, columns[i], &value) < 0) G_fatal_error(_("Unable to select record from table <%s> (key %s, column %s)"), Fi->table, Fi->key, columns[i]); if (columns[i]) fprintf(ascii, "%s%s", fs, columns[i]); else fprintf(ascii, "%s", columns[i]); /* can not happen */ } } fprintf(ascii, "%s", HOST_NEWLINE); } Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); ACats = Vect_new_cats_struct(); fcats = Vect_new_list(); /* by default, read_next_line will NOT read Dead lines */ /* but we can override that (in Level I only) by specifying */ /* the type -1, which means match all line types */ Vect_rewind(Map); count = n_skipped = line = 0; while (TRUE) { ltype = Vect_read_next_line(Map, Points, Cats); if (ltype == -1 ) { /* failure */ if (columns) { db_close_database(driver); db_shutdown_driver(driver); free_col_arrays(coltypes, all_columns, column_names && strcmp(column_names[0], "*") == 0 ? columns : NULL); } return -1; } if (ltype == -2) { /* EOF */ if (columns) { db_close_database(driver); db_shutdown_driver(driver); free_col_arrays(coltypes, all_columns, column_names && strcmp(column_names[0], "*") == 0 ? columns : NULL); } break; } line++; if (!(ltype & type)) continue; if (format == GV_ASCII_FORMAT_POINT && !(ltype & GV_POINTS)) continue; found = get_cat(Cats, Clist, cats, ncats, field, &cat); if (!found && field > 0 && ltype == GV_BOUNDARY && type & GV_AREA && Vect_level(Map) > 1) { Vect_get_line_areas(Map, line, &left, &right); if (left < 0) left = Vect_get_isle_area(Map, abs(left)); if (left > 0) { Vect_get_area_cats(Map, left, ACats); found = get_cat(ACats, Clist, cats, ncats, field, &cat); } if (right < 0) right = Vect_get_isle_area(Map, abs(right)); if (!found && right > 0) { Vect_get_area_cats(Map, right, ACats); found = get_cat(ACats, Clist, cats, ncats, field, &cat); } } if (!found) { if (Cats->n_cats < 1) n_skipped++; continue; } if (ver < 5) { Vect_cat_get(Cats, 1, &cat); } switch (ltype) { case GV_BOUNDARY: if (ver == 5) ctype = 'B'; else ctype = 'A'; break; case GV_CENTROID: if (ver < 5) { if (att != NULL) { if (cat > 0) { G_rasprintf(&xstring, &xsize, "%.*f", dp, Points->x[0]); G_trim_decimal(xstring); G_rasprintf(&ystring, &ysize, "%.*f", dp, Points->y[0]); G_trim_decimal(ystring); fprintf(att, "A %s %s %d%s", xstring, ystring, cat, HOST_NEWLINE); } } continue; } ctype = 'C'; break; case GV_LINE: ctype = 'L'; break; case GV_POINT: ctype = 'P'; break; case GV_FACE: ctype = 'F'; break; case GV_KERNEL: ctype = 'K'; break; default: ctype = 'X'; G_warning(_("Unknown feature type %d"), (int)ltype); break; } if (format == GV_ASCII_FORMAT_POINT) { if (region_flag) { if ((window.east < Points->x[0]) || (window.west > Points->x[0])) continue; } G_rasprintf(&xstring, &xsize, "%.*f", dp, Points->x[0]); G_trim_decimal(xstring); if (region_flag) { if ((window.north < Points->y[0]) || (window.south > Points->y[0])) continue; } G_rasprintf(&ystring, &ysize, "%.*f", dp, Points->y[0]); G_trim_decimal(ystring); Vect_field_cat_get(Cats, field, fcats); if (Map->head.with_z && ver == 5) { if (region_flag) { if ((window.top < Points->z[0]) || (window.bottom > Points->z[0])) continue; } G_rasprintf(&zstring, &zsize, "%.*f", dp, Points->z[0]); G_trim_decimal(zstring); fprintf(ascii, "%s%s%s%s%s", xstring, fs, ystring, fs, zstring); } else { fprintf(ascii, "%s%s%s", xstring, fs, ystring); } if (fcats->n_values > 0 && cat > -1) { if (fcats->n_values > 1) { G_warning(_("Feature has more categories. Only one category (%d) " "is exported."), cat); } fprintf(ascii, "%s%d", fs, cat); /* print attributes */ if (columns) { G_rasprintf(&buf, &bufsize, "SELECT %s FROM %s WHERE %s = %d", all_columns, Fi->table, Fi->key, cat); G_debug(2, "SQL: %s", buf); db_set_string(&dbstring, buf); if (db_open_select_cursor (driver, &dbstring, &cursor, DB_SEQUENTIAL) != DB_OK) { db_close_database(driver); db_shutdown_driver(driver); G_fatal_error(_("Cannot select attributes for cat = %d"), cat); } if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) { db_close_database(driver); db_shutdown_driver(driver); G_fatal_error(_("Unable to fetch data from table")); } Table = db_get_cursor_table(&cursor); for (i = 0; columns[i]; i++) { Column = db_get_table_column(Table, i); Value = db_get_column_value(Column); if (db_test_value_isnull(Value)) { fprintf(ascii, "%s", fs); } else { switch(coltypes[i]) { case DB_C_TYPE_INT: { fprintf(ascii, "%s%d", fs, db_get_value_int(Value)); break; } case DB_C_TYPE_DOUBLE: { fprintf(ascii, "%s%.*f", fs, dp, db_get_value_double(Value)); break; } case DB_C_TYPE_STRING: { fprintf(ascii, "%s%s", fs, db_get_value_string(Value)); break; } case DB_C_TYPE_DATETIME: { break; } case -1: G_fatal_error(_("Column <%s> not found in table <%s>"), columns[i], Fi->table); default: G_fatal_error(_("Column <%s>: unsupported data type"), columns[i]); } } } db_close_cursor(&cursor); } } fprintf(ascii, "%s", HOST_NEWLINE); } else if (format == GV_ASCII_FORMAT_STD) { /* FORMAT_STANDARD */ if (ver == 5 && Cats->n_cats > 0) fprintf(ascii, "%c %d %d%s", ctype, Points->n_points, Cats->n_cats, HOST_NEWLINE); else fprintf(ascii, "%c %d%s", ctype, Points->n_points, HOST_NEWLINE); xptr = Points->x; yptr = Points->y; zptr = Points->z; while (Points->n_points--) { G_rasprintf(&xstring, &xsize, "%.*f", dp, *xptr++); G_trim_decimal(xstring); G_rasprintf(&ystring, &ysize, "%.*f", dp, *yptr++); G_trim_decimal(ystring); if (ver == 5) { if (Map->head.with_z) { G_rasprintf(&zstring, &zsize, "%.*f", dp, *zptr++); G_trim_decimal(zstring); fprintf(ascii, " %-12s %-12s %-12s%s", xstring, ystring, zstring, HOST_NEWLINE); } else { fprintf(ascii, " %-12s %-12s%s", xstring, ystring, HOST_NEWLINE); } } /*Version 4 */ else { fprintf(ascii, " %-12s %-12s%s", ystring, xstring, HOST_NEWLINE); } } if (ver == 5) { for (i = 0; i < Cats->n_cats; i++) { fprintf(ascii, " %-5d %-10d%s", Cats->field[i], Cats->cat[i], HOST_NEWLINE); } } else { if (cat > -1) { if (ltype == GV_POINT) { G_rasprintf(&xstring, &xsize, "%.*f", dp, Points->x[0]); G_trim_decimal(xstring); G_rasprintf(&ystring, &ysize, "%.*f", dp, Points->y[0]); G_trim_decimal(ystring); fprintf(att, "P %s %s %d%s", xstring, ystring, cat, HOST_NEWLINE); } else { x = (Points->x[1] + Points->x[0]) / 2; y = (Points->y[1] + Points->y[0]) / 2; G_rasprintf(&xstring, &xsize, "%.*f", dp, x); G_trim_decimal(xstring); G_rasprintf(&ystring, &ysize, "%.*f", dp, y); G_trim_decimal(ystring); fprintf(att, "L %s %s %d%s", xstring, ystring, cat, HOST_NEWLINE); } } } } else if (format == GV_ASCII_FORMAT_WKT) { if (ltype & (GV_BOUNDARY | GV_CENTROID | GV_FACE | GV_KERNEL)) continue; /* Well-Known Text */ Vect_sfa_line_astext(Points, ltype, Vect_is_3d(Map), dp, ascii); count++; } else { G_fatal_error(_("Unknown format")); } count++; } if (format == GV_ASCII_FORMAT_WKT) { /* process areas - topology required */ int i, area, nareas, isle, nisles; if (Vect_level(Map) < 2) { G_warning(_("Topology not available, unable to process areas")); nareas = 0; } else { nareas = Vect_get_num_areas(Map); } for (area = 1; area <= nareas; area++) { if (!Vect_area_alive(Map, area)) /* skip dead areas */ continue; if (Vect_get_area_cat(Map, area, field) < 0) continue; /* get boundary -> linearring */ if (Vect_get_area_points(Map, area, Points) < 0) { G_warning(_("Unable to get boundary of area id %d"), area); continue; } fprintf(ascii, "POLYGON("); /* write outter ring */ Vect_sfa_line_astext(Points, GV_BOUNDARY, 0, dp, ascii); /* boundary is always 2D */ /* get isles (holes) -> inner rings */ nisles = Vect_get_area_num_isles(Map, area); for (i = 0; i < nisles; i++) { /* get isle boundary -> linearring */ isle = Vect_get_area_isle(Map, area, i); if (Vect_get_isle_points(Map, isle, Points) < 0) { G_warning(_("Unable to get boundary of isle id %d (area id %d)"), isle, area); continue; } fprintf(ascii, ", "); /* write inner ring */ Vect_sfa_line_astext(Points, GV_BOUNDARY, 0, dp, ascii); /* boundary is always 2D */ } fprintf(ascii, ")%s", HOST_NEWLINE); count++; } } if (n_skipped > 0) G_important_message(_("%d features without category skipped. To export also " "features without category use '%s=-1'."), n_skipped, "layer"); Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(Cats); Vect_destroy_cats_struct(ACats); return count; }
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); }
int display_area(struct Map_info *Map, struct cat_list *Clist, const struct Cell_head *window, const struct color_rgb *bcolor, const struct color_rgb *fcolor, int chcat, int id_flag, int cats_color_flag, int default_width, double width_scale, struct Colors *zcolors, dbCatValArray *cvarr_rgb, struct Colors *colors, dbCatValArray *cvarr_width, int nrec_width) { int num, area, isle, n_isles, n_points; double xl, yl; struct line_pnts *Points, * APoints, **IPoints; struct line_cats *Cats; int n_ipoints_alloc; int cat, centroid; int red, grn, blu; int i, custom_rgb, found; int width; struct bound_box box; if (Vect_level(Map) < 2) { G_warning(_("Unable to display areas, topology not available. " "Please try to rebuild topology using " "v.build or v.build.all.")); return 1; } G_debug(1, "display areas:"); centroid = 0; Points = Vect_new_line_struct(); APoints = Vect_new_line_struct(); n_ipoints_alloc = 10; IPoints = (struct line_pnts **)G_malloc(n_ipoints_alloc * sizeof(struct line_pnts *)); for (i = 0; i < n_ipoints_alloc; i++) { IPoints[i] = Vect_new_line_struct(); } Cats = Vect_new_cats_struct(); num = Vect_get_num_areas(Map); G_debug(2, "\tn_areas = %d", num); for (area = 1; area <= num; area++) { G_debug(3, "\tarea = %d", area); if (!Vect_area_alive(Map, area)) continue; centroid = Vect_get_area_centroid(Map, area); if (!centroid) { continue; } /* Check box */ Vect_get_area_box(Map, area, &box); if (box.N < window->south || box.S > window->north || box.E < window->west || box.W > window->east) { if (window->proj != PROJECTION_LL) continue; else { /* out of bounds for -180 to 180, try 0 to 360 as well */ if (box.N < window->south || box.S > window->north) continue; if (box.E + 360 < window->west || box.W + 360 > window->east) continue; } } custom_rgb = FALSE; found = FALSE; if (chcat) { if (id_flag) { if (!(Vect_cat_in_cat_list(area, Clist))) continue; } else { G_debug(3, "centroid = %d", centroid); if (centroid < 1) continue; Vect_read_line(Map, Points, Cats, centroid); for (i = 0; i < Cats->n_cats; i++) { G_debug(3, " centroid = %d, field = %d, cat = %d", centroid, Cats->field[i], Cats->cat[i]); if (Cats->field[i] == Clist->field && Vect_cat_in_cat_list(Cats->cat[i], Clist)) { found = TRUE; break; } } if (!found) continue; } } else if (Clist->field > 0) { found = FALSE; G_debug(3, "\tcentroid = %d", centroid); if (centroid < 1) continue; Vect_read_line(Map, NULL, Cats, centroid); for (i = 0; i < Cats->n_cats; i++) { G_debug(3, "\tcentroid = %d, field = %d, cat = %d", centroid, Cats->field[i], Cats->cat[i]); if (Cats->field[i] == Clist->field) { found = TRUE; break; } } /* lines with no category will be displayed */ if (Cats->n_cats > 0 && !found) continue; } /* fill */ Vect_get_area_points(Map, area, APoints); G_debug(3, "\tn_points = %d", APoints->n_points); if (APoints->n_points < 3) { G_warning(_("Invalid area %d skipped (not enough points)"), area); continue; } Vect_reset_line(Points); Vect_append_points(Points, APoints, GV_FORWARD); n_points = Points->n_points; xl = Points->x[n_points - 1]; yl = Points->y[n_points - 1]; n_isles = Vect_get_area_num_isles(Map, area); if (n_isles >= n_ipoints_alloc) { IPoints = (struct line_pnts **)G_realloc(IPoints, (n_isles + 10) * sizeof(struct line_pnts *)); for (i = n_ipoints_alloc; i < n_isles + 10; i++) { IPoints[i] = Vect_new_line_struct(); } n_ipoints_alloc = n_isles + 10; } for (i = 0; i < n_isles; i++) { isle = Vect_get_area_isle(Map, area, i); Vect_get_isle_points(Map, isle, IPoints[i]); Vect_append_points(Points, IPoints[i], GV_FORWARD); Vect_append_point(Points, xl, yl, 0.0); /* ??? */ } cat = Vect_get_area_cat(Map, area, (Clist->field > 0 ? Clist->field : (Cats->n_cats > 0 ? Cats->field[0] : 1))); if (!centroid && cat == -1) { continue; } /* z height colors */ if (zcolors) { if (Rast_get_d_color(&Points->z[0], &red, &grn, &blu, zcolors) == 1) custom_rgb = TRUE; else custom_rgb = FALSE; } /* custom colors */ if (colors || cvarr_rgb) { custom_rgb = get_table_color(cat, area, colors, cvarr_rgb, &red, &grn, &blu); } /* random colors */ if (cats_color_flag) { custom_rgb = get_cat_color(area, Cats, Clist, &red, &grn, &blu); } /* line width */ if (nrec_width) { width = (int) get_property(cat, area, cvarr_width, (double) width_scale, (double) default_width); D_line_width(width); } if (fcolor || zcolors) { if (!cvarr_rgb && !cats_color_flag && !zcolors && !colors) { D_RGB_color(fcolor->r, fcolor->g, fcolor->b); D_polygon_abs(Points->x, Points->y, Points->n_points); } else { if (custom_rgb) { D_RGB_color((unsigned char)red, (unsigned char)grn, (unsigned char)blu); } else { D_RGB_color(fcolor->r, fcolor->g, fcolor->b); } if (cat >= 0) { D_polygon_abs(Points->x, Points->y, Points->n_points); } } } /* boundary */ if (bcolor) { if (custom_rgb) { D_RGB_color((unsigned char)red, (unsigned char)grn, (unsigned char)blu); } else { D_RGB_color(bcolor->r, bcolor->g, bcolor->b); } /* use different user defined render methods */ D_polyline_abs(APoints->x, APoints->y, APoints->n_points); for (i = 0; i < n_isles; i++) { /* use different user defined render methods */ D_polyline_abs(IPoints[i]->x, IPoints[i]->y, IPoints[i]->n_points); } } } if ((colors || cvarr_rgb) && get_num_color_rules_skipped() > 0) G_warning(_n("%d invalid color rule for areas skipped", "%d invalid color rules for areas skipped", get_num_color_rules_skipped()), get_num_color_rules_skipped()); Vect_destroy_line_struct(Points); Vect_destroy_line_struct(APoints); for (i = 0; i < n_ipoints_alloc; i++) { Vect_destroy_line_struct(IPoints[i]); } G_free(IPoints); Vect_destroy_cats_struct(Cats); return 0; }
int main(int argc, char *argv[]) { int i, j, k; int print_as_matrix; /* only for all */ int all; /* calculate from each to each within the threshold */ struct GModule *module; struct Option *from_opt, *to_opt, *from_type_opt, *to_type_opt, *from_field_opt, *to_field_opt; struct Option *out_opt, *max_opt, *min_opt, *table_opt; struct Option *upload_opt, *column_opt, *to_column_opt; struct Flag *print_flag, *all_flag; struct Map_info From, To, Out, *Outp; int from_type, to_type, from_field, to_field; double max, min; double *max_step; int n_max_steps, curr_step; struct line_pnts *FPoints, *TPoints; struct line_cats *FCats, *TCats; NEAR *Near, *near; int anear; /* allocated space, used only for all */ UPLOAD *Upload; /* zero terminated */ int ftype, fcat, tcat, count; int nfrom, nto, nfcats, fline, tline, tseg, tarea, area, isle, nisles; double tx, ty, tz, dist, talong, tmp_tx, tmp_ty, tmp_tz, tmp_dist, tmp_talong; struct field_info *Fi, *toFi; dbString stmt, dbstr; dbDriver *driver, *to_driver; int *catexist, ncatexist, *cex; char buf1[2000], buf2[2000]; int update_ok, update_err, update_exist, update_notexist, update_dupl, update_notfound; struct boxlist *List; struct bound_box box; dbCatValArray cvarr; dbColumn *column; all = 0; print_as_matrix = 0; column = NULL; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("database")); G_add_keyword(_("attribute table")); module->description = _("Finds the nearest element in vector map 'to' for elements in vector map 'from'."); from_opt = G_define_standard_option(G_OPT_V_INPUT); from_opt->key = "from"; from_opt->description = _("Name of existing vector map (from)"); from_opt->guisection = _("From"); from_field_opt = G_define_standard_option(G_OPT_V_FIELD); from_field_opt->key = "from_layer"; from_field_opt->label = _("Layer number or name (from)"); from_field_opt->guisection = _("From"); from_type_opt = G_define_standard_option(G_OPT_V_TYPE); from_type_opt->key = "from_type"; from_type_opt->options = "point,centroid"; from_type_opt->answer = "point"; from_type_opt->label = _("Feature type (from)"); from_type_opt->guisection = _("From"); to_opt = G_define_standard_option(G_OPT_V_INPUT); to_opt->key = "to"; to_opt->description = _("Name of existing vector map (to)"); to_opt->guisection = _("To"); to_field_opt = G_define_standard_option(G_OPT_V_FIELD); to_field_opt->key = "to_layer"; to_field_opt->label = _("Layer number or name (to)"); to_field_opt->guisection = _("To"); to_type_opt = G_define_standard_option(G_OPT_V_TYPE); to_type_opt->key = "to_type"; to_type_opt->options = "point,line,boundary,centroid,area"; to_type_opt->answer = "point,line,area"; to_type_opt->label = _("Feature type (to)"); to_type_opt->guisection = _("To"); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); out_opt->key = "output"; out_opt->required = NO; out_opt->description = _("Name for output vector map containing lines " "connecting nearest elements"); max_opt = G_define_option(); max_opt->key = "dmax"; max_opt->type = TYPE_DOUBLE; max_opt->required = NO; max_opt->answer = "-1"; max_opt->description = _("Maximum distance or -1 for no limit"); min_opt = G_define_option(); min_opt->key = "dmin"; min_opt->type = TYPE_DOUBLE; min_opt->required = NO; min_opt->answer = "-1"; min_opt->description = _("Minimum distance or -1 for no limit"); upload_opt = G_define_option(); upload_opt->key = "upload"; upload_opt->type = TYPE_STRING; upload_opt->required = YES; upload_opt->multiple = YES; upload_opt->options = "cat,dist,to_x,to_y,to_along,to_angle,to_attr"; upload_opt->description = _("Values describing the relation between two nearest features"); upload_opt->descriptions = _("cat;category of the nearest feature;" "dist;minimum distance to nearest feature;" "to_x;x coordinate of the nearest point on 'to' feature;" "to_y;y coordinate of the nearest point on 'to' feature;" "to_along;distance between points/centroids in 'from' map and the linear feature's " "start point in 'to' map, along this linear feature;" "to_angle;angle between the linear feature in 'to' map and the positive x axis, at " "the location of point/centroid in 'from' map, counterclockwise, in radians, which " "is between -PI and PI inclusive;" "to_attr;attribute of nearest feature given by to_column option"); /* "from_x - x coordinate of the nearest point on 'from' feature;" */ /* "from_y - y coordinate of the nearest point on 'from' feature;" */ /* "from_along - distance to the nearest point on 'from' feature along linear feature;" */ column_opt = G_define_standard_option(G_OPT_DB_COLUMN); column_opt->required = YES; column_opt->multiple = YES; column_opt->description = _("Column name(s) where values specified by 'upload' option will be uploaded"); column_opt->guisection = _("From_map"); to_column_opt = G_define_standard_option(G_OPT_DB_COLUMN); to_column_opt->key = "to_column"; to_column_opt->description = _("Column name of nearest feature (used with upload=to_attr)"); to_column_opt->guisection = _("To"); table_opt = G_define_standard_option(G_OPT_DB_TABLE); table_opt->gisprompt = "new_dbtable,dbtable,dbtable"; table_opt->description = _("Name of table created for output when the distance to all flag is used"); print_flag = G_define_flag(); print_flag->key = 'p'; print_flag->label = _("Print output to stdout, don't update attribute table"); print_flag->description = _("First column is always category of 'from' feature called from_cat"); all_flag = G_define_flag(); all_flag->key = 'a'; all_flag->label = _("Calculate distances to all features within the threshold"); all_flag->description = _("The output is written to stdout but may be uploaded " "to a new table created by this module. " "From categories are may be multiple."); /* huh? */ /* GUI dependency */ from_opt->guidependency = G_store(from_field_opt->key); sprintf(buf1, "%s,%s", to_field_opt->key, to_column_opt->key); to_opt->guidependency = G_store(buf1); to_field_opt->guidependency = G_store(to_column_opt->key); if (G_parser(argc, argv)) exit(EXIT_FAILURE); from_type = Vect_option_to_types(from_type_opt); to_type = Vect_option_to_types(to_type_opt); from_field = atoi(from_field_opt->answer); max = atof(max_opt->answer); min = atof(min_opt->answer); if (all_flag->answer) all = 1; /* Read upload and column options */ /* count */ i = 0; while (upload_opt->answers[i]) i++; if (strcmp(from_opt->answer, to_opt->answer) == 0 && all && !table_opt->answer && i == 1) print_as_matrix = 1; /* alloc */ Upload = (UPLOAD *) G_calloc(i + 1, sizeof(UPLOAD)); /* read upload */ i = 0; while (upload_opt->answers[i]) { if (strcmp(upload_opt->answers[i], "cat") == 0) Upload[i].upload = CAT; else if (strcmp(upload_opt->answers[i], "from_x") == 0) Upload[i].upload = FROM_X; else if (strcmp(upload_opt->answers[i], "from_y") == 0) Upload[i].upload = FROM_Y; else if (strcmp(upload_opt->answers[i], "to_x") == 0) Upload[i].upload = TO_X; else if (strcmp(upload_opt->answers[i], "to_y") == 0) Upload[i].upload = TO_Y; else if (strcmp(upload_opt->answers[i], "from_along") == 0) Upload[i].upload = FROM_ALONG; else if (strcmp(upload_opt->answers[i], "to_along") == 0) Upload[i].upload = TO_ALONG; else if (strcmp(upload_opt->answers[i], "dist") == 0) Upload[i].upload = DIST; else if (strcmp(upload_opt->answers[i], "to_angle") == 0) Upload[i].upload = TO_ANGLE; else if (strcmp(upload_opt->answers[i], "to_attr") == 0) { if (!(to_column_opt->answer)) { G_fatal_error(_("to_column option missing")); } Upload[i].upload = TO_ATTR; } i++; } Upload[i].upload = END; /* read columns */ i = 0; while (column_opt->answers[i]) { if (Upload[i].upload == END) { G_warning(_("Too many column names")); break; } Upload[i].column = G_store(column_opt->answers[i]); i++; } if (Upload[i].upload != END) G_fatal_error(_("Not enough column names")); /* Open 'from' vector */ Vect_set_open_level(2); Vect_open_old(&From, from_opt->answer, G_mapset()); /* Open 'to' vector */ Vect_set_open_level(2); Vect_open_old2(&To, to_opt->answer, "", to_field_opt->answer); to_field = Vect_get_field_number(&To, to_field_opt->answer); /* Open output vector */ if (out_opt->answer) { Vect_open_new(&Out, out_opt->answer, WITHOUT_Z); Vect_hist_command(&Out); Outp = &Out; } else { Outp = NULL; } /* TODO: add maxdist = -1 to Vect_select_ !!! */ /* Calc maxdist */ n_max_steps = 1; if (max != 0) { struct bound_box fbox, tbox; double dx, dy, dz, tmp_max; int n_features = 0; Vect_get_map_box(&From, &fbox); Vect_get_map_box(&To, &tbox); Vect_box_extend(&fbox, &tbox); dx = fbox.E - fbox.W; dy = fbox.N - fbox.S; if (Vect_is_3d(&From)) dz = fbox.T - fbox.B; else dz = 0.0; tmp_max = sqrt(dx * dx + dy * dy + dz * dz); if (max < 0) max = tmp_max; /* how to determine a reasonable number of steps to increase the search box? */ /* with max > 0 but max <<< tmp_max, 2 steps are sufficient, first 0 then max * a reasonable number of steps also depends on the number of features in To * e.g. only one area in To, no need to step */ nto = Vect_get_num_lines(&To); for (tline = 1; tline <= nto; tline++) { /* TODO: Vect_get_line_type() */ n_features += ((to_type & To.plus.Line[tline]->type) != 0); } if (to_type & GV_AREA) { if (Vect_get_num_areas(&To) > n_features) n_features = Vect_get_num_areas(&To); } if (n_features == 0) G_fatal_error(_("No features of selected type in To vector <%s>"), to_opt->answer); n_max_steps = sqrt(n_features) * max / tmp_max; /* max 9 steps from testing */ if (n_max_steps > 9) n_max_steps = 9; if (n_max_steps < 2) n_max_steps = 2; if (n_max_steps > n_features) n_max_steps = n_features; G_debug(2, "max = %f", max); G_debug(2, "maximum reasonable search distance = %f", tmp_max); G_debug(2, "n_features = %d", n_features); G_debug(2, "n_max_steps = %d", n_max_steps); } if (min > max) G_fatal_error("dmin can not be larger than dmax"); if (n_max_steps > 1) { /* set up steps to increase search box */ max_step = G_malloc(n_max_steps * sizeof(double)); /* first step always 0 */ max_step[0] = 0; for (curr_step = 1; curr_step < n_max_steps - 1; curr_step++) { /* for 9 steps, this would be max / [128, 64, 32, 16, 8, 4, 2] */ max_step[curr_step] = max / (2 << (n_max_steps - 1 - curr_step)); } /* last step always max */ max_step[n_max_steps - 1] = max; } else { max_step = G_malloc(sizeof(double)); max_step[0] = max; } /* Open database driver */ db_init_string(&stmt); db_init_string(&dbstr); driver = NULL; if (!print_flag->answer) { if (!all) { Fi = Vect_get_field(&From, from_field); if (Fi == NULL) G_fatal_error(_("Database connection not defined for layer %d"), from_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); /* check if column exists */ i = 0; while (column_opt->answers[i]) { db_get_column(driver, Fi->table, column_opt->answers[i], &column); if (column) { db_free_column(column); column = NULL; } else { G_fatal_error(_("Column <%s> not found in table <%s>"), column_opt->answers[i], Fi->table); } i++; } } else { driver = db_start_driver_open_database(NULL, NULL); if (driver == NULL) G_fatal_error(_("Unable to open default database")); } } to_driver = NULL; if (to_column_opt->answer) { toFi = Vect_get_field(&To, to_field); if (toFi == NULL) G_fatal_error(_("Database connection not defined for layer %d"), to_field); to_driver = db_start_driver_open_database(toFi->driver, toFi->database); if (to_driver == NULL) G_fatal_error(_("Unable to open database <%s> by driver <%s>"), toFi->database, toFi->driver); /* check if to_column exists */ db_get_column(to_driver, toFi->table, to_column_opt->answer, &column); if (column) { db_free_column(column); column = NULL; } else { G_fatal_error(_("Column <%s> not found in table <%s>"), to_column_opt->answer, toFi->table); } /* Check column types */ if (!print_flag->answer && !all) { char *fcname = NULL; int fctype, tctype; i = 0; while (column_opt->answers[i]) { if (Upload[i].upload == TO_ATTR) { fcname = column_opt->answers[i]; break; } i++; } if (fcname) { fctype = db_column_Ctype(driver, Fi->table, fcname); tctype = db_column_Ctype(to_driver, toFi->table, to_column_opt->answer); if (((tctype == DB_C_TYPE_STRING || tctype == DB_C_TYPE_DATETIME) && (fctype == DB_C_TYPE_INT || fctype == DB_C_TYPE_DOUBLE)) || ((tctype == DB_C_TYPE_INT || tctype == DB_C_TYPE_DOUBLE) && (fctype == DB_C_TYPE_STRING || fctype == DB_C_TYPE_DATETIME)) ) { G_fatal_error(_("Incompatible column types")); } } } } FPoints = Vect_new_line_struct(); TPoints = Vect_new_line_struct(); FCats = Vect_new_cats_struct(); TCats = Vect_new_cats_struct(); List = Vect_new_boxlist(1); /* Allocate space ( may be more than needed (duplicate cats and elements without cats) ) */ nfrom = Vect_get_num_lines(&From); nto = Vect_get_num_lines(&To); if (all) { /* Attention with space for all, it can easily run out of memory */ anear = 2 * nfrom; Near = (NEAR *) G_calloc(anear, sizeof(NEAR)); } else { Near = (NEAR *) G_calloc(nfrom, sizeof(NEAR)); } /* Read all cats from 'from' */ if (!all) { nfcats = 0; for (i = 1; i <= nfrom; i++) { ftype = Vect_read_line(&From, NULL, FCats, i); /* This keeps also categories of areas for future (if area s in from_type) */ if (!(ftype & from_type) && (ftype != GV_CENTROID || !(from_type & GV_AREA))) continue; Vect_cat_get(FCats, from_field, &fcat); if (fcat < 0) continue; Near[nfcats].from_cat = fcat; nfcats++; } G_debug(1, "%d cats loaded from vector (including duplicates)", nfcats); /* Sort by cats and remove duplicates */ qsort((void *)Near, nfcats, sizeof(NEAR), cmp_near); /* remove duplicates */ for (i = 1; i < nfcats; i++) { if (Near[i].from_cat == Near[i - 1].from_cat) { for (j = i; j < nfcats - 1; j++) { Near[j].from_cat = Near[j + 1].from_cat; } nfcats--; } } G_debug(1, "%d cats loaded from vector (unique)", nfcats); } /* Go through all lines in 'from' and find nearest in 'to' for each */ /* Note: as from_type is restricted to GV_POINTS (for now) everything is simple */ count = 0; /* count of distances in 'all' mode */ /* Find nearest lines */ if (to_type & (GV_POINTS | GV_LINES)) { struct line_pnts *LLPoints; if (G_projection() == PROJECTION_LL) { LLPoints = Vect_new_line_struct(); } else { LLPoints = NULL; } G_message(_("Finding nearest feature...")); for (fline = 1; fline <= nfrom; fline++) { int tmp_tcat; double tmp_tangle, tangle; double tmp_min = (min < 0 ? 0 : min); double box_edge = 0; int done = 0; curr_step = 0; G_debug(3, "fline = %d", fline); G_percent(fline, nfrom, 2); ftype = Vect_read_line(&From, FPoints, FCats, fline); if (!(ftype & from_type)) continue; Vect_cat_get(FCats, from_field, &fcat); if (fcat < 0 && !all) continue; while (!done) { done = 1; if (!all) { /* enlarge search box until we get a hit */ /* the objective is to enlarge the search box * in the first iterations just a little bit * to keep the number of hits low */ Vect_reset_boxlist(List); while (curr_step < n_max_steps) { box_edge = max_step[curr_step]; if (box_edge < tmp_min) continue; box.E = FPoints->x[0] + box_edge; box.W = FPoints->x[0] - box_edge; box.N = FPoints->y[0] + box_edge; box.S = FPoints->y[0] - box_edge; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_lines_by_box(&To, &box, to_type, List); curr_step++; if (List->n_values > 0) break; } } else { box.E = FPoints->x[0] + max; box.W = FPoints->x[0] - max; box.N = FPoints->y[0] + max; box.S = FPoints->y[0] - max; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_lines_by_box(&To, &box, to_type, List); } G_debug(3, " %d lines in box", List->n_values); tline = 0; dist = PORT_DOUBLE_MAX; for (i = 0; i < List->n_values; i++) { tmp_tcat = -1; Vect_read_line(&To, TPoints, TCats, List->id[i]); tseg = Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0], (Vect_is_3d(&From) && Vect_is_3d(&To)) ? WITH_Z : WITHOUT_Z, &tmp_tx, &tmp_ty, &tmp_tz, &tmp_dist, NULL, &tmp_talong); Vect_point_on_line(TPoints, tmp_talong, NULL, NULL, NULL, &tmp_tangle, NULL); if (tmp_dist > max || tmp_dist < min) continue; /* not in threshold */ /* TODO: more cats of the same field */ Vect_cat_get(TCats, to_field, &tmp_tcat); if (G_projection() == PROJECTION_LL) { /* calculate distances in meters not degrees (only 2D) */ Vect_reset_line(LLPoints); Vect_append_point(LLPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0]); Vect_append_point(LLPoints, tmp_tx, tmp_ty, tmp_tz); tmp_dist = Vect_line_geodesic_length(LLPoints); Vect_reset_line(LLPoints); for (k = 0; k < tseg; k++) Vect_append_point(LLPoints, TPoints->x[k], TPoints->y[k], TPoints->z[k]); Vect_append_point(LLPoints, tmp_tx, tmp_ty, tmp_tz); tmp_talong = Vect_line_geodesic_length(LLPoints); } G_debug(4, " tmp_dist = %f tmp_tcat = %d", tmp_dist, tmp_tcat); if (all) { if (anear <= count) { anear += 10 + nfrom / 10; Near = (NEAR *) G_realloc(Near, anear * sizeof(NEAR)); } near = &(Near[count]); /* store info about relation */ near->from_cat = fcat; near->to_cat = tmp_tcat; /* -1 is OK */ near->dist = tmp_dist; near->from_x = FPoints->x[0]; near->from_y = FPoints->y[0]; near->from_z = FPoints->z[0]; near->to_x = tmp_tx; near->to_y = tmp_ty; near->to_z = tmp_tz; near->to_along = tmp_talong; /* 0 for points */ near->to_angle = tmp_tangle; near->count++; count++; } else { if (tline == 0 || (tmp_dist < dist)) { tline = List->id[i]; tcat = tmp_tcat; dist = tmp_dist; tx = tmp_tx; ty = tmp_ty; tz = tmp_tz; talong = tmp_talong; tangle = tmp_tangle; } } } G_debug(4, " dist = %f", dist); if (curr_step < n_max_steps) { /* enlarging the search box is possible */ if (tline > 0 && dist > box_edge) { /* line found but distance > search edge: * line bbox overlaps with search box, line itself is outside search box */ done = 0; } else if (tline == 0) { /* no line within max dist, but search box can still be enlarged */ done = 0; } } if (done && !all && tline > 0) { /* find near by cat */ near = (NEAR *) bsearch((void *)&fcat, Near, nfcats, sizeof(NEAR), cmp_near); G_debug(4, " near.from_cat = %d near.count = %d", near->from_cat, near->count); /* store info about relation */ if (near->count == 0 || near->dist > dist) { near->to_cat = tcat; /* -1 is OK */ near->dist = dist; near->from_x = FPoints->x[0]; near->from_y = FPoints->y[0]; near->from_z = FPoints->z[0]; near->to_x = tx; near->to_y = ty; near->to_z = tz; near->to_along = talong; /* 0 for points */ near->to_angle = tangle; } near->count++; } } /* done */ } /* next feature */ if (LLPoints) { Vect_destroy_line_struct(LLPoints); } } /* Find nearest areas */ if (to_type & GV_AREA) { G_message(_("Finding nearest areas...")); for (fline = 1; fline <= nfrom; fline++) { double tmp_min = (min < 0 ? 0 : min); double box_edge = 0; int done = 0; curr_step = 0; G_debug(3, "fline = %d", fline); G_percent(fline, nfrom, 2); ftype = Vect_read_line(&From, FPoints, FCats, fline); if (!(ftype & from_type)) continue; Vect_cat_get(FCats, from_field, &fcat); if (fcat < 0 && !all) continue; while (!done) { done = 1; if (!all) { /* enlarge search box until we get a hit */ /* the objective is to enlarge the search box * in the first iterations just a little bit * to keep the number of hits low */ Vect_reset_boxlist(List); while (curr_step < n_max_steps) { box_edge = max_step[curr_step]; if (box_edge < tmp_min) continue; box.E = FPoints->x[0] + box_edge; box.W = FPoints->x[0] - box_edge; box.N = FPoints->y[0] + box_edge; box.S = FPoints->y[0] - box_edge; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_areas_by_box(&To, &box, List); curr_step++; if (List->n_values > 0) break; } } else { box.E = FPoints->x[0] + max; box.W = FPoints->x[0] - max; box.N = FPoints->y[0] + max; box.S = FPoints->y[0] - max; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_areas_by_box(&To, &box, List); } G_debug(4, "%d areas selected by box", List->n_values); /* For each area in box check the distance */ tarea = 0; dist = PORT_DOUBLE_MAX; for (i = 0; i < List->n_values; i++) { int tmp_tcat; area = List->id[i]; G_debug(4, "%d: area %d", i, area); Vect_get_area_points(&To, area, TPoints); /* Find the distance to this area */ if (Vect_point_in_area(FPoints->x[0], FPoints->y[0], &To, area, List->box[i])) { /* in area */ tmp_dist = 0; tmp_tx = FPoints->x[0]; tmp_ty = FPoints->y[0]; } else if (Vect_point_in_poly(FPoints->x[0], FPoints->y[0], TPoints) > 0) { /* in isle */ nisles = Vect_get_area_num_isles(&To, area); for (j = 0; j < nisles; j++) { double tmp2_dist, tmp2_tx, tmp2_ty; isle = Vect_get_area_isle(&To, area, j); Vect_get_isle_points(&To, isle, TPoints); Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0], WITHOUT_Z, &tmp2_tx, &tmp2_ty, NULL, &tmp2_dist, NULL, NULL); if (j == 0 || tmp2_dist < tmp_dist) { tmp_dist = tmp2_dist; tmp_tx = tmp2_tx; tmp_ty = tmp2_ty; } } } else { /* outside area */ Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0], WITHOUT_Z, &tmp_tx, &tmp_ty, NULL, &tmp_dist, NULL, NULL); } if (tmp_dist > max || tmp_dist < min) continue; /* not in threshold */ Vect_get_area_cats(&To, area, TCats); tmp_tcat = -1; /* TODO: all cats of given field ? */ for (j = 0; j < TCats->n_cats; j++) { if (TCats->field[j] == to_field) { if (tmp_tcat >= 0) G_warning(_("More cats found in to_layer (area=%d)"), area); tmp_tcat = TCats->cat[j]; } } G_debug(4, " tmp_dist = %f tmp_tcat = %d", tmp_dist, tmp_tcat); if (all) { if (anear <= count) { anear += 10 + nfrom / 10; Near = (NEAR *) G_realloc(Near, anear * sizeof(NEAR)); } near = &(Near[count]); /* store info about relation */ near->from_cat = fcat; near->to_cat = tmp_tcat; /* -1 is OK */ near->dist = tmp_dist; near->from_x = FPoints->x[0]; near->from_y = FPoints->y[0]; near->to_x = tmp_tx; near->to_y = tmp_ty; near->to_along = 0; /* nonsense for areas */ near->to_angle = 0; /* not supported for areas */ near->count++; count++; } else if (tarea == 0 || tmp_dist < dist) { tarea = area; tcat = tmp_tcat; dist = tmp_dist; tx = tmp_tx; ty = tmp_ty; } } if (curr_step < n_max_steps) { /* enlarging the search box is possible */ if (tarea > 0 && dist > box_edge) { /* area found but distance > search edge: * area bbox overlaps with search box, area itself is outside search box */ done = 0; } else if (tarea == 0) { /* no area within max dist, but search box can still be enlarged */ done = 0; } } if (done && !all && tarea > 0) { /* find near by cat */ near = (NEAR *) bsearch((void *)&fcat, Near, nfcats, sizeof(NEAR), cmp_near); G_debug(4, "near.from_cat = %d near.count = %d dist = %f", near->from_cat, near->count, near->dist); /* store info about relation */ if (near->count == 0 || near->dist > dist) { near->to_cat = tcat; /* -1 is OK */ near->dist = dist; near->from_x = FPoints->x[0]; near->from_y = FPoints->y[0]; near->to_x = tx; near->to_y = ty; near->to_along = 0; /* nonsense for areas */ near->to_angle = 0; /* not supported for areas */ } near->count++; } } /* done */ } /* next feature */ } G_debug(3, "count = %d", count); /* Update database / print to stdout / create output map */ if (print_flag->answer) { /* print header */ fprintf(stdout, "from_cat"); i = 0; while (Upload[i].upload != END) { fprintf(stdout, "|%s", Upload[i].column); i++; } fprintf(stdout, "\n"); } else if (all && table_opt->answer) { /* create new table */ db_set_string(&stmt, "create table "); db_append_string(&stmt, table_opt->answer); db_append_string(&stmt, " (from_cat integer"); j = 0; while (Upload[j].upload != END) { db_append_string(&stmt, ", "); switch (Upload[j].upload) { case CAT: sprintf(buf2, "%s integer", Upload[j].column); break; case DIST: case FROM_X: case FROM_Y: case TO_X: case TO_Y: case FROM_ALONG: case TO_ALONG: case TO_ANGLE: sprintf(buf2, "%s double precision", Upload[j].column); } db_append_string(&stmt, buf2); j++; } db_append_string(&stmt, " )"); G_debug(3, "SQL: %s", db_get_string(&stmt)); if (db_execute_immediate(driver, &stmt) != DB_OK) G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&stmt)); if (db_grant_on_table(driver, table_opt->answer, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) G_fatal_error(_("Unable to grant privileges on table <%s>"), table_opt->answer); } else if (!all) { /* read existing cats from table */ ncatexist = db_select_int(driver, Fi->table, Fi->key, NULL, &catexist); G_debug(1, "%d cats selected from the table", ncatexist); } update_ok = update_err = update_exist = update_notexist = update_dupl = update_notfound = 0; if (!all) { count = nfcats; } else if (print_as_matrix) { qsort((void *)Near, count, sizeof(NEAR), cmp_near_to); } if (driver) db_begin_transaction(driver); /* select 'to' attributes */ if (to_column_opt->answer) { int nrec; db_CatValArray_init(&cvarr); nrec = db_select_CatValArray(to_driver, toFi->table, toFi->key, to_column_opt->answer, NULL, &cvarr); G_debug(3, "selected values = %d", nrec); if (cvarr.ctype == DB_C_TYPE_DATETIME) { G_warning(_("DATETIME type not yet supported, no attributes will be uploaded")); } db_close_database_shutdown_driver(to_driver); } if (!(print_flag->answer || (all && !table_opt->answer))) /* no printing */ G_message("Update database..."); for (i = 0; i < count; i++) { dbCatVal *catval = 0; if (!(print_flag->answer || (all && !table_opt->answer))) /* no printing */ G_percent(i, count, 1); /* Write line connecting nearest points */ if (Outp != NULL) { Vect_reset_line(FPoints); Vect_reset_cats(FCats); Vect_append_point(FPoints, Near[i].from_x, Near[i].from_y, 0); if (Near[i].dist == 0) { Vect_write_line(Outp, GV_POINT, FPoints, FCats); } else { Vect_append_point(FPoints, Near[i].to_x, Near[i].to_y, 0); Vect_write_line(Outp, GV_LINE, FPoints, FCats); } } if (Near[i].count > 1) update_dupl++; if (Near[i].count == 0) update_notfound++; if (to_column_opt->answer && Near[i].count > 0) { db_CatValArray_get_value(&cvarr, Near[i].to_cat, &catval); } if (print_flag->answer || (all && !table_opt->answer)) { /* print only */ /* input and output is the same && calculate distances && only one upload option given -> print as a matrix */ if (print_as_matrix) { if (i == 0) { for (j = 0; j < nfrom; j++) { if (j == 0) fprintf(stdout, " "); fprintf(stdout, "|%d", Near[j].to_cat); } fprintf(stdout, "\n"); } if (i % nfrom == 0) { fprintf(stdout, "%d", Near[i].from_cat); for (j = 0; j < nfrom; j++) { print_upload(Near, Upload, i + j, &cvarr, catval); } fprintf(stdout, "\n"); } } else { fprintf(stdout, "%d", Near[i].from_cat); print_upload(Near, Upload, i, &cvarr, catval); fprintf(stdout, "\n"); } } else if (all) { /* insert new record */ sprintf(buf1, "insert into %s values ( %d ", table_opt->answer, Near[i].from_cat); db_set_string(&stmt, buf1); j = 0; while (Upload[j].upload != END) { db_append_string(&stmt, ","); switch (Upload[j].upload) { case CAT: sprintf(buf2, " %d", Near[i].to_cat); break; case DIST: sprintf(buf2, " %f", Near[i].dist); break; case FROM_X: sprintf(buf2, " %f", Near[i].from_x); break; case FROM_Y: sprintf(buf2, " %f", Near[i].from_y); break; case TO_X: sprintf(buf2, " %f", Near[i].to_x); break; case TO_Y: sprintf(buf2, " %f", Near[i].to_y); break; case FROM_ALONG: sprintf(buf2, " %f", Near[i].from_along); break; case TO_ALONG: sprintf(buf2, " %f", Near[i].to_along); break; case TO_ANGLE: sprintf(buf2, " %f", Near[i].to_angle); break; case TO_ATTR: if (catval) { switch (cvarr.ctype) { case DB_C_TYPE_INT: sprintf(buf2, " %d", catval->val.i); break; case DB_C_TYPE_DOUBLE: sprintf(buf2, " %.15e", catval->val.d); break; case DB_C_TYPE_STRING: db_set_string(&dbstr, db_get_string(catval->val.s)); db_double_quote_string(&dbstr); sprintf(buf2, " '%s'", db_get_string(&dbstr)); break; case DB_C_TYPE_DATETIME: /* TODO: formating datetime */ sprintf(buf2, " null"); break; } } else { sprintf(buf2, " null"); } break; } db_append_string(&stmt, buf2); j++; } db_append_string(&stmt, " )"); G_debug(3, "SQL: %s", db_get_string(&stmt)); if (db_execute_immediate(driver, &stmt) == DB_OK) { update_ok++; } else { update_err++; } } else { /* update table */ /* check if exists in table */ cex = (int *)bsearch((void *)&(Near[i].from_cat), catexist, ncatexist, sizeof(int), cmp_exist); if (cex == NULL) { /* cat does not exist in DB */ update_notexist++; continue; } update_exist++; sprintf(buf1, "update %s set", Fi->table); db_set_string(&stmt, buf1); j = 0; while (Upload[j].upload != END) { if (j > 0) db_append_string(&stmt, ","); sprintf(buf2, " %s =", Upload[j].column); db_append_string(&stmt, buf2); if (Near[i].count == 0) { /* no nearest found */ db_append_string(&stmt, " null"); } else { switch (Upload[j].upload) { case CAT: if (Near[i].to_cat > 0) sprintf(buf2, " %d", Near[i].to_cat); else sprintf(buf2, " null"); break; case DIST: sprintf(buf2, " %f", Near[i].dist); break; case FROM_X: sprintf(buf2, " %f", Near[i].from_x); break; case FROM_Y: sprintf(buf2, " %f", Near[i].from_y); break; case TO_X: sprintf(buf2, " %f", Near[i].to_x); break; case TO_Y: sprintf(buf2, " %f", Near[i].to_y); break; case FROM_ALONG: sprintf(buf2, " %f", Near[i].from_along); break; case TO_ALONG: sprintf(buf2, " %f", Near[i].to_along); break; case TO_ANGLE: sprintf(buf2, " %f", Near[i].to_angle); break; case TO_ATTR: if (catval) { switch (cvarr.ctype) { case DB_C_TYPE_INT: sprintf(buf2, " %d", catval->val.i); break; case DB_C_TYPE_DOUBLE: sprintf(buf2, " %.15e", catval->val.d); break; case DB_C_TYPE_STRING: db_set_string(&dbstr, db_get_string(catval->val.s)); db_double_quote_string(&dbstr); sprintf(buf2, " '%s'", db_get_string(&dbstr)); break; case DB_C_TYPE_DATETIME: /* TODO: formating datetime */ sprintf(buf2, " null"); break; } } else { sprintf(buf2, " null"); } break; } db_append_string(&stmt, buf2); } j++; } sprintf(buf2, " where %s = %d", Fi->key, Near[i].from_cat); db_append_string(&stmt, buf2); G_debug(2, "SQL: %s", db_get_string(&stmt)); if (db_execute_immediate(driver, &stmt) == DB_OK) { update_ok++; } else { update_err++; } } } G_percent(count, count, 1); if (driver) db_commit_transaction(driver); /* print stats */ if (update_dupl > 0) G_message(_("%d categories with more than 1 feature in vector map <%s>"), update_dupl, from_opt->answer); if (update_notfound > 0) G_message(_("%d categories - no nearest feature found"), update_notfound); if (!print_flag->answer) { db_close_database_shutdown_driver(driver); db_free_string(&stmt); /* print stats */ if (all && table_opt->answer) { G_message(_("%d distances calculated"), count); G_message(_("%d records inserted"), update_ok); if (update_err > 0) G_message(_("%d insert errors"), update_err); } else if (!all) { if (nfcats > 0) G_message(_("%d categories read from the map"), nfcats); if (ncatexist > 0) G_message(_("%d categories exist in the table"), ncatexist); if (update_exist > 0) G_message(_("%d categories read from the map exist in the table"), update_exist); if (update_notexist > 0) G_message(_("%d categories read from the map don't exist in the table"), update_notexist); G_message(_("%d records updated"), update_ok); if (update_err > 0) G_message(_("%d update errors"), update_err); G_free(catexist); } Vect_set_db_updated(&From); } Vect_close(&From); if (Outp != NULL) { Vect_build(Outp); Vect_close(Outp); } G_done_msg(" "); exit(EXIT_SUCCESS); }
/* shortest distance between line and area * return 1 inside area * return 2 inside isle of area * return 3 outside area */ int line2area(const struct Map_info *To, struct line_pnts *Points, int type, int area, const struct bound_box *abox, double *fx, double *fy, double *fz, double *falong, double *fangle, double *tx, double *ty, double *tz, double *talong, double *tangle, double *dist, int with_z) { int i, j; double tmp_dist; int isle, nisles; int all_inside_outer, all_outside_outer, all_outside_inner; static struct line_pnts *aPoints = NULL; static struct line_pnts **iPoints = NULL; static struct bound_box *ibox = NULL; static int isle_alloc = 0; if (!aPoints) aPoints = Vect_new_line_struct(); *dist = PORT_DOUBLE_MAX; /* fangle and tangle are angles in radians, counter clockwise from x axis * initialize to invalid angle */ *fangle = *tangle = -9.; *falong = *talong = 0.; *fx = Points->x[0]; *fy = Points->y[0]; *fz = Points->z[0]; *tx = Points->x[0]; *ty = Points->y[0]; *tz = Points->z[0]; Vect_get_area_points(To, area, aPoints); nisles = Vect_get_area_num_isles(To, area); if (nisles > isle_alloc) { iPoints = G_realloc(iPoints, nisles * sizeof(struct line_pnts *)); ibox = G_realloc(ibox, nisles * sizeof(struct bound_box)); for (i = isle_alloc; i < nisles; i++) iPoints[i] = Vect_new_line_struct(); isle_alloc = nisles; } for (i = 0; i < nisles; i++) { isle = Vect_get_area_isle(To, area, i); Vect_get_isle_points(To, isle, iPoints[i]); Vect_get_isle_box(To, isle, &ibox[i]); } /* inside area ? */ all_inside_outer = all_outside_outer = 1; all_outside_inner = 1; int in_box; for (i = 0; i < Points->n_points; i++) { if (with_z) in_box = Vect_point_in_box(Points->x[i], Points->y[i], Points->z[i], abox); else in_box = Vect_point_in_box_2d(Points->x[i], Points->y[i], abox); if (in_box) { int poly; poly = Vect_point_in_poly(Points->x[i], Points->y[i], aPoints); if (poly > 0) { /* inside outer ring */ all_outside_outer = 0; } else { /* outside outer ring */ all_inside_outer = 0; } /* exactly on boundary */ if (poly == 2) { line2line(Points, type, aPoints, GV_BOUNDARY, fx, fy, fz, falong, fangle, tx, ty, tz, talong, tangle, dist, with_z); *talong = 0; *tangle = -9; return 1; } /* inside outer ring */ else if (poly == 1) { int inside_isle = 0; for (j = 0; j < nisles; j++) { if (with_z) in_box = Vect_point_in_box(Points->x[i], Points->y[i], Points->z[i], &ibox[j]); else in_box = Vect_point_in_box_2d(Points->x[i], Points->y[i], &ibox[j]); if (in_box) { poly = Vect_point_in_poly(Points->x[i], Points->y[i], iPoints[j]); /* inside or exactly on boundary */ if (poly > 0) { double tmp_fx, tmp_fy, tmp_fz, tmp_fangle, tmp_falong; double tmp_tx, tmp_ty, tmp_tz, tmp_tangle, tmp_talong; /* pass all points of the line, * this will catch an intersection */ line2line(Points, type, iPoints[j], GV_BOUNDARY, &tmp_fx, &tmp_fy, &tmp_fz, &tmp_falong, &tmp_fangle, &tmp_tx, &tmp_ty, &tmp_tz, &tmp_talong, &tmp_tangle, &tmp_dist, with_z); if (*dist > tmp_dist) { *dist = tmp_dist; *fx = tmp_fx; *fy = tmp_fy; *fz = tmp_fz; *falong = tmp_falong; *fangle = tmp_fangle; *tx = tmp_tx; *ty = tmp_ty; *tz = tmp_tz; *talong = 0; *tangle = tmp_tangle; } if (poly == 1) /* excludes isle boundary */ inside_isle = 1; } } if (*dist == 0) break; } /* inside area (inside outer ring, outside inner rings * or exactly on one of the inner rings) */ if (!inside_isle) { *fx = Points->x[i]; *fy = Points->y[i]; *fz = Points->z[i]; *tx = Points->x[i]; *ty = Points->y[i]; *tz = Points->z[i]; *fangle = *tangle = -9.; *falong = *talong = 0.; *dist = 0; return 1; } else { /* inside one of the islands */ all_outside_inner = 0; if (*dist == 0) { /* the line intersected with the isle boundary * -> line is partially inside the area */ *fangle = *tangle = -9.; *falong = *talong = 0.; return 1; } /* else continue with next point */ } } /* end inside outer ring */ } else { /* point not in box of outer ring */ all_inside_outer = 0; } /* exactly on boundary */ if (*dist == 0) return 1; } /* if all points are inside the outer ring and inside inner rings, * there could still be an intersection with one of the inner rings */ if (all_inside_outer) { if (all_outside_inner) { /* at least one point is really inside the area! * that should have been detected above */ G_fatal_error(_("At least one point is really inside the area!")); } /* else all points are inside one of the area isles * and we already have the minimum distance */ return 2; } /* if at least one point was found to be inside the outer ring, * but no point really inside the area, * and at least one point outside, * then there must be an intersection of the line with both * the outer ring and one of the isle boundaries */ /* if all line points are outside of the area, * intersection is still possible */ line2line(Points, type, aPoints, GV_BOUNDARY, fx, fy, fz, falong, fangle, tx, ty, tz, talong, tangle, dist, with_z); *talong = 0; if (*dist == 0) return 1; return 3; }