Example #1
0
/*!
  \brief Writes feature on level 2

  \param Map pointer to Map_info structure
  \param type feature type
  \param points pointer to line_pnts structure (feature geometry)
  \param cats pointer to line_cats structure (feature categories)

  \return feature offset into file
  \return -1 on error
*/
off_t V2_write_line_ogr(struct Map_info *Map, int type,
                        const struct line_pnts *points, const struct line_cats *cats)
{
    int line;
    off_t offset;
    struct Plus_head *plus;
    struct bound_box box;

    line = 0;

    G_debug(3, "V2_write_line_ogr()");

    offset = V1_write_line_ogr(Map, type, points, cats);
    if (offset < 0)
        return -1;

    /* Update topology */
    plus = &(Map->plus);
    /* Add line */
    if (plus->built >= GV_BUILD_BASE) {
        dig_line_box(points, &box);
        line = dig_add_line(plus, type, points, &box, offset);
        G_debug(3, "  line added to topo with id = %d", line);
        if (line == 1)
            Vect_box_copy(&(plus->box), &box);
        else
            Vect_box_extend(&(plus->box), &box);

        V2__add_line_to_topo_ogr(Map, line, points, cats);
    }


    G_debug(3, "updated lines : %d , updated nodes : %d", plus->n_uplines,
            plus->n_upnodes);

    /* returns int line, but is defined as off_t for compatibility with
     * Write_line_array in write.c */

    return line;

}
Example #2
0
/* code taken from Vect_build_nat() */
int level_one_info(struct Map_info *Map)
{
    struct Plus_head *plus;
    int i, type, first = 1;
    off_t offset;
    struct line_pnts *Points;
    struct line_cats *Cats;
    struct bound_box box;

    int n_primitives, n_points, n_lines, n_boundaries, n_centroids;
    int n_faces, n_kernels;

    G_debug(1, "Count vector objects for level 1");

    plus = &(Map->plus);

    n_primitives = n_points = n_lines = n_boundaries = n_centroids = 0;
    n_faces = n_kernels = 0;

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    
    Vect_rewind(Map);
    /* G_message(_("Registering primitives...")); */
    i = 1;
    while (1) {
	/* register line */
	type = Vect_read_next_line(Map, Points, Cats);

	/* Note: check for dead lines is not needed, because they are skipped by V1_read_next_line_nat() */
	if (type == -1) {
	    G_warning(_("Unable to read vector map"));
	    return 0;
	}
	else if (type == -2) {
	    break;
	}

	/* count features */
	n_primitives++;
	
	if (type & GV_POINT)  /* probably most common */
	    n_points++;
	else if (type & GV_LINE)
	    n_lines++;
	else if (type & GV_BOUNDARY)
	    n_boundaries++;
	else if (type & GV_CENTROID)
	    n_centroids++;
	else if (type & GV_KERNEL)
	    n_kernels++;
	else if (type & GV_FACE)
	    n_faces++;

	offset = Map->head.last_offset;

	G_debug(3, "Register line: offset = %lu", (unsigned long)offset);
	dig_line_box(Points, &box);
	if (first == 1) {
	    Vect_box_copy(&(plus->box), &box);
	    first = 0;
	}
	else
	    Vect_box_extend(&(plus->box), &box);

	/* can't print progress, unfortunately */
/*
	if (G_verbose() > G_verbose_min() && i % 1000 == 0) {
	    if (format == G_INFO_FORMAT_PLAIN)
		fprintf(stderr, "%d..", i);
	    else
		fprintf(stderr, "%11d\b\b\b\b\b\b\b\b\b\b\b", i);
	}
	i++;
*/
    }

    /* save result in plus */
    plus->n_lines = n_primitives;
    plus->n_plines = n_points;
    plus->n_llines = n_lines;
    plus->n_blines = n_boundaries;
    plus->n_clines = n_centroids;
    plus->n_klines = n_kernels;
    plus->n_flines = n_faces;

    return 1;
}
Example #3
0
/*!
   \brief Dump topology to file

   \param Map vector map
   \param out file for output (stdout/stderr for example)

   \return 1 on success
   \return 0 on error
 */
