/*! \brief Reads next unread line each time called. Use Vect_rewind to reset. This function implements sequential access on level 2. \param Map vector map layer \param[out] line_p container used to store line points within \param[out] line_c container used to store line categories within \return line type ( > 0 ) \return 0 dead line \return -1 out of memory \return -2 end of file */ int V2_read_next_line_nat(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c) { register int line, ret; register struct P_line *Line; struct bound_box lbox, mbox; G_debug(3, "V2_read_next_line_nat()"); if (Map->Constraint_region_flag) Vect_get_constraint_box(Map, &mbox); while (1) { line = Map->next_line; if (line > Map->plus.n_lines) return (-2); Line = Map->plus.Line[line]; if (Line == NULL) { /* Dead line */ Map->next_line++; continue; } if ((Map->Constraint_type_flag && !(Line->type & Map->Constraint_type))) { Map->next_line++; continue; } ret = V2_read_line_nat(Map, line_p, line_c, Map->next_line++); if (Map->Constraint_region_flag) { Vect_line_box(line_p, &lbox); if (!Vect_box_overlap(&lbox, &mbox)) { continue; } } return ret; } /* NOTREACHED */ }
/*! \brief Read next line from coor file. This function implements sequential access on level 1. \param Map vector map layer \param[out] line_p container used to store line points within \param[out] line_c container used to store line categories within \return line type \return 0 dead line \return -2 end of table (last row) \return -1 out of memory */ int V1_read_next_line_nat(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c) { int itype; off_t offset; struct bound_box lbox, mbox; G_debug(3, "V1_read_next_line_nat()"); if (Map->Constraint_region_flag) Vect_get_constraint_box(Map, &mbox); while (1) { offset = dig_ftell(&(Map->dig_fp)); itype = read_line_nat(Map, line_p, line_c, offset); if (itype < 0) return (itype); if (itype == 0) /* is it DEAD? */ continue; /* Constraint on Type of line * Default is all of Point, Line, Area and whatever else comes along */ if (Map->Constraint_type_flag) { if (!(itype & Map->Constraint_type)) continue; } /* Constraint on specified region */ if (Map->Constraint_region_flag) { Vect_line_box(line_p, &lbox); if (!Vect_box_overlap(&lbox, &mbox)) continue; } return (itype); } /* NOTREACHED */ }
/*! \brief Read next feature from OGR layer. Skip empty features (level 1) This function implements sequential access. The action of this routine can be modified by: - Vect_read_constraint_region() - Vect_read_constraint_type() - Vect_remove_constraints() \param Map pointer to Map_info structure \param[out] line_p container used to store line points within \param[out] line_c container used to store line categories within \return feature type \return -2 no more features (EOF) \return -1 out of memory */ int V1_read_next_line_ogr(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c) { int itype; struct bound_box lbox, mbox; OGRFeatureH hFeature; OGRGeometryH hGeom; G_debug(3, "V1_read_next_line_ogr()"); if (line_p != NULL) Vect_reset_line(line_p); if (line_c != NULL) Vect_reset_cats(line_c); if (Map->Constraint_region_flag) Vect_get_constraint_box(Map, &mbox); while (TRUE) { /* Read feature to cache if necessary */ while (Map->fInfo.ogr.lines_next == Map->fInfo.ogr.lines_num) { hFeature = OGR_L_GetNextFeature(Map->fInfo.ogr.layer); if (hFeature == NULL) { return -2; } /* no more features */ hGeom = OGR_F_GetGeometryRef(hFeature); if (hGeom == NULL) { /* feature without geometry */ OGR_F_Destroy(hFeature); continue; } Map->fInfo.ogr.feature_cache_id = (int)OGR_F_GetFID(hFeature); if (Map->fInfo.ogr.feature_cache_id == OGRNullFID) { G_warning(_("OGR feature without ID")); } /* Cache the feature */ Map->fInfo.ogr.lines_num = 0; cache_feature(Map, hGeom, -1); G_debug(4, "%d lines read to cache", Map->fInfo.ogr.lines_num); OGR_F_Destroy(hFeature); Map->fInfo.ogr.lines_next = 0; /* next to be read from cache */ } /* Read next part of the feature */ G_debug(4, "read next cached line %d", Map->fInfo.ogr.lines_next); itype = Map->fInfo.ogr.lines_types[Map->fInfo.ogr.lines_next]; /* Constraint on Type of line * Default is all of Point, Line, Area and whatever else comes along */ if (Map->Constraint_type_flag) { if (!(itype & Map->Constraint_type)) { Map->fInfo.ogr.lines_next++; continue; } } /* Constraint on specified region */ if (Map->Constraint_region_flag) { Vect_line_box(Map->fInfo.ogr.lines[Map->fInfo.ogr.lines_next], &lbox); if (!Vect_box_overlap(&lbox, &mbox)) { Map->fInfo.ogr.lines_next++; continue; } } if (line_p != NULL) Vect_append_points(line_p, Map->fInfo.ogr.lines[Map->fInfo.ogr. lines_next], GV_FORWARD); if (line_c != NULL && Map->fInfo.ogr.feature_cache_id != OGRNullFID) Vect_cat_set(line_c, 1, Map->fInfo.ogr.feature_cache_id); Map->fInfo.ogr.lines_next++; G_debug(4, "next line read, type = %d", itype); return itype; } return -2; /* not reached */ }
int main(int argc, char *argv[]) { char *output, buf[DB_SQL_MAX]; double (*rng)(void) = G_drand48; double zmin, zmax; int seed; int i, j, k, n, type, usefloat; int area, nareas, field; struct boxlist *List = NULL; BOX_SIZE *size_list = NULL; int alloc_size_list = 0; struct Map_info In, Out; struct line_pnts *Points; struct line_cats *Cats; struct cat_list *cat_list; struct bound_box box; struct Cell_head window; struct GModule *module; struct { struct Option *input, *field, *cats, *where, *output, *nsites, *zmin, *zmax, *zcol, *ztype, *seed; } parm; struct { struct Flag *z, *notopo, *a; } flag; struct field_info *Fi; dbDriver *driver; dbTable *table; dbString sql; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("sampling")); G_add_keyword(_("statistics")); G_add_keyword(_("random")); module->description = _("Generates random 2D/3D vector points."); parm.output = G_define_standard_option(G_OPT_V_OUTPUT); parm.nsites = G_define_option(); parm.nsites->key = "n"; parm.nsites->type = TYPE_INTEGER; parm.nsites->required = YES; parm.nsites->description = _("Number of points to be created"); parm.input = G_define_standard_option(G_OPT_V_INPUT); parm.input->required = NO; parm.input->description = _("Restrict points to areas in input vector"); parm.input->guisection = _("Selection"); parm.field = G_define_standard_option(G_OPT_V_FIELD_ALL); parm.field->guisection = _("Selection"); parm.cats = G_define_standard_option(G_OPT_V_CATS); parm.cats->guisection = _("Selection"); parm.where = G_define_standard_option(G_OPT_DB_WHERE); parm.where->guisection = _("Selection"); parm.zmin = G_define_option(); parm.zmin->key = "zmin"; parm.zmin->type = TYPE_DOUBLE; parm.zmin->required = NO; parm.zmin->description = _("Minimum z height (needs -z flag or column name)"); parm.zmin->answer = "0.0"; parm.zmin->guisection = _("3D output"); parm.zmax = G_define_option(); parm.zmax->key = "zmax"; parm.zmax->type = TYPE_DOUBLE; parm.zmax->required = NO; parm.zmax->description = _("Maximum z height (needs -z flag or column name)"); parm.zmax->answer = "0.0"; parm.zmax->guisection = _("3D output"); parm.seed = G_define_option(); parm.seed->key = "seed"; parm.seed->type = TYPE_INTEGER; parm.seed->required = NO; parm.seed->description = _("The seed to initialize the random generator. If not set the process ID is used"); parm.zcol = G_define_standard_option(G_OPT_DB_COLUMN); parm.zcol->label = _("Name of column for z values"); parm.zcol->description = _("Writes z values to column"); parm.zcol->guisection = _("3D output"); parm.ztype = G_define_option(); parm.ztype->key = "column_type"; parm.ztype->type = TYPE_STRING; parm.ztype->required = NO; parm.ztype->multiple = NO; parm.ztype->description = _("Type of column for z values"); parm.ztype->options = "integer,double precision"; parm.ztype->answer = "double precision"; parm.ztype->guisection = _("3D output"); flag.z = G_define_flag(); flag.z->key = 'z'; flag.z->description = _("Create 3D output"); flag.z->guisection = _("3D output"); flag.a = G_define_flag(); flag.a->key = 'a'; flag.a->description = _("Generate n points for each individual area"); flag.notopo = G_define_standard_flag(G_FLG_V_TOPO); if (G_parser(argc, argv)) exit(EXIT_FAILURE); output = parm.output->answer; n = atoi(parm.nsites->answer); if(parm.seed->answer) seed = atoi(parm.seed->answer); if (n <= 0) { G_fatal_error(_("Number of points must be > 0 (%d given)"), n); } nareas = 0; cat_list = NULL; field = -1; if (parm.input->answer) { Vect_set_open_level(2); /* topology required */ if (2 > Vect_open_old2(&In, parm.input->answer, "", parm.field->answer)) G_fatal_error(_("Unable to open vector map <%s>"), parm.input->answer); if (parm.field->answer) field = Vect_get_field_number(&In, parm.field->answer); if ((parm.cats->answer || parm.where->answer) && field == -1) { G_warning(_("Invalid layer number (%d). Parameter '%s' or '%s' specified, assuming layer '1'."), field, parm.cats->key, parm.where->key); field = 1; } if (field > 0) cat_list = Vect_cats_set_constraint(&In, field, parm.where->answer, parm.cats->answer); nareas = Vect_get_num_areas(&In); if (nareas == 0) { Vect_close(&In); G_fatal_error(_("No areas in vector map <%s>"), parm.input->answer); } } else { if (flag.a->answer) G_fatal_error(_("The <-%c> flag requires an input vector with areas"), flag.a->key); } /* create new vector map */ if (-1 == Vect_open_new(&Out, output, flag.z->answer ? WITH_Z : WITHOUT_Z)) G_fatal_error(_("Unable to create vector map <%s>"), output); Vect_set_error_handler_io(NULL, &Out); /* Do we need to write random values into attribute table? */ usefloat = -1; if (parm.zcol->answer) { Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE); driver = db_start_driver_open_database(Fi->driver, Vect_subst_var(Fi->database, &Out)); if (driver == NULL) { G_fatal_error(_("Unable to open database <%s> by driver <%s>"), Vect_subst_var(Fi->database, &Out), Fi->driver); } db_set_error_handler_driver(driver); db_begin_transaction(driver); db_init_string(&sql); sprintf(buf, "create table %s (%s integer, %s %s)", Fi->table, GV_KEY_COLUMN, parm.zcol->answer, parm.ztype->answer); db_set_string(&sql, buf); Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database, Fi->driver); /* Create table */ G_debug(3, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { G_fatal_error(_("Unable to create table: %s"), db_get_string(&sql)); } /* Create index */ if (db_create_index2(driver, Fi->table, Fi->key) != DB_OK) G_warning(_("Unable to create index")); /* Grant */ 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); } /* OK. Let's check what type of column user has created */ db_set_string(&sql, Fi->table); if (db_describe_table(driver, &sql, &table) != DB_OK) { G_fatal_error(_("Unable to describe table <%s>"), Fi->table); } if (db_get_table_number_of_columns(table) != 2) { G_fatal_error(_("Table should contain only two columns")); } type = db_get_column_sqltype(db_get_table_column(table, 1)); if (type == DB_SQL_TYPE_SMALLINT || type == DB_SQL_TYPE_INTEGER) usefloat = 0; if (type == DB_SQL_TYPE_REAL || type == DB_SQL_TYPE_DOUBLE_PRECISION) usefloat = 1; if (usefloat < 0) { G_fatal_error(_("You have created unsupported column type. This module supports only INTEGER" " and DOUBLE PRECISION column types.")); } } Vect_hist_command(&Out); /* Init the random seed */ if(parm.seed->answer) G_srand48(seed); else G_srand48_auto(); G_get_window(&window); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); if (nareas > 0) { int first = 1, count; struct bound_box abox, bbox; box.W = window.west; box.E = window.east; box.S = window.south; box.N = window.north; box.B = -PORT_DOUBLE_MAX; box.T = PORT_DOUBLE_MAX; count = 0; for (i = 1; i <= nareas; i++) { if (!Vect_get_area_centroid(&In, i)) continue; if (field > 0) { if (Vect_get_area_cats(&In, i, Cats)) continue; if (!Vect_cats_in_constraint(Cats, field, cat_list)) continue; } Vect_get_area_box(&In, i, &abox); if (!Vect_box_overlap(&abox, &box)) continue; if (first) { Vect_box_copy(&bbox, &abox); first = 0; } else Vect_box_extend(&bbox, &abox); count++; } if (count == 0) { Vect_close(&In); Vect_close(&Out); Vect_delete(output); G_fatal_error(_("Selected areas in input vector <%s> do not overlap with the current region"), parm.input->answer); } Vect_box_copy(&box, &bbox); /* does the vector overlap with the current region ? */ if (box.W >= window.east || box.E <= window.west || box.S >= window.north || box.N <= window.south) { Vect_close(&In); Vect_close(&Out); Vect_delete(output); G_fatal_error(_("Input vector <%s> does not overlap with the current region"), parm.input->answer); } /* try to reduce the current region */ if (window.east > box.E) window.east = box.E; if (window.west < box.W) window.west = box.W; if (window.north > box.N) window.north = box.N; if (window.south < box.S) window.south = box.S; List = Vect_new_boxlist(1); alloc_size_list = 10; size_list = G_malloc(alloc_size_list * sizeof(BOX_SIZE)); } zmin = zmax = 0; if (flag.z->answer || parm.zcol->answer) { zmax = atof(parm.zmax->answer); zmin = atof(parm.zmin->answer); } G_message(_("Generating points...")); if (flag.a->answer && nareas > 0) { struct bound_box abox, bbox; int cat = 1; /* n points for each area */ nareas = Vect_get_num_areas(&In); G_percent(0, nareas, 1); for (area = 1; area <= nareas; area++) { G_percent(area, nareas, 1); if (!Vect_get_area_centroid(&In, area)) continue; if (field > 0) { if (Vect_get_area_cats(&In, area, Cats)) continue; if (!Vect_cats_in_constraint(Cats, field, cat_list)) { continue; } } box.W = window.west; box.E = window.east; box.S = window.south; box.N = window.north; box.B = -PORT_DOUBLE_MAX; box.T = PORT_DOUBLE_MAX; Vect_get_area_box(&In, area, &abox); if (!Vect_box_overlap(&box, &abox)) continue; bbox = abox; if (bbox.W < box.W) bbox.W = box.W; if (bbox.E > box.E) bbox.E = box.E; if (bbox.S < box.S) bbox.S = box.S; if (bbox.N > box.N) bbox.N = box.N; for (i = 0; i < n; ++i) { double x, y, z; int outside = 1; int ret; Vect_reset_line(Points); Vect_reset_cats(Cats); while (outside) { x = rng() * (bbox.W - bbox.E) + bbox.E; y = rng() * (bbox.N - bbox.S) + bbox.S; z = rng() * (zmax - zmin) + zmin; ret = Vect_point_in_area(x, y, &In, area, &abox); G_debug(3, " area = %d Vect_point_in_area() = %d", area, ret); if (ret >= 1) { outside = 0; } } if (flag.z->answer) Vect_append_point(Points, x, y, z); else Vect_append_point(Points, x, y, 0.0); if (parm.zcol->answer) { sprintf(buf, "insert into %s values ( %d, ", Fi->table, i + 1); db_set_string(&sql, buf); /* Round random value if column is integer type */ if (usefloat) sprintf(buf, "%f )", z); else sprintf(buf, "%.0f )", z); db_append_string(&sql, buf); G_debug(3, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { G_fatal_error(_("Cannot insert new row: %s"), db_get_string(&sql)); } } Vect_cat_set(Cats, 1, cat++); Vect_write_line(&Out, GV_POINT, Points, Cats); } } } else { /* n points in total */ for (i = 0; i < n; ++i) { double x, y, z; G_percent(i, n, 4); Vect_reset_line(Points); Vect_reset_cats(Cats); x = rng() * (window.west - window.east) + window.east; y = rng() * (window.north - window.south) + window.south; z = rng() * (zmax - zmin) + zmin; if (nareas) { int outside = 1; do { /* select areas by box */ box.E = x; box.W = x; box.N = y; box.S = y; box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; Vect_select_areas_by_box(&In, &box, List); G_debug(3, " %d areas selected by box", List->n_values); /* sort areas by size, the smallest is likely to be the nearest */ if (alloc_size_list < List->n_values) { alloc_size_list = List->n_values; size_list = G_realloc(size_list, alloc_size_list * sizeof(BOX_SIZE)); } k = 0; for (j = 0; j < List->n_values; j++) { area = List->id[j]; if (!Vect_get_area_centroid(&In, area)) continue; if (field > 0) { if (Vect_get_area_cats(&In, area, Cats)) continue; if (!Vect_cats_in_constraint(Cats, field, cat_list)) { continue; } } List->id[k] = List->id[j]; List->box[k] = List->box[j]; size_list[k].i = List->id[k]; box = List->box[k]; size_list[k].box = List->box[k]; size_list[k].size = (box.N - box.S) * (box.E - box.W); k++; } List->n_values = k; if (List->n_values == 2) { /* simple swap */ if (size_list[1].size < size_list[0].size) { size_list[0].i = List->id[1]; size_list[1].i = List->id[0]; size_list[0].box = List->box[1]; size_list[1].box = List->box[0]; } } else if (List->n_values > 2) qsort(size_list, List->n_values, sizeof(BOX_SIZE), sort_by_size); for (j = 0; j < List->n_values; j++) { int ret; area = size_list[j].i; ret = Vect_point_in_area(x, y, &In, area, &size_list[j].box); G_debug(3, " area = %d Vect_point_in_area() = %d", area, ret); if (ret >= 1) { outside = 0; break; } } if (outside) { x = rng() * (window.west - window.east) + window.east; y = rng() * (window.north - window.south) + window.south; z = rng() * (zmax - zmin) + zmin; } } while (outside); } if (flag.z->answer) Vect_append_point(Points, x, y, z); else Vect_append_point(Points, x, y, 0.0); if (parm.zcol->answer) { sprintf(buf, "insert into %s values ( %d, ", Fi->table, i + 1); db_set_string(&sql, buf); /* Round random value if column is integer type */ if (usefloat) sprintf(buf, "%f )", z); else sprintf(buf, "%.0f )", z); db_append_string(&sql, buf); G_debug(3, db_get_string(&sql)); if (db_execute_immediate(driver, &sql) != DB_OK) { G_fatal_error(_("Cannot insert new row: %s"), db_get_string(&sql)); } } Vect_cat_set(Cats, 1, i + 1); Vect_write_line(&Out, GV_POINT, Points, Cats); } G_percent(1, 1, 1); } if (parm.zcol->answer) { db_commit_transaction(driver); db_close_database_shutdown_driver(driver); } if (!flag.notopo->answer) { Vect_build(&Out); } Vect_close(&Out); exit(EXIT_SUCCESS); }
/* calculate distance parameters between two primitives * return 1 point to point * return 2 point to line * return 1 line to line */ int line2line(struct line_pnts *FPoints, int ftype, struct line_pnts *TPoints, int ttype, 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, fseg, tseg, tmp_seg; double tmp_dist, tmp_x, tmp_y, tmp_z, tmp_along; int ret = 1; static struct line_pnts *iPoints = NULL; if (!iPoints) { iPoints = 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 = FPoints->x[0]; *fy = FPoints->y[0]; *fz = FPoints->z[0]; *tx = TPoints->x[0]; *ty = TPoints->y[0]; *tz = TPoints->z[0]; tmp_z = 0; /* point -> point */ if ((ftype & GV_POINTS) && (ttype & GV_POINTS)) { line_distance(TPoints, FPoints->x[0], FPoints->y[0], FPoints->z[0], with_z, tx, ty, tz, dist, NULL, talong); } /* point -> line and line -> line */ if ((ttype & GV_LINES)) { fseg = tseg = 0; /* calculate the min distance between each point in fline with tline */ for (i = 0; i < FPoints->n_points; i++) { tmp_seg = line_distance(TPoints, FPoints->x[i], FPoints->y[i], FPoints->z[i], with_z, &tmp_x, &tmp_y, &tmp_z, &tmp_dist, NULL, &tmp_along); if (*dist > tmp_dist) { *dist = tmp_dist; *fx = FPoints->x[i]; *fy = FPoints->y[i]; *fz = FPoints->z[i]; *tx = tmp_x; *ty = tmp_y; *tz = tmp_z; *talong = tmp_along; tseg = tmp_seg; fseg = i + 1; } } *tangle = sangle(TPoints, tseg); if (FPoints->n_points > 1 && fseg > 0) { int np = FPoints->n_points; fseg--; if (fseg > 0) { FPoints->n_points = fseg + 1; *falong = Vect_line_length(FPoints); FPoints->n_points = np; } np = fseg; if (fseg == 0) fseg = 1; *fangle = sangle(FPoints, fseg); } ret++; } /* line -> point and line -> line */ if (ftype & GV_LINES) { fseg = tseg = 0; /* calculate the min distance between each point in tline with fline */ for (i = 0; i < TPoints->n_points; i++) { tmp_seg = line_distance(FPoints, TPoints->x[i], TPoints->y[i], TPoints->z[i], with_z, &tmp_x, &tmp_y, &tmp_z, &tmp_dist, NULL, &tmp_along); if (*dist > tmp_dist) { *dist = tmp_dist; *fx = tmp_x; *fy = tmp_y; *fz = tmp_z; *falong = tmp_along; *tx = TPoints->x[i]; *ty = TPoints->y[i]; *tz = TPoints->z[i]; fseg = tmp_seg; tseg = i + 1; } } *fangle = sangle(FPoints, fseg); if (TPoints->n_points > 1 && tseg > 0) { int np = TPoints->n_points; tseg--; if (tseg > 0) { TPoints->n_points = tseg + 1; *talong = Vect_line_length(TPoints); TPoints->n_points = np; } np = tseg; if (tseg == 0) tseg = 1; *tangle = sangle(TPoints, tseg); } ret++; if ((ttype & GV_LINES) && *dist > 0) { /* check for line intersection */ struct bound_box fbox, tbox; get_line_box(FPoints, &fbox); get_line_box(TPoints, &tbox); if (Vect_box_overlap(&fbox, &tbox)) { Vect_reset_line(iPoints); Vect_line_get_intersections(FPoints, TPoints, iPoints, with_z); if (iPoints->n_points) { *dist = 0; *fx = *tx = iPoints->x[0]; *fy = *ty = iPoints->y[0]; *fz = *tz = iPoints->z[0]; /* falong, talong */ fseg = line_distance(FPoints, iPoints->x[0], iPoints->y[0], iPoints->z[0], with_z, NULL, NULL, NULL, NULL, NULL, falong); tseg = line_distance(TPoints, iPoints->x[0], iPoints->y[0], iPoints->z[0], with_z, NULL, NULL, NULL, NULL, NULL, talong); /* fangle, tangle */ *fangle = sangle(FPoints, fseg); *tangle = sangle(TPoints, tseg); } } } } return ret; }