|
@@ -4,15 +4,18 @@
|
|
|
* MODULE: v.extrude
|
|
|
*
|
|
|
* AUTHOR(S): Jachym Cepicky <jachym.cepicky gmail.com>
|
|
|
+ * Support for points & OGR support (08/2007, 2009), new
|
|
|
+ * parameters cats, where, method (2013) added by Martin
|
|
|
+ * Landa <landa.martin gmail.com>
|
|
|
+ *
|
|
|
+ * PURPOSE: "Extrudes" flat polygons and lines to 3D with defined height
|
|
|
+ * Useful for creating buildings for displaying with NVIZ
|
|
|
+ *
|
|
|
* Based on v.example by Radim Blazek
|
|
|
* Inspired by d.vect and v.drape
|
|
|
* Coding help and code cleaning by Markus Neteler
|
|
|
- * Support for points & OGR support added by Martin Landa (08/2007 / 2009)
|
|
|
*
|
|
|
- * PURPOSE: "Extrudes" flat polygons and lines to 3D with defined height
|
|
|
- * Useful for creating buildings for displaying with NVIZ
|
|
|
- *
|
|
|
- * COPYRIGHT: (C) 2005-2010 by the GRASS Development Team
|
|
|
+ * COPYRIGHT: (C) 2005-2010,2013 by the GRASS Development Team
|
|
|
*
|
|
|
* This program is free software under the GNU General
|
|
|
* Public License (>=v2). Read the file COPYING that comes
|
|
@@ -27,44 +30,39 @@
|
|
|
#include <grass/glocale.h>
|
|
|
#include <grass/dbmi.h>
|
|
|
|
|
|
-static int extrude(struct Map_info *, struct Map_info *,
|
|
|
- struct line_cats *, struct line_pnts *,
|
|
|
- int, int, double, double, struct Cell_head, int, int);
|
|
|
+#include "local_proto.h"
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
{
|
|
|
struct GModule *module;
|
|
|
- struct Option *old, *new, *zshift, *height, *elevation, *hcolumn,
|
|
|
- *type_opt, *field_opt;
|
|
|
- struct Flag *t_flag;
|
|
|
-
|
|
|
+ struct {
|
|
|
+ struct Option *input, *output, *zshift, *height, *elevation, *hcolumn,
|
|
|
+ *type, *field, *cats, *where, *interp;
|
|
|
+ } opt;
|
|
|
+ struct {
|
|
|
+ struct Flag *trace;
|
|
|
+ } flag;
|
|
|
+
|
|
|
struct Map_info In, Out;
|
|
|
struct line_pnts *Points;
|
|
|
struct line_cats *Cats;
|
|
|
struct bound_box map_box;
|
|
|
|
|
|
+ struct cat_list *cat_list;
|
|
|
+
|
|
|
struct Cell_head window;
|
|
|
- struct cat_list *Clist;
|
|
|
-
|
|
|
+
|
|
|
int field;
|
|
|
- int i, only_type, cat, ctype = -1, fdrast = -1, areanum = 0;
|
|
|
- int nelements;
|
|
|
- int line, type;
|
|
|
- int area, trace, centroid;
|
|
|
- double objheight, voffset;
|
|
|
-
|
|
|
- /* dbmi */
|
|
|
+ int only_type, cat;
|
|
|
+ int fdrast, interp_method;
|
|
|
+ int process_area, trace;
|
|
|
+ double objheight, objheight_default, voffset;
|
|
|
+
|
|
|
struct field_info *Fi;
|
|
|
dbDriver *driver = NULL;
|
|
|
- char query[1024];
|
|
|
- dbString sql;
|
|
|
- dbCursor cursor;
|
|
|
- dbTable *table;
|
|
|
- dbColumn *column;
|
|
|
- dbValue *value;
|
|
|
- int more;
|
|
|
+
|
|
|
char *comment;
|
|
|
-
|
|
|
+
|
|
|
module = G_define_module();
|
|
|
G_add_keyword(_("vector"));
|
|
|
G_add_keyword(_("geometry"));
|
|
@@ -72,66 +70,87 @@ int main(int argc, char *argv[])
|
|
|
module->description =
|
|
|
_("Extrudes flat vector features to 3D with defined height.");
|
|
|
|
|
|
- t_flag = G_define_flag();
|
|
|
- t_flag->key = 't';
|
|
|
- t_flag->description = _("Trace elevation");
|
|
|
-
|
|
|
- old = G_define_standard_option(G_OPT_V_INPUT);
|
|
|
+ flag.trace = G_define_flag();
|
|
|
+ flag.trace->key = 't';
|
|
|
+ flag.trace->description = _("Trace elevation");
|
|
|
+ flag.trace->guisection = _("Elevation");
|
|
|
|
|
|
- field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);
|
|
|
+ opt.input = G_define_standard_option(G_OPT_V_INPUT);
|
|
|
|
|
|
- type_opt = G_define_standard_option(G_OPT_V_TYPE);
|
|
|
- type_opt->answer = "point,line,boundary,area";
|
|
|
- type_opt->options = "point,line,boundary,area";
|
|
|
-
|
|
|
- new = G_define_standard_option(G_OPT_V_OUTPUT);
|
|
|
-
|
|
|
- zshift = G_define_option();
|
|
|
- zshift->key = "zshift";
|
|
|
- zshift->description = _("Shifting value for z coordinates");
|
|
|
- zshift->type = TYPE_DOUBLE;
|
|
|
- zshift->required = NO;
|
|
|
- zshift->answer = "0";
|
|
|
+ opt.field = G_define_standard_option(G_OPT_V_FIELD_ALL);
|
|
|
+ opt.field->guisection = _("Selection");
|
|
|
|
|
|
+ opt.cats = G_define_standard_option(G_OPT_V_CATS);
|
|
|
+ opt.cats->guisection = _("Selection");
|
|
|
+
|
|
|
+ opt.where = G_define_standard_option(G_OPT_DB_WHERE);
|
|
|
+ opt.where->guisection = _("Selection");
|
|
|
+
|
|
|
+ opt.type = G_define_standard_option(G_OPT_V_TYPE);
|
|
|
+ opt.type->answer = "point,boundary,area";
|
|
|
+ opt.type->options = "point,boundary,area";
|
|
|
+ opt.type->guisection = _("Selection");
|
|
|
+
|
|
|
+ opt.output = G_define_standard_option(G_OPT_V_OUTPUT);
|
|
|
+
|
|
|
+ opt.zshift = G_define_option();
|
|
|
+ opt.zshift->key = "zshift";
|
|
|
+ opt.zshift->description = _("Shifting value for z coordinates");
|
|
|
+ opt.zshift->type = TYPE_DOUBLE;
|
|
|
+ opt.zshift->required = NO;
|
|
|
+ opt.zshift->answer = "0";
|
|
|
+ opt.zshift->guisection = _("Height");
|
|
|
+
|
|
|
+ opt.height = G_define_option();
|
|
|
+ opt.height->key = "height";
|
|
|
+ opt.height->type = TYPE_DOUBLE;
|
|
|
+ opt.height->required = NO;
|
|
|
+ opt.height->multiple = NO;
|
|
|
+ opt.height->description = _("Fixed height for 3D vector features");
|
|
|
+ opt.height->guisection = _("Height");
|
|
|
+
|
|
|
+ opt.hcolumn = G_define_standard_option(G_OPT_DB_COLUMN);
|
|
|
+ opt.hcolumn->key = "hcolumn";
|
|
|
+ opt.hcolumn->multiple = NO;
|
|
|
+ opt.hcolumn->description = _("Name of attribute column with feature height");
|
|
|
+ opt.hcolumn->guisection = _("Height");
|
|
|
+
|
|
|
/* raster sampling */
|
|
|
- elevation = G_define_standard_option(G_OPT_R_ELEV);
|
|
|
- elevation->required = NO;
|
|
|
- elevation->description = _("Elevation raster for height extraction");
|
|
|
-
|
|
|
- height = G_define_option();
|
|
|
- height->key = "height";
|
|
|
- height->type = TYPE_DOUBLE;
|
|
|
- height->required = NO;
|
|
|
- height->multiple = NO;
|
|
|
- height->description = _("Fixed height for 3D vector objects");
|
|
|
-
|
|
|
- hcolumn = G_define_standard_option(G_OPT_DB_COLUMN);
|
|
|
- hcolumn->key = "hcolumn";
|
|
|
- hcolumn->multiple = NO;
|
|
|
- hcolumn->description = _("Name of attribute column with object heights");
|
|
|
+ opt.elevation = G_define_standard_option(G_OPT_R_ELEV);
|
|
|
+ opt.elevation->required = NO;
|
|
|
+ opt.elevation->description = _("Elevation raster map for height extraction");
|
|
|
+ opt.elevation->guisection = _("Elevation");
|
|
|
+
|
|
|
+ opt.interp = G_define_standard_option(G_OPT_R_INTERP_TYPE);
|
|
|
+ opt.interp->answer = "nearest";
|
|
|
+ opt.interp->guisection = _("Elevation");
|
|
|
|
|
|
G_gisinit(argv[0]);
|
|
|
|
|
|
if (G_parser(argc, argv))
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
|
- if (!height->answer && !hcolumn->answer) {
|
|
|
+ if (!opt.height->answer && !opt.hcolumn->answer) {
|
|
|
G_fatal_error(_("One of '%s' or '%s' parameters must be set"),
|
|
|
- height->key, hcolumn->key);
|
|
|
+ opt.height->key, opt.hcolumn->key);
|
|
|
}
|
|
|
|
|
|
- sscanf(zshift->answer, "%lf", &voffset);
|
|
|
-
|
|
|
- if (height->answer)
|
|
|
- sscanf(height->answer, "%lf", &objheight);
|
|
|
+ sscanf(opt.zshift->answer, "%lf", &voffset);
|
|
|
+ G_debug(1, "voffset = %f", voffset);
|
|
|
+
|
|
|
+ if (opt.height->answer)
|
|
|
+ sscanf(opt.height->answer, "%lf", &objheight);
|
|
|
else
|
|
|
objheight = 0.;
|
|
|
+ G_debug(1, "objheight = %f", objheight);
|
|
|
+ objheight_default = objheight;
|
|
|
|
|
|
- only_type = Vect_option_to_types(type_opt);
|
|
|
+ only_type = Vect_option_to_types(opt.type);
|
|
|
+ interp_method = Rast_option_to_interp_type(opt.interp);
|
|
|
|
|
|
- trace = (t_flag->answer) ? 1 : 0;
|
|
|
- area = (only_type & GV_AREA) ? 1 : 0;
|
|
|
- if (area) {
|
|
|
+ trace = (flag.trace->answer) ? TRUE : FALSE;
|
|
|
+ process_area = (only_type & GV_AREA) ? TRUE : FALSE;
|
|
|
+ if (process_area) {
|
|
|
if (only_type & GV_BOUNDARY) {
|
|
|
/* do not write wall twice -> disable boundary type */
|
|
|
only_type &= ~GV_BOUNDARY;
|
|
@@ -139,193 +158,177 @@ int main(int argc, char *argv[])
|
|
|
only_type &= ~GV_AREA;
|
|
|
}
|
|
|
|
|
|
- centroid = 0;
|
|
|
-
|
|
|
/* set input vector map name and mapset */
|
|
|
- Vect_check_input_output_name(old->answer, new->answer, G_FATAL_EXIT);
|
|
|
+ Vect_check_input_output_name(opt.input->answer, opt.output->answer, G_FATAL_EXIT);
|
|
|
|
|
|
- /* vector setup */
|
|
|
Points = Vect_new_line_struct();
|
|
|
Cats = Vect_new_cats_struct();
|
|
|
|
|
|
- Vect_set_open_level(2);
|
|
|
- Vect_open_new(&Out, new->answer, WITH_Z);
|
|
|
+ Vect_set_open_level(2); /* topology required for input */
|
|
|
+ /* opening input vector map */
|
|
|
+ Vect_open_old2(&In, opt.input->answer, "", opt.field->answer);
|
|
|
+ Vect_set_error_handler_io(&In, &Out);
|
|
|
+
|
|
|
+ /* creating output vector map */
|
|
|
+ Vect_open_new(&Out, opt.output->answer, WITH_Z);
|
|
|
|
|
|
- /* opening old vector */
|
|
|
- Vect_open_old2(&In, old->answer, "", field_opt->answer);
|
|
|
- field = Vect_get_field_number(&In, field_opt->answer);
|
|
|
+ field = Vect_get_field_number(&In, opt.field->answer);
|
|
|
|
|
|
+ if ((opt.hcolumn->answer || opt.cats->answer || opt.where->answer) && field == -1) {
|
|
|
+ G_warning(_("Invalid layer number (%d). "
|
|
|
+ "Parameter '%s', '%s' or '%s' specified, assuming layer '1'."),
|
|
|
+ field, opt.hcolumn->key, opt.cats->key, opt.where->key);
|
|
|
+ field = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* set constraint for cats or where */
|
|
|
+ cat_list = NULL;
|
|
|
+ if (field > 0)
|
|
|
+ cat_list = Vect_cats_set_constraint(&In, field, opt.where->answer,
|
|
|
+ opt.cats->answer);
|
|
|
+
|
|
|
+
|
|
|
Vect_hist_copy(&In, &Out);
|
|
|
Vect_hist_command(&Out);
|
|
|
|
|
|
/* opening database connection, if required */
|
|
|
- if (hcolumn->answer) {
|
|
|
- Clist = Vect_new_cat_list();
|
|
|
- Clist->field = atoi(field_opt->answer);
|
|
|
- if ((Fi = Vect_get_field(&In, Clist->field)) == NULL)
|
|
|
+ if (opt.hcolumn->answer) {
|
|
|
+ int ctype;
|
|
|
+ dbColumn *column;
|
|
|
+
|
|
|
+ if ((Fi = Vect_get_field(&In, field)) == NULL)
|
|
|
G_fatal_error(_("Database connection not defined for layer %d"),
|
|
|
- Clist->field);
|
|
|
+ field);
|
|
|
|
|
|
if ((driver =
|
|
|
db_start_driver_open_database(Fi->driver, Fi->database)) == NULL)
|
|
|
G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
|
|
|
Fi->database, Fi->driver);
|
|
|
-
|
|
|
- if (db_get_column(driver, Fi->table, hcolumn->answer, &column) != DB_OK)
|
|
|
+ db_set_error_handler_driver(driver);
|
|
|
+
|
|
|
+ if (db_get_column(driver, Fi->table, opt.hcolumn->answer, &column) != DB_OK)
|
|
|
G_fatal_error(_("Column <%s> does not exist"),
|
|
|
- hcolumn->answer);
|
|
|
+ opt.hcolumn->answer);
|
|
|
else
|
|
|
db_free_column(column);
|
|
|
|
|
|
- ctype = db_column_Ctype(driver, Fi->table, hcolumn->answer);
|
|
|
+ ctype = db_column_Ctype(driver, Fi->table, opt.hcolumn->answer);
|
|
|
|
|
|
if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_STRING &&
|
|
|
ctype != DB_C_TYPE_DOUBLE) {
|
|
|
G_fatal_error(_("Column <%s>: invalid data type"),
|
|
|
- hcolumn->answer);
|
|
|
+ opt.hcolumn->answer);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* do we work with elevation raster? */
|
|
|
- if (elevation->answer) {
|
|
|
+ fdrast = -1;
|
|
|
+ if (opt.elevation->answer) {
|
|
|
/* raster setup */
|
|
|
G_get_window(&window);
|
|
|
|
|
|
/* open the elev raster, and check for error condition */
|
|
|
- fdrast = Rast_open_old(elevation->answer, "");
|
|
|
+ fdrast = Rast_open_old(opt.elevation->answer, "");
|
|
|
}
|
|
|
|
|
|
/* if area */
|
|
|
- if (area) {
|
|
|
- G_debug(1, "drawing areas");
|
|
|
- nelements = Vect_get_num_areas(&In);
|
|
|
- G_debug(2, "n_areas = %d", nelements);
|
|
|
- if (nelements > 0)
|
|
|
+ if (process_area) {
|
|
|
+ int area, nareas, centroid;
|
|
|
+
|
|
|
+ nareas = Vect_get_num_areas(&In);
|
|
|
+ G_debug(2, "n_areas = %d", nareas);
|
|
|
+ if (nareas > 0)
|
|
|
G_message(_("Extruding areas..."));
|
|
|
- for (areanum = 1; areanum <= nelements; areanum++) {
|
|
|
-
|
|
|
- G_debug(3, "area = %d", areanum);
|
|
|
-
|
|
|
- if (!Vect_area_alive(&In, areanum))
|
|
|
+ for (area = 1; area <= nareas; area++) {
|
|
|
+ G_debug(3, "area = %d", area);
|
|
|
+ G_percent(area, nareas, 2);
|
|
|
+
|
|
|
+ if (!Vect_area_alive(&In, area))
|
|
|
continue;
|
|
|
-
|
|
|
- centroid = Vect_get_area_centroid(&In, areanum);
|
|
|
+
|
|
|
+ centroid = Vect_get_area_centroid(&In, area);
|
|
|
if (!centroid) {
|
|
|
- G_warning(_("Skipping area %d without centroid"), areanum);
|
|
|
+ G_warning(_("Skipping area %d without centroid"), area);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
+ Vect_read_line(&In, NULL, Cats, centroid);
|
|
|
+ if (field > 0 && !Vect_cats_in_constraint(Cats, field, cat_list))
|
|
|
+ continue;
|
|
|
+
|
|
|
/* height attribute */
|
|
|
- if (hcolumn->answer) {
|
|
|
- cat = Vect_get_area_cat(&In, areanum, Clist->field);
|
|
|
- db_init_string(&sql);
|
|
|
- sprintf(query, "SELECT %s FROM %s WHERE %s = %d",
|
|
|
- hcolumn->answer, Fi->table, Fi->key, cat);
|
|
|
- G_debug(3, "SQL: %s", query);
|
|
|
- db_append_string(&sql, query);
|
|
|
- if (db_open_select_cursor
|
|
|
- (driver, &sql, &cursor, DB_SEQUENTIAL)
|
|
|
- != DB_OK)
|
|
|
- G_fatal_error(_("Cannot select attributes for area %d"),
|
|
|
- areanum);
|
|
|
- table = db_get_cursor_table(&cursor);
|
|
|
- column = db_get_table_column(table, 0); /* first column */
|
|
|
-
|
|
|
- if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
|
|
|
- continue;
|
|
|
-
|
|
|
- value = db_get_column_value(column);
|
|
|
- G_debug(3, "column_host_type: %d", db_get_column_host_type(column));
|
|
|
- objheight = db_get_value_as_double(value, DB_C_TYPE_DOUBLE);
|
|
|
- G_debug(3, "height from DB: %f", objheight);
|
|
|
- /* only draw if hcolumn was defined */
|
|
|
- if (objheight != 0) {
|
|
|
- G_debug(3, "area centroid %d: object height: %f",
|
|
|
- centroid, objheight);
|
|
|
- }
|
|
|
-
|
|
|
- } /* if hcolumn->answer */
|
|
|
-
|
|
|
- Vect_get_area_points(&In, areanum, Points);
|
|
|
-
|
|
|
- G_debug(3, "height: %f", objheight);
|
|
|
+ if (opt.hcolumn->answer) {
|
|
|
+ cat = Vect_get_area_cat(&In, area, field);
|
|
|
+ if (cat == -1) {
|
|
|
+ G_warning(_("No category defined for area %d. Using default fixed height %f."),
|
|
|
+ area, objheight_default);
|
|
|
+ objheight = objheight_default;
|
|
|
+ }
|
|
|
+ if (get_height(Fi, opt.hcolumn->answer,
|
|
|
+ driver, cat, &objheight) != 0) {
|
|
|
+ G_warning(_("Unable to fetch height from DB for area %d. Using default fixed height %f."),
|
|
|
+ area, objheight_default);
|
|
|
+ objheight = objheight_default;
|
|
|
+ }
|
|
|
+ } /* if opt.hcolumn->answer */
|
|
|
+
|
|
|
+ Vect_get_area_points(&In, area, Points);
|
|
|
+
|
|
|
+ G_debug(3, "area: %d height: %f", area, objheight);
|
|
|
|
|
|
extrude(&In, &Out, Cats, Points,
|
|
|
- fdrast, trace, objheight, voffset, window, GV_AREA,
|
|
|
+ fdrast, trace, interp_method,
|
|
|
+ objheight, voffset, &window, GV_AREA,
|
|
|
centroid);
|
|
|
-
|
|
|
- G_percent(areanum, nelements, 2);
|
|
|
-
|
|
|
- } /* foreach area */
|
|
|
+ } /* foreach area */
|
|
|
|
|
|
}
|
|
|
|
|
|
if (only_type > 0) {
|
|
|
- G_debug(1, "drawing other than areas");
|
|
|
- i = 1;
|
|
|
+ int line, nlines;
|
|
|
+ int type;
|
|
|
+
|
|
|
+ G_debug(1, "other than areas");
|
|
|
/* loop through each line in the dataset */
|
|
|
- nelements = Vect_get_num_lines(&In);
|
|
|
+ nlines = Vect_get_num_lines(&In);
|
|
|
G_message(_("Extruding features..."));
|
|
|
- for (line = 1; line <= nelements; line++) {
|
|
|
-
|
|
|
- /* read line */
|
|
|
- type = Vect_read_line(&In, Points, Cats, line);
|
|
|
+ for (line = 1; line <= nlines; line++) {
|
|
|
+ /* progress feedback */
|
|
|
+ G_percent(line, nlines, 2);
|
|
|
|
|
|
if (!Vect_line_alive(&In, line))
|
|
|
continue;
|
|
|
|
|
|
+ /* read line */
|
|
|
+ type = Vect_read_line(&In, Points, Cats, line);
|
|
|
+
|
|
|
if (!(type & only_type))
|
|
|
continue;
|
|
|
|
|
|
- /* fetch categories */
|
|
|
- if (field != -1 && !Vect_cat_get(Cats, field, &cat)) {
|
|
|
- Vect_cat_set(Cats, 1, i);
|
|
|
- i++;
|
|
|
- }
|
|
|
+ if (field > 0 && !Vect_cats_in_constraint(Cats, field, cat_list))
|
|
|
+ continue;
|
|
|
|
|
|
/* height attribute */
|
|
|
- if (hcolumn->answer) {
|
|
|
- cat = Vect_get_line_cat(&In, line, Clist->field);
|
|
|
-
|
|
|
- /* sql init */
|
|
|
- db_init_string(&sql);
|
|
|
- sprintf(query, "SELECT %s FROM %s WHERE %s = %d",
|
|
|
- hcolumn->answer, Fi->table, Fi->key, cat);
|
|
|
- G_debug(3, "SQL: %s", query);
|
|
|
- db_append_string(&sql, query);
|
|
|
-
|
|
|
- /* cursor init */
|
|
|
- if (db_open_select_cursor
|
|
|
- (driver, &sql, &cursor, DB_SEQUENTIAL)
|
|
|
- != DB_OK)
|
|
|
- G_fatal_error(_("Cannot select attributes for area #%d"),
|
|
|
- areanum);
|
|
|
- table = db_get_cursor_table(&cursor);
|
|
|
- column = db_get_table_column(table, 0); /* first column */
|
|
|
-
|
|
|
- if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
|
|
|
- continue;
|
|
|
-
|
|
|
- /* objheight value */
|
|
|
- value = db_get_column_value(column);
|
|
|
- objheight = db_get_value_as_double(value, ctype);
|
|
|
-
|
|
|
- /* only draw if hcolumn was defined */
|
|
|
- if (objheight != 0) {
|
|
|
- G_debug(3, "area centroid %d: object height: %f",
|
|
|
- centroid, objheight);
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
+ if (opt.hcolumn->answer) {
|
|
|
+ cat = Vect_get_line_cat(&In, line, field);
|
|
|
+ if (cat == -1) {
|
|
|
+ G_warning(_("No category defined for feature %d. Using default fixed height %f."),
|
|
|
+ line, objheight_default);
|
|
|
+ objheight = objheight_default;
|
|
|
+ }
|
|
|
+ if (get_height(Fi, opt.hcolumn->answer,
|
|
|
+ driver, cat, &objheight) != 0) {
|
|
|
+ G_warning(_("Unable to fetch height from DB for line %d. Using default fixed height %f."),
|
|
|
+ line, objheight_default);
|
|
|
+ objheight = objheight_default;
|
|
|
+ }
|
|
|
+ } /* if opt.hcolumn->answer */
|
|
|
+
|
|
|
extrude(&In, &Out, Cats, Points,
|
|
|
- fdrast, trace, objheight, voffset, window, type, -1);
|
|
|
-
|
|
|
- /* progress feedback */
|
|
|
- G_percent(line, nelements, 2);
|
|
|
-
|
|
|
- } /* for each line */
|
|
|
- } /* else if area */
|
|
|
+ fdrast, trace, interp_method,
|
|
|
+ objheight, voffset, &window, type, -1);
|
|
|
+ } /* for each line */
|
|
|
+ } /* else if area */
|
|
|
|
|
|
if (driver) {
|
|
|
db_close_database(driver);
|
|
@@ -336,7 +339,7 @@ int main(int argc, char *argv[])
|
|
|
|
|
|
/* header */
|
|
|
G_asprintf(&comment, "Generated by %s from vector map <%s>",
|
|
|
- G_program_name(), old->answer);
|
|
|
+ G_program_name(), Vect_get_full_name(&In));
|
|
|
Vect_set_comment(&Out, comment);
|
|
|
G_free(comment);
|
|
|
|
|
@@ -352,180 +355,3 @@ int main(int argc, char *argv[])
|
|
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- \brief Extrude vector object
|
|
|
-
|
|
|
- - point -> 3d line (vertical)
|
|
|
- - line -> 3d line
|
|
|
- - boundary -> face
|
|
|
- - area -> face + kernel
|
|
|
-
|
|
|
- \param[in] In input vector map
|
|
|
- \param[out] Out output vector map
|
|
|
- \param[in] Cats categories
|
|
|
- \param[in] Points points
|
|
|
- \param[in] fdrast background raster map
|
|
|
- \param[in] trace trace raster map values
|
|
|
- \param[in] objheight object height
|
|
|
- \param[in] voffset vertical offset
|
|
|
- \param[in] window raster region
|
|
|
- \param[in] type feature type
|
|
|
- \param[in] centroid number of centroid for area
|
|
|
- \return number of writen objects
|
|
|
-*/
|
|
|
-static int extrude(struct Map_info *In, struct Map_info *Out,
|
|
|
- struct line_cats *Cats, struct line_pnts *Points,
|
|
|
- int fdrast, int trace, double objheight, double voffset,
|
|
|
- struct Cell_head window, int type, int centroid)
|
|
|
-{
|
|
|
- int k; /* Points->n_points */
|
|
|
- int nlines;
|
|
|
- struct line_pnts *Points_wall, *Points_roof;
|
|
|
-
|
|
|
- double voffset_dem; /* minimal offset */
|
|
|
- double voffset_curr; /* offset of current point */
|
|
|
- double voffset_next; /* offset of next point */
|
|
|
-
|
|
|
- nlines = 0;
|
|
|
-
|
|
|
- if (type != GV_POINT && Points->n_points < 2)
|
|
|
- return nlines;
|
|
|
-
|
|
|
- Points_wall = Vect_new_line_struct();
|
|
|
- Points_roof = Vect_new_line_struct();
|
|
|
-
|
|
|
- voffset_dem = 0.0;
|
|
|
- /* do not trace -> calculate minumum dem offset */
|
|
|
- if (fdrast >= 0 && !trace) {
|
|
|
- for (k = 0; k < Points->n_points; k++) {
|
|
|
- voffset_curr = Rast_get_sample(fdrast, &window, NULL,
|
|
|
- Points->y[k], Points->x[k], 0,
|
|
|
- NEAREST);
|
|
|
- if (Rast_is_d_null_value(&voffset_curr))
|
|
|
- continue;
|
|
|
-
|
|
|
- if (k == 0) {
|
|
|
- voffset_dem = voffset_curr;
|
|
|
- }
|
|
|
- else {
|
|
|
- if (voffset_curr < voffset_dem)
|
|
|
- voffset_dem = voffset_curr;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /* walls */
|
|
|
- for (k = 0; ; k++) {
|
|
|
- voffset_curr = voffset_next = 0.0;
|
|
|
-
|
|
|
- /* trace */
|
|
|
- if (fdrast >= 0 && trace) {
|
|
|
- voffset_curr = Rast_get_sample(fdrast, &window, NULL,
|
|
|
- Points->y[k], Points->x[k], 0,
|
|
|
- NEAREST);
|
|
|
-
|
|
|
- if (type != GV_POINT) {
|
|
|
- voffset_next = Rast_get_sample(fdrast, &window, NULL,
|
|
|
- Points->y[k + 1],
|
|
|
- Points->x[k + 1], 0,
|
|
|
- NEAREST);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (Rast_is_d_null_value(&voffset_curr) ||
|
|
|
- Rast_is_d_null_value(&voffset_next)) {
|
|
|
- if (type == GV_POINT)
|
|
|
- break;
|
|
|
- else if (type == GV_LINE) {
|
|
|
- if (k >= Points->n_points - 1)
|
|
|
- break;
|
|
|
- }
|
|
|
- else if (type & (GV_BOUNDARY | GV_AREA)) {
|
|
|
- if (k >= Points->n_points - 2)
|
|
|
- break;
|
|
|
- }
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if (trace) {
|
|
|
- voffset_curr += voffset;
|
|
|
- voffset_next += voffset;
|
|
|
- }
|
|
|
- else {
|
|
|
- voffset_curr = voffset_dem + voffset;
|
|
|
- voffset_next = voffset_dem + voffset;
|
|
|
- }
|
|
|
-
|
|
|
- if (type == GV_POINT) {
|
|
|
- /* point -> 3d line (vertical) */
|
|
|
- Vect_append_point(Points_wall, Points->x[k], Points->y[k],
|
|
|
- Points->z[k] + voffset_curr);
|
|
|
- Vect_append_point(Points_wall, Points->x[k], Points->y[k],
|
|
|
- Points->z[k] + objheight + voffset_curr);
|
|
|
- break;
|
|
|
- }
|
|
|
- else if (type == GV_LINE) {
|
|
|
- /* line -> 3d line */
|
|
|
- Vect_append_point(Points_wall, Points->x[k], Points->y[k],
|
|
|
- Points->z[k] + objheight + voffset_curr);
|
|
|
- if (k >= Points->n_points - 1)
|
|
|
- break;
|
|
|
- }
|
|
|
- else if (type & (GV_BOUNDARY | GV_AREA)) {
|
|
|
- /* reset */
|
|
|
- Vect_reset_line(Points_wall);
|
|
|
-
|
|
|
- /* boudary -> face */
|
|
|
- Vect_append_point(Points_wall, Points->x[k], Points->y[k],
|
|
|
- Points->z[k] + voffset_curr);
|
|
|
- Vect_append_point(Points_wall, Points->x[k + 1], Points->y[k + 1],
|
|
|
- Points->z[k + 1] + voffset_next);
|
|
|
- Vect_append_point(Points_wall, Points->x[k + 1], Points->y[k + 1],
|
|
|
- Points->z[k + 1] + objheight + voffset_next);
|
|
|
- Vect_append_point(Points_wall, Points->x[k], Points->y[k],
|
|
|
- Points->z[k] + objheight + voffset_curr);
|
|
|
- Vect_append_point(Points_wall, Points->x[k], Points->y[k],
|
|
|
- Points->z[k] + voffset_curr);
|
|
|
-
|
|
|
- Vect_write_line(Out, GV_FACE, Points_wall, Cats);
|
|
|
- nlines++;
|
|
|
-
|
|
|
- if (type == GV_AREA) {
|
|
|
- /* roof */
|
|
|
- Vect_append_point(Points_roof, Points->x[k], Points->y[k],
|
|
|
- Points->z[k] + objheight + voffset_curr);
|
|
|
- }
|
|
|
-
|
|
|
- if (k >= Points->n_points - 2)
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (type & (GV_POINT | GV_LINE)) {
|
|
|
- Vect_write_line(Out, GV_LINE, Points_wall, Cats);
|
|
|
- nlines++;
|
|
|
- }
|
|
|
- else if (type == GV_AREA && Points_roof->n_points > 3) {
|
|
|
- Vect_append_point(Points_roof,
|
|
|
- Points_roof->x[0], Points_roof->y[0],
|
|
|
- Points_roof->z[0]);
|
|
|
- Vect_write_line(Out, GV_FACE, Points_roof, Cats);
|
|
|
- nlines++;
|
|
|
-
|
|
|
- if (centroid > 0) {
|
|
|
- /* centroid -> kernel */
|
|
|
- Vect_read_line(In, Points, Cats, centroid);
|
|
|
- Points->z[0] = Points_roof->z[0] / 2.0;
|
|
|
- Vect_write_line(Out, GV_KERNEL, Points, Cats);
|
|
|
- nlines++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Vect_destroy_line_struct(Points_wall);
|
|
|
- Vect_destroy_line_struct(Points_roof);
|
|
|
-
|
|
|
- return nlines;
|
|
|
-}
|