int Vect_topo_dump(const struct Map_info *Map, FILE *out)
{
    int i, j, line, isle;
    float angle_deg;
    struct P_node *Node;
    struct P_line *Line;
    struct P_area *Area;
    struct P_isle *Isle;
    struct bound_box box;
    const struct Plus_head *plus;

    plus = &(Map->plus);
    
    fprintf(out, "---------- TOPOLOGY DUMP ----------\n");
    fprintf(out, "Map:             %s\n", Vect_get_full_name(Map));
    fprintf(out, "Topology format: ");
    if (Map->format == GV_FORMAT_NATIVE)
        fprintf(out, "native");
    else if (Map->format == GV_FORMAT_POSTGIS &&
             Map->fInfo.pg.toposchema_name) {
        fprintf(out, "PostGIS");
    }
    else {
        fprintf(out, "pseudo (simple features)");
        if (Map->format == GV_FORMAT_OGR)
            fprintf(out, " @ OGR");
        else
            fprintf(out, " @ PostgreSQL");
    }
    fprintf(out, "\n");
    
    fprintf(out, SEP);
     
    /* box */
    Vect_box_copy(&box, &(plus->box));
    fprintf(out, "N,S,E,W,T,B: %f, %f, %f, %f, %f, %f\n", box.N, box.S,
	    box.E, box.W, box.T, box.B);

    fprintf(out, SEP);
    
    /* nodes */
    fprintf(out, "Nodes (%d nodes, alive + dead):\n", plus->n_nodes);
    for (i = 1; i <= plus->n_nodes; i++) {
	if (plus->Node[i] == NULL) {
	    continue;
	}
	Node = plus->Node[i];
	fprintf(out, "node = %d, n_lines = %d, xyz = %f, %f, %f\n", i,
		Node->n_lines, Node->x, Node->y, Node->z);
	for (j = 0; j < Node->n_lines; j++) {
	    line = Node->lines[j];
	    Line = plus->Line[abs(line)];
            angle_deg = (Node->angles[j] * 180) / M_PI;
            if (angle_deg < 0)
                angle_deg += 360;
	    fprintf(out, "  line = %3d, type = %d, angle = %f (%.4f)\n", line,
		    Line->type, Node->angles[j], angle_deg);
	}
    }

    fprintf(out, SEP);
    
    /* lines */
    fprintf(out, "Lines (%d lines, alive + dead):\n", plus->n_lines);
    for (i = 1; i <= plus->n_lines; i++) {
	if (plus->Line[i] == NULL) {
	    continue;
	}
	Line = plus->Line[i];
	if (Line->type == GV_POINT) {
	    fprintf(out, "line = %d, type = %d, offset = %lu\n",
		    i, Line->type, (unsigned long)Line->offset);
	}
	else if (Line->type == GV_CENTROID) {
	    struct P_topo_c *topo = (struct P_topo_c *)Line->topo;

	    fprintf(out, "line = %d, type = %d, offset = %lu, area = %d\n",
		    i, Line->type, (unsigned long)Line->offset, topo->area);
	}
	else if (Line->type == GV_LINE) {
	    struct P_topo_l *topo = (struct P_topo_l *)Line->topo;

	    fprintf(out, "line = %d, type = %d, offset = %lu, n1 = %d, n2 = %d\n",
		    i, Line->type, (unsigned long)Line->offset, topo->N1,
		    topo->N2);
	}
	else if (Line->type == GV_BOUNDARY) {
	    struct P_topo_b *topo = (struct P_topo_b *)Line->topo;

	    fprintf(out, "line = %d, type = %d, offset = %lu, n1 = %d, n2 = %d, "
		    "left = %d, right = %d\n",
		    i, Line->type, (unsigned long)Line->offset, topo->N1,
		    topo->N2, topo->left, topo->right);
	}
	else if (Line->type == GV_FACE) {
	    struct P_topo_f *topo = (struct P_topo_f *)Line->topo;

	    fprintf(out, "line = %d, type = %d, offset = %lu, e1 = %d, e2 = %d, "
		    "e3 = %d, left = %d, right = %d\n",
		    i, Line->type, (unsigned long)Line->offset, topo->E[0],
		    topo->E[1], topo->E[2], topo->left, topo->right);
	}
	else if (Line->type == GV_KERNEL) {
	    struct P_topo_k *topo = (struct P_topo_k *)Line->topo;

	    fprintf(out, "line = %d, type = %d, offset = %lu, volume = %d",
		    i, Line->type, (unsigned long)Line->offset, topo->volume);
	}
    }

    fprintf(out, SEP);
    
    /* areas */
    fprintf(out, "Areas (%d areas, alive + dead):\n", plus->n_areas);
    for (i = 1; i <= plus->n_areas; i++) {
	if (plus->Area[i] == NULL) {
	    continue;
	}
	Area = plus->Area[i];

	fprintf(out, "area = %d, n_lines = %d, n_isles = %d centroid = %d\n",
		i, Area->n_lines, Area->n_isles, Area->centroid);

	for (j = 0; j < Area->n_lines; j++) {
	    line = Area->lines[j];
	    Line = plus->Line[abs(line)];
	    fprintf(out, "  line = %3d\n", line);
	}
	for (j = 0; j < Area->n_isles; j++) {
	    isle = Area->isles[j];
	    fprintf(out, "  isle = %3d\n", isle);
	}
    }

    fprintf(out, SEP);
    
    /* isles */
    fprintf(out, "Islands (%d islands, alive + dead):\n", plus->n_isles);
    for (i = 1; i <= plus->n_isles; i++) {
	if (plus->Isle[i] == NULL) {
	    continue;
	}
	Isle = plus->Isle[i];

	fprintf(out, "isle = %d, n_lines = %d area = %d\n", i, Isle->n_lines,
		Isle->area);

	for (j = 0; j < Isle->n_lines; j++) {
	    line = Isle->lines[j];
	    Line = plus->Line[abs(line)];
	    fprintf(out, "  line = %3d\n", line);
	}
    }

    return 1;
}
Example #4
0
int main(int argc, char **argv)
{
    struct GModule *module;
    struct Option *map_opt, *field_opt, *fs_opt, *vs_opt, *nv_opt, *col_opt,
	*where_opt, *file_opt;
    struct Flag *c_flag, *v_flag, *r_flag;
    dbDriver *driver;
    dbString sql, value_string;
    dbCursor cursor;
    dbTable *table;
    dbColumn *column;
    dbValue *value;
    struct field_info *Fi;
    int ncols, col, more;
    struct Map_info Map;
    char query[1024];
    struct ilist *list_lines;

    struct bound_box *min_box, *line_box;
    int i, line, area, init_box, cat;

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("database"));
    G_add_keyword(_("attribute table"));
    module->description = _("Prints vector map attributes.");

    map_opt = G_define_standard_option(G_OPT_V_MAP);
    field_opt = G_define_standard_option(G_OPT_V_FIELD);

    col_opt = G_define_standard_option(G_OPT_DB_COLUMNS);

    where_opt = G_define_standard_option(G_OPT_DB_WHERE);

    fs_opt = G_define_standard_option(G_OPT_F_SEP);
    fs_opt->description = _("Output field separator");
    fs_opt->guisection = _("Format");

    vs_opt = G_define_standard_option(G_OPT_F_SEP);
    vs_opt->key = "vs";
    vs_opt->description = _("Output vertical record separator");
    vs_opt->answer = NULL;
    vs_opt->guisection = _("Format");

    nv_opt = G_define_option();
    nv_opt->key = "nv";
    nv_opt->type = TYPE_STRING;
    nv_opt->required = NO;
    nv_opt->description = _("Null value indicator");
    nv_opt->guisection = _("Format");

    file_opt = G_define_standard_option(G_OPT_F_OUTPUT); 
    file_opt->key = "file";
    file_opt->required = NO; 
    file_opt->description = 
	_("Name for output file (if omitted or \"-\" output to stdout)"); 
    
    r_flag = G_define_flag();
    r_flag->key = 'r';
    r_flag->description =
	_("Print minimal region extent of selected vector features instead of attributes");

    c_flag = G_define_flag();
    c_flag->key = 'c';
    c_flag->description = _("Do not include column names in output");
    c_flag->guisection = _("Format");

    v_flag = G_define_flag();
    v_flag->key = 'v';
    v_flag->description = _("Vertical output (instead of horizontal)");
    v_flag->guisection = _("Format");

    G_gisinit(argv[0]);

    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    /* set input vector map name and mapset */
    if (file_opt->answer && strcmp(file_opt->answer, "-") != 0) { 
	if (NULL == freopen(file_opt->answer, "w", stdout)) { 
	    G_fatal_error(_("Unable to open file <%s> for writing"), file_opt->answer); 
	} 
    } 
    
    if (r_flag->answer) {
	min_box = (struct bound_box *) G_malloc(sizeof(struct bound_box));
	G_zero((void *)min_box, sizeof(struct bound_box));

	line_box = (struct bound_box *) G_malloc(sizeof(struct bound_box));
	list_lines = Vect_new_list();
    }
    else {
      min_box = line_box = NULL;
      list_lines = NULL;
    }

    db_init_string(&sql);
    db_init_string(&value_string);

    /* open input vector */
    if (!r_flag->answer)
	Vect_open_old_head2(&Map, map_opt->answer, "", field_opt->answer);
    else {
	if (2 > Vect_open_old2(&Map, map_opt->answer, "", field_opt->answer)) {
	    Vect_close(&Map);
	    G_fatal_error(_("Unable to open vector map <%s> at topology level. "
			   "Flag '%c' requires topology level."),
			  map_opt->answer, r_flag->key);
	}
    }

    if ((Fi = Vect_get_field2(&Map, field_opt->answer)) == NULL)
	G_fatal_error(_("Database connection not defined for layer <%s>"),
		      field_opt->answer);

    driver = db_start_driver_open_database(Fi->driver, Fi->database);

    if (!driver)
	G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
		      Fi->database, Fi->driver);

    if (col_opt->answer)
	sprintf(query, "SELECT %s FROM ", col_opt->answer);
    else
	sprintf(query, "SELECT * FROM ");

    db_set_string(&sql, query);
    db_append_string(&sql, Fi->table);

    if (where_opt->answer) {
	char *buf = NULL;

	buf = G_malloc((strlen(where_opt->answer) + 8));
	sprintf(buf, " WHERE %s", where_opt->answer);
	db_append_string(&sql, buf);
	G_free(buf);
    }

    if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK)
	G_fatal_error(_("Unable to open select cursor"));

    table = db_get_cursor_table(&cursor);
    ncols = db_get_table_number_of_columns(table);

    /* column names if horizontal output (ignore for -r) */
    if (!v_flag->answer && !c_flag->answer && !r_flag->answer) {
	for (col = 0; col < ncols; col++) {
	    column = db_get_table_column(table, col);
	    if (col)
		fprintf(stdout, "%s", fs_opt->answer);
	    fprintf(stdout, "%s", db_get_column_name(column));
	}
	fprintf(stdout, "\n");
    }

    init_box = 1;

    /* fetch the data */
    while (1) {
	if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
	    G_fatal_error(_("Unable to fetch data from table <%s>"),
			  Fi->table);

	if (!more)
	    break;

	cat = -1;
	for (col = 0; col < ncols; col++) {
	    column = db_get_table_column(table, col);
	    value = db_get_column_value(column);

	    if (cat < 0 && strcmp(Fi->key, db_get_column_name(column)) == 0) {
		cat = db_get_value_int(value);
		if (r_flag->answer)
		    break;
	    }

	    if (r_flag->answer)
		continue;

	    db_convert_column_value_to_string(column, &value_string);

	    if (!c_flag->answer && v_flag->answer)
		fprintf(stdout, "%s%s", db_get_column_name(column),
			fs_opt->answer);

	    if (col && !v_flag->answer)
		fprintf(stdout, "%s", fs_opt->answer);

	    if (nv_opt->answer && db_test_value_isnull(value))
		fprintf(stdout, "%s", nv_opt->answer);
	    else
		fprintf(stdout, "%s", db_get_string(&value_string));

	    if (v_flag->answer)
		fprintf(stdout, "\n");
	}

	if (r_flag->answer) {
	    /* get minimal region extent */
	    Vect_cidx_find_all(&Map, Vect_get_field_number(&Map, field_opt->answer), -1, cat, list_lines);
	    for (i = 0; i < list_lines->n_values; i++) {
		line = list_lines->value[i];
		area = Vect_get_centroid_area(&Map, line);
		if (area > 0) {
		    if (!Vect_get_area_box(&Map, area, line_box))
			G_fatal_error(_("Unable to get bounding box of area %d"),
				      area);
		}
		else {
		    if (!Vect_get_line_box(&Map, line, line_box))
			G_fatal_error(_("Unable to get bounding box of line %d"),
				      line);
		}
		if (init_box) {
		    Vect_box_copy(min_box, line_box);
		    init_box = 0;
		}
		else {
		    Vect_box_extend(min_box, line_box);
		}
	    }
	}
	else {
	    if (!v_flag->answer)
		fprintf(stdout, "\n");
	    else if (vs_opt->answer)
		fprintf(stdout, "%s\n", vs_opt->answer);
	}
    }

    if (r_flag->answer) {
	fprintf(stdout, "n=%f\n", min_box->N);
	fprintf(stdout, "s=%f\n", min_box->S);
	fprintf(stdout, "w=%f\n", min_box->W);
	fprintf(stdout, "e=%f\n", min_box->E);
	if (Vect_is_3d(&Map)) {
	    fprintf(stdout, "t=%f\n", min_box->T);
	    fprintf(stdout, "b=%f\n", min_box->B);
	}
	fflush(stdout);

	G_free((void *)min_box);
	G_free((void *)line_box);

	Vect_destroy_list(list_lines);
    }

    db_close_cursor(&cursor);
    db_close_database_shutdown_driver(driver);
    Vect_close(&Map);

    exit(EXIT_SUCCESS);
}
Example #5
0
/*!
   \brief Build topology 

   \param Map vector map
   \param build build level

   \return 1 on success
   \return 0 on error
 */
int Vect_build_nat(struct Map_info *Map, int build)
{
    struct Plus_head *plus;
    int i, s, type, line;
    off_t offset;
    int side, area;
    struct line_cats *Cats;
    struct P_line *Line;
    struct P_area *Area;
    struct bound_box box;
    
    G_debug(3, "Vect_build_nat() build = %d", build);

    plus = &(Map->plus);

    if (build == plus->built)
	return 1;		/* Do nothing */

    /* Check if upgrade or downgrade */
    if (build < plus->built) {
        /* -> downgrade */
	Vect__build_downgrade(Map, build);
        return 1;
    }

    /* -> upgrade */
    if (!Points)
        Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    
    if (plus->built < GV_BUILD_BASE) {
        int npoints, c;
        
	/* 
	 *  We shall go through all primitives in coor file and add
	 *  new node for each end point to nodes structure if the node
	 *  with the same coordinates doesn't exist yet.
	 */

	/* register lines, create nodes */
	Vect_rewind(Map);
	G_message(_("Registering primitives..."));
	i = 0;
	npoints = 0;
	while (TRUE) {
	    /* register line */
	    type = Vect_read_next_line(Map, Points, Cats);

	    /* Note: check for dead lines is not needed, because they
               are skipped by V1_read_next_line() */
	    if (type == -1) {
		G_warning(_("Unable to read vector map"));
		return 0;
	    }
	    else if (type == -2) {
		break;
	    }

	    G_progress(++i, 1e4);
	    
	    npoints += Points->n_points;

	    offset = Map->head.last_offset;

	    G_debug(3, "Register line: offset = %lu", (unsigned long)offset);
	    dig_line_box(Points, &box);
	    line = dig_add_line(plus, type, Points, &box, offset);
	    if (line == 1)
		Vect_box_copy(&(plus->box), &box);
	    else
		Vect_box_extend(&(plus->box), &box);

	    /* Add all categories to category index */
	    if (build == GV_BUILD_ALL) {
		for (c = 0; c < Cats->n_cats; c++) {
		    dig_cidx_add_cat(plus, Cats->field[c], Cats->cat[c],
				     line, type);
		}
		if (Cats->n_cats == 0)	/* add field 0, cat 0 */
		    dig_cidx_add_cat(plus, 0, 0, line, type);
	    }
	}
	G_progress(1, 1);

	G_message(_n("One primitive registered", "%d primitives registered", plus->n_lines), plus->n_lines);
	G_message(_n("One vertex registered", "%d vertices registered", npoints), npoints);

	plus->built = GV_BUILD_BASE;
    }

    if (build < GV_BUILD_AREAS)
	return 1;

    if (plus->built < GV_BUILD_AREAS) {
	/* Build areas */
	/* Go through all bundaries and try to build area for both sides */
	G_important_message(_("Building areas..."));
	for (line = 1; line <= plus->n_lines; line++) {
	    G_percent(line, plus->n_lines, 1);

	    /* build */
	    if (plus->Line[line] == NULL) {
		continue;
	    }			/* dead line */
	    Line = plus->Line[line];
	    if (Line->type != GV_BOUNDARY) {
		continue;
	    }

	    for (s = 0; s < 2; s++) {
		if (s == 0)
		    side = GV_LEFT;
		else
		    side = GV_RIGHT;

		G_debug(3, "Build area for line = %d, side = %d", line, side);
		Vect_build_line_area(Map, line, side);
	    }
	}
	G_message(_n("One area built", "%d areas built", plus->n_areas), plus->n_areas);
	G_message(_n("One isle built", "%d isles built", plus->n_isles), plus->n_isles);
	plus->built = GV_BUILD_AREAS;
    }

    if (build < GV_BUILD_ATTACH_ISLES)
	return 1;

    /* Attach isles to areas */
    if (plus->built < GV_BUILD_ATTACH_ISLES) {
	G_important_message(_("Attaching islands..."));
	for (i = 1; i <= plus->n_isles; i++) {
	    G_percent(i, plus->n_isles, 1);
	    Vect_attach_isle(Map, i);
	}
	plus->built = GV_BUILD_ATTACH_ISLES;
    }

    if (build < GV_BUILD_CENTROIDS)
	return 1;

    /* Attach centroids to areas */
    if (plus->built < GV_BUILD_CENTROIDS) {
	int nlines;
	struct P_topo_c *topo;

	G_important_message(_("Attaching centroids..."));

	nlines = Vect_get_num_lines(Map);
	for (line = 1; line <= nlines; line++) {
	    G_percent(line, nlines, 1);

	    Line = plus->Line[line];
	    if (!Line)
		continue;	/* Dead */

	    if (Line->type != GV_CENTROID)
		continue;

	    Vect_read_line(Map, Points, NULL, line);
	    area = Vect_find_area(Map, Points->x[0], Points->y[0]);

	    if (area > 0) {
		G_debug(3, "Centroid (line=%d) in area %d", line, area);

		Area = plus->Area[area];
		topo = (struct P_topo_c *)Line->topo;

		if (Area->centroid == 0) {	/* first */
		    Area->centroid = line;
		    topo->area = area;
		}
		else {		/* duplicate */
		    topo->area = -area;
		}
	    }
	}
	plus->built = GV_BUILD_CENTROIDS;
    }

    /* Add areas to category index */
    for (i = 1; i <= plus->n_areas; i++) {
	int c;

	if (plus->Area[i] == NULL)
	    continue;

	if (plus->Area[i]->centroid > 0) {
	    Vect_read_line(Map, NULL, Cats, plus->Area[i]->centroid);

	    for (c = 0; c < Cats->n_cats; c++) {
		dig_cidx_add_cat(plus, Cats->field[c], Cats->cat[c], i,
				 GV_AREA);
	    }
	}

	if (plus->Area[i]->centroid == 0 || Cats->n_cats == 0)	/* no centroid or no cats */
	    dig_cidx_add_cat(plus, 0, 0, i, GV_AREA);
    }

    Vect_destroy_cats_struct(Cats);
    
    return 1;
}
Example #6
0
File: main.c Project: caomw/grass
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);
}