int main(int argc, char *argv[]) { struct Option *vector_opt, *seed_opt, *flowlines_opt, *flowacc_opt, *sampled_opt, *scalar_opt, *unit_opt, *step_opt, *limit_opt, *skip_opt, *dir_opt, *error_opt; struct Flag *table_fl; struct GModule *module; RASTER3D_Region region; RASTER3D_Map *flowacc, *sampled; struct Integration integration; struct Seed seed; struct Gradient_info gradient_info; struct Map_info seed_Map; struct line_pnts *seed_points; struct line_cats *seed_cats; struct Map_info fl_map; struct line_cats *fl_cats; /* for flowlines */ struct line_pnts *fl_points; /* for flowlines */ struct field_info *finfo; dbDriver *driver; int cat; /* cat of flowlines */ int if_table; int i, r, c, d; char *desc; int n_seeds, seed_count, ltype; int skip[3]; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("raster3d")); G_add_keyword(_("hydrology")); G_add_keyword(_("voxel")); module->description = _("Computes 3D flow lines and 3D flow accumulation."); scalar_opt = G_define_standard_option(G_OPT_R3_INPUT); scalar_opt->required = NO; scalar_opt->guisection = _("Input"); vector_opt = G_define_standard_option(G_OPT_R3_INPUTS); vector_opt->key = "vector_field"; vector_opt->required = NO; vector_opt->description = _("Names of three 3D raster maps describing " "x, y, z components of vector field"); vector_opt->guisection = _("Input"); seed_opt = G_define_standard_option(G_OPT_V_INPUT); seed_opt->required = NO; seed_opt->key = "seed_points"; seed_opt->description = _("If no map is provided, " "flow lines are generated " "from each cell of the input 3D raster"); seed_opt->label = _("Name of vector map with points " "from which flow lines are generated"); seed_opt->guisection = _("Input"); flowlines_opt = G_define_standard_option(G_OPT_V_OUTPUT); flowlines_opt->key = "flowline"; flowlines_opt->required = NO; flowlines_opt->description = _("Name for vector map of flow lines"); flowlines_opt->guisection = _("Output"); flowacc_opt = G_define_standard_option(G_OPT_R3_OUTPUT); flowacc_opt->key = "flowaccumulation"; flowacc_opt->required = NO; flowacc_opt->description = _("Name for output flowaccumulation 3D raster"); flowacc_opt->guisection = _("Output"); sampled_opt = G_define_standard_option(G_OPT_R3_INPUT); sampled_opt->key = "sampled"; sampled_opt->required = NO; sampled_opt->label = _("Name for 3D raster sampled by flowlines"); sampled_opt->description = _("Values of this 3D raster will be stored " "as attributes of flowlines segments"); unit_opt = G_define_option(); unit_opt->key = "unit"; unit_opt->type = TYPE_STRING; unit_opt->required = NO; unit_opt->answer = "cell"; unit_opt->options = "time,length,cell"; desc = NULL; G_asprintf(&desc, "time;%s;" "length;%s;" "cell;%s", _("elapsed time"), _("length in map units"), _("length in cells (voxels)")); unit_opt->descriptions = desc; unit_opt->label = _("Unit of integration step"); unit_opt->description = _("Default unit is cell"); unit_opt->guisection = _("Integration"); step_opt = G_define_option(); step_opt->key = "step"; step_opt->type = TYPE_DOUBLE; step_opt->required = NO; step_opt->answer = "0.25"; step_opt->label = _("Integration step in selected unit"); step_opt->description = _("Default step is 0.25 cell"); step_opt->guisection = _("Integration"); limit_opt = G_define_option(); limit_opt->key = "limit"; limit_opt->type = TYPE_INTEGER; limit_opt->required = NO; limit_opt->answer = "2000"; limit_opt->description = _("Maximum number of steps"); limit_opt->guisection = _("Integration"); error_opt = G_define_option(); error_opt->key = "max_error"; error_opt->type = TYPE_DOUBLE; error_opt->required = NO; error_opt->answer = "1e-5"; error_opt->label = _("Maximum error of integration"); error_opt->description = _("Influences step, increase maximum error " "to allow bigger steps"); error_opt->guisection = _("Integration"); skip_opt = G_define_option(); skip_opt->key = "skip"; skip_opt->type = TYPE_INTEGER; skip_opt->required = NO; skip_opt->multiple = YES; skip_opt->description = _("Number of cells between flow lines in x, y and z direction"); dir_opt = G_define_option(); dir_opt->key = "direction"; dir_opt->type = TYPE_STRING; dir_opt->required = NO; dir_opt->multiple = NO; dir_opt->options = "up,down,both"; dir_opt->answer = "down"; dir_opt->description = _("Compute flowlines upstream, " "downstream or in both direction."); table_fl = G_define_flag(); table_fl->key = 'a'; table_fl->description = _("Create and fill attribute table"); G_option_required(scalar_opt, vector_opt, NULL); G_option_exclusive(scalar_opt, vector_opt, NULL); G_option_required(flowlines_opt, flowacc_opt, NULL); G_option_requires(seed_opt, flowlines_opt, NULL); G_option_requires(table_fl, flowlines_opt, NULL); G_option_requires(sampled_opt, table_fl, NULL); if (G_parser(argc, argv)) exit(EXIT_FAILURE); driver = NULL; finfo = NULL; if_table = table_fl->answer ? TRUE : FALSE; check_vector_input_maps(vector_opt, seed_opt); Rast3d_init_defaults(); Rast3d_get_window(®ion); /* set up integration variables */ if (step_opt->answer) { integration.step = atof(step_opt->answer); integration.unit = unit_opt->answer; } else { integration.unit = "cell"; integration.step = 0.25; } integration.max_error = atof(error_opt->answer); integration.max_step = 5 * integration.step; integration.min_step = integration.step / 5; integration.limit = atof(limit_opt->answer); if (strcmp(dir_opt->answer, "up") == 0) integration.direction_type = FLOWDIR_UP; else if (strcmp(dir_opt->answer, "down") == 0) integration.direction_type = FLOWDIR_DOWN; else integration.direction_type = FLOWDIR_BOTH; /* cell size is the diagonal */ integration.cell_size = sqrt(region.ns_res * region.ns_res + region.ew_res * region.ew_res + region.tb_res * region.tb_res); /* set default skip if needed */ if (skip_opt->answers) { for (i = 0; i < 3; i++) { if (skip_opt->answers[i] != NULL) { skip[i] = atoi(skip_opt->answers[i]); } else { G_fatal_error(_("Please provide 3 integer values for skip option.")); } } } else { skip[0] = fmax(1, region.cols / 10); skip[1] = fmax(1, region.rows / 10); skip[2] = fmax(1, region.depths / 10); } /* open raster 3D maps of velocity components */ gradient_info.initialized = FALSE; load_input_raster3d_maps(scalar_opt, vector_opt, &gradient_info, ®ion); /* open new 3D raster map of flowacumulation */ if (flowacc_opt->answer) { flowacc = Rast3d_open_new_opt_tile_size(flowacc_opt->answer, RASTER3D_USE_CACHE_DEFAULT, ®ion, FCELL_TYPE, 32); if (!flowacc) Rast3d_fatal_error(_("Unable to open 3D raster map <%s>"), flowacc_opt->answer); init_flowaccum(®ion, flowacc); } /* open 3D raster map used for sampling */ if (sampled_opt->answer) { sampled = Rast3d_open_cell_old(sampled_opt->answer, G_find_raster3d(sampled_opt->answer, ""), ®ion, RASTER3D_TILE_SAME_AS_FILE, RASTER3D_USE_CACHE_DEFAULT); if (!sampled) Rast3d_fatal_error(_("Unable to open 3D raster map <%s>"), sampled_opt->answer); } else sampled = NULL; /* open new vector map of flowlines */ if (flowlines_opt->answer) { fl_cats = Vect_new_cats_struct(); fl_points = Vect_new_line_struct(); if (Vect_open_new(&fl_map, flowlines_opt->answer, TRUE) < 0) G_fatal_error(_("Unable to create vector map <%s>"), flowlines_opt->answer); Vect_hist_command(&fl_map); if (if_table) { create_table(&fl_map, &finfo, &driver, gradient_info.compute_gradient, sampled ? 1 : 0); } } n_seeds = 0; /* open vector map of seeds */ if (seed_opt->answer) { if (Vect_open_old2(&seed_Map, seed_opt->answer, "", "1") < 0) G_fatal_error(_("Unable to open vector map <%s>"), seed_opt->answer); if (!Vect_is_3d(&seed_Map)) G_fatal_error(_("Vector map <%s> is not 3D"), seed_opt->answer); n_seeds = Vect_get_num_primitives(&seed_Map, GV_POINT); } if (flowacc_opt->answer || (!seed_opt->answer && flowlines_opt->answer)) { if (flowacc_opt->answer) n_seeds += region.cols * region.rows * region.depths; else { n_seeds += ceil(region.cols / (double)skip[0]) * ceil(region.rows / (double)skip[1]) * ceil(region.depths / (double)skip[2]); } } G_debug(1, "Number of seeds is %d", n_seeds); seed_count = 0; cat = 1; if (seed_opt->answer) { seed_points = Vect_new_line_struct(); seed_cats = Vect_new_cats_struct(); /* compute flowlines from vector seed map */ while (TRUE) { ltype = Vect_read_next_line(&seed_Map, seed_points, seed_cats); if (ltype == -1) { Vect_close(&seed_Map); G_fatal_error(_("Error during reading seed vector map")); } else if (ltype == -2) { break; } else if (ltype == GV_POINT) { seed.x = seed_points->x[0]; seed.y = seed_points->y[0]; seed.z = seed_points->z[0]; seed.flowline = TRUE; seed.flowaccum = FALSE; } G_percent(seed_count, n_seeds, 1); if (integration.direction_type == FLOWDIR_UP || integration.direction_type == FLOWDIR_BOTH) { integration.actual_direction = FLOWDIR_UP; compute_flowline(®ion, &seed, &gradient_info, flowacc, sampled, &integration, &fl_map, fl_cats, fl_points, &cat, if_table, finfo, driver); } if (integration.direction_type == FLOWDIR_DOWN || integration.direction_type == FLOWDIR_BOTH) { integration.actual_direction = FLOWDIR_DOWN; compute_flowline(®ion, &seed, &gradient_info, flowacc, sampled, &integration, &fl_map, fl_cats, fl_points, &cat, if_table, finfo, driver); } seed_count++; } Vect_destroy_line_struct(seed_points); Vect_destroy_cats_struct(seed_cats); Vect_close(&seed_Map); } if (flowacc_opt->answer || (!seed_opt->answer && flowlines_opt->answer)) { /* compute flowlines from points on grid */ for (r = region.rows; r > 0; r--) { for (c = 0; c < region.cols; c++) { for (d = 0; d < region.depths; d++) { seed.x = region.west + c * region.ew_res + region.ew_res / 2; seed.y = region.south + r * region.ns_res - region.ns_res / 2; seed.z = region.bottom + d * region.tb_res + region.tb_res / 2; seed.flowline = FALSE; seed.flowaccum = FALSE; if (flowacc_opt->answer) seed.flowaccum = TRUE; if (flowlines_opt->answer && !seed_opt->answer && (c % skip[0] == 0) && (r % skip[1] == 0) && (d % skip[2] == 0)) seed.flowline = TRUE; if (seed.flowaccum || seed.flowline) { G_percent(seed_count, n_seeds, 1); if (integration.direction_type == FLOWDIR_UP || integration.direction_type == FLOWDIR_BOTH) { integration.actual_direction = FLOWDIR_UP; compute_flowline(®ion, &seed, &gradient_info, flowacc, sampled, &integration, &fl_map, fl_cats, fl_points, &cat, if_table, finfo, driver); } if (integration.direction_type == FLOWDIR_DOWN || integration.direction_type == FLOWDIR_BOTH) { integration.actual_direction = FLOWDIR_DOWN; compute_flowline(®ion, &seed, &gradient_info, flowacc, sampled, &integration, &fl_map, fl_cats, fl_points, &cat, if_table, finfo, driver); } seed_count++; } } } } } G_percent(1, 1, 1); if (flowlines_opt->answer) { if (if_table) { db_commit_transaction(driver); db_close_database_shutdown_driver(driver); } Vect_destroy_line_struct(fl_points); Vect_destroy_cats_struct(fl_cats); Vect_build(&fl_map); Vect_close(&fl_map); } if (flowacc_opt->answer) Rast3d_close(flowacc); return EXIT_SUCCESS; }
int main(int argc, char **argv) { char *map_name; int maptype; int color; int i; int thin, lines, steps; int fp; int label_indent; int hide_catnum, hide_catstr, show_ticks, show_bg, hide_nodata, do_smooth; struct Categories cats; struct Colors colors; struct GModule *module; struct Option *opt_rast2d, *opt_rast3d, *opt_color, *opt_lines, *opt_thin, *opt_labelnum, *opt_at, *opt_use, *opt_range, *opt_font, *opt_path, *opt_charset, *opt_fontsize, *opt_title, *opt_ticks, *opt_tstep, *opt_brdcolor, *opt_bgcolor, *opt_tit_fontsize, *opt_digits, *opt_units; struct Flag *hidestr, *hidenum, *hidenodata, *smooth, *flipit, *histo, *showtick, *showbg, *log_sc; double X0, X1, Y0, Y1; int flip, UserRange; double UserRangeMin, UserRangeMax, UserRangeTemp; double *catlist; int catlistCount, use_catlist, ticksCount; double fontsize; char *title; char *units; double *tick_values; double t_step; int colorb, colorbg; double tit_fontsize; int log_scale, digits; /* Initialize the GIS calls */ G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("display")); G_add_keyword(_("cartography")); G_add_keyword(_("legend")); module->description = _("Displays a legend for a 2D or 3D raster map in the active frame " "of the graphics monitor."); opt_rast2d = G_define_standard_option(G_OPT_R_MAP); opt_rast2d->key = "raster"; opt_rast2d->required = NO; opt_rast2d->guisection = _("Input"); opt_rast3d = G_define_standard_option(G_OPT_R3_MAP); opt_rast3d->key = "raster_3d"; opt_rast3d->required = NO; opt_rast3d->guisection = _("Input"); opt_title = G_define_option(); opt_title->key = "title"; opt_title->type = TYPE_STRING; opt_title->required = NO; opt_title->description = _("Legend title"); opt_title->guisection = _("Title"); opt_tit_fontsize = G_define_option(); opt_tit_fontsize->key = "title_fontsize"; opt_tit_fontsize->type = TYPE_DOUBLE; opt_tit_fontsize->required = NO; opt_tit_fontsize->options = "1-360"; opt_tit_fontsize->label = _("Title font size"); opt_tit_fontsize->description = _("Default: Same as fontsize"); opt_tit_fontsize->guisection = _("Title"); opt_lines = G_define_option(); opt_lines->key = "lines"; opt_lines->type = TYPE_INTEGER; opt_lines->answer = "0"; opt_lines->options = "0-1000"; opt_lines->description = _("Number of text lines (useful for truncating long legends)"); opt_lines->guisection = _("Advanced"); opt_thin = G_define_option(); opt_thin->key = "thin"; opt_thin->type = TYPE_INTEGER; opt_thin->required = NO; opt_thin->answer = "1"; opt_thin->options = "1-1000"; opt_thin->description = _("Thinning factor (thin=10 gives cats 0,10,20...)"); opt_thin->guisection = _("Advanced"); opt_units = G_define_option(); opt_units->key = "units"; opt_units->type = TYPE_STRING; opt_units->required = NO; opt_units->description = _("Units to display after labels (e.g. meters)"); opt_units->guisection = _("Advanced"); opt_labelnum = G_define_option(); opt_labelnum->key = "labelnum"; opt_labelnum->type = TYPE_INTEGER; opt_labelnum->answer = "5"; opt_labelnum->options = "2-100"; opt_labelnum->description = _("Number of text labels for smooth gradient legend"); opt_labelnum->guisection = _("Gradient"); opt_ticks = G_define_option(); opt_ticks->key = "label_values"; opt_ticks->type = TYPE_DOUBLE; opt_ticks->required = NO; opt_ticks->description = _("Specific values to draw ticks"); opt_ticks->required = NO; opt_ticks->multiple = YES; opt_ticks->guisection = _("Gradient"); opt_tstep = G_define_option(); opt_tstep->key = "label_step"; opt_tstep->type = TYPE_DOUBLE; opt_tstep->required = NO; opt_tstep->description = _("Display label every step"); opt_tstep->guisection = _("Gradient"); opt_digits = G_define_option(); opt_digits->key = "digits"; opt_digits->type = TYPE_INTEGER; opt_digits->required = NO; opt_digits->description = _("Number of digits after decimal point"); opt_digits->guisection = _("Advanced"); opt_digits->answer = NULL; opt_digits->options = "0-6"; opt_at = G_define_option(); opt_at->key = "at"; opt_at->key_desc = "bottom,top,left,right"; opt_at->type = TYPE_DOUBLE; /* needs to be TYPE_DOUBLE to get past options check */ opt_at->required = NO; opt_at->options = "0-100"; opt_at->label = _("Size and placement as percentage of screen coordinates " "(0,0 is lower left)"); opt_at->description = opt_at->key_desc; opt_at->answer = NULL; opt_use = G_define_option(); opt_use->key = "use"; opt_use->type = TYPE_DOUBLE; /* string as it is fed through the parser? */ opt_use->required = NO; opt_use->description = _("List of discrete category numbers/values for legend"); opt_use->multiple = YES; opt_use->guisection = _("Subset"); opt_range = G_define_option(); opt_range->key = "range"; opt_range->key_desc = "min,max"; opt_range->type = TYPE_DOUBLE; /* should it be type_double or _string ?? */ opt_range->required = NO; opt_range->description = _("Use a subset of the map range for the legend (min,max)"); opt_range->guisection = _("Subset"); opt_color = G_define_standard_option(G_OPT_C); opt_color->label = _("Text color"); opt_color->guisection = _("Font settings"); opt_font = G_define_option(); opt_font->key = "font"; opt_font->type = TYPE_STRING; opt_font->required = NO; opt_font->description = _("Font name"); opt_font->guisection = _("Font settings"); opt_fontsize = G_define_option(); opt_fontsize->key = "fontsize"; opt_fontsize->type = TYPE_DOUBLE; opt_fontsize->required = NO; opt_fontsize->options = "1-360"; opt_fontsize->label = _("Font size"); opt_fontsize->description = _("Default: Auto-scaled"); opt_fontsize->guisection = _("Font settings"); opt_path = G_define_standard_option(G_OPT_F_INPUT); opt_path->key = "path"; opt_path->required = NO; opt_path->description = _("Path to font file"); opt_path->gisprompt = "old_file,font,file"; opt_path->guisection = _("Font settings"); opt_charset = G_define_option(); opt_charset->key = "charset"; opt_charset->type = TYPE_STRING; opt_charset->required = NO; opt_charset->description = _("Text encoding (only applicable to TrueType fonts)"); opt_charset->guisection = _("Font settings"); opt_brdcolor = G_define_standard_option(G_OPT_CN); opt_brdcolor->key = "border_color"; opt_brdcolor->answer = "black"; opt_brdcolor->label = _("Border color"); opt_brdcolor->guisection = _("Background"); opt_bgcolor = G_define_standard_option(G_OPT_CN); opt_bgcolor->key = "bgcolor"; opt_bgcolor->answer = "white"; opt_bgcolor->label = _("Background color"); opt_bgcolor->guisection = _("Background"); hidestr = G_define_flag(); hidestr->key = 'v'; hidestr->description = _("Do not show category labels"); hidestr->guisection = _("Advanced"); hidenum = G_define_flag(); hidenum->key = 'c'; hidenum->description = _("Do not show category numbers"); hidenum->guisection = _("Advanced"); showtick = G_define_flag(); showtick->key = 't'; showtick->description = _("Draw legend ticks for labels"); showtick->guisection = _("Gradient"); hidenodata = G_define_flag(); hidenodata->key = 'n'; hidenodata->description = _("Skip categories with no label"); hidenodata->guisection = _("Advanced"); smooth = G_define_flag(); smooth->key = 's'; smooth->description = _("Draw smooth gradient"); smooth->guisection = _("Gradient"); flipit = G_define_flag(); flipit->key = 'f'; flipit->description = _("Flip legend"); flipit->guisection = _("Advanced"); histo = G_define_flag(); histo->key = 'd'; histo->description = _("Add histogram to smoothed legend"); histo->guisection = _("Gradient"); showbg = G_define_flag(); showbg->key = 'b'; showbg->description = _("Show background"); showbg->guisection = _("Background"); log_sc = G_define_flag(); log_sc->key = 'l'; log_sc->description = _("Use logarithmic scale"); log_sc->guisection = _("Advanced"); G_option_required(opt_rast2d, opt_rast3d, NULL); G_option_exclusive(opt_rast2d, opt_rast3d, NULL); G_option_exclusive(hidenum, opt_ticks, NULL); G_option_exclusive(hidenum, opt_tstep, NULL); /* Check command line */ if (G_parser(argc, argv)) exit(EXIT_FAILURE); if (opt_rast2d->answer) { map_name = opt_rast2d->answer; maptype = MAP_TYPE_RASTER2D; } else { map_name = opt_rast3d->answer; maptype = MAP_TYPE_RASTER3D; } if (opt_title->answer) title = opt_title->answer; else title = ""; if (opt_units->answer) { units = opt_units->answer; } else units = ""; hide_catstr = hidestr->answer; /* note hide_catstr gets changed and re-read below */ hide_catnum = hidenum->answer; show_ticks = showtick->answer; hide_nodata = hidenodata->answer; do_smooth = smooth->answer; flip = flipit->answer; show_bg = showbg->answer; log_scale = log_sc->answer; if (showtick->answer) { label_indent = 12; } else label_indent = 6; if (opt_digits->answer != NULL) sscanf(opt_digits->answer, "%d", &digits); else digits = -1; color = D_parse_color(opt_color->answer, TRUE); if (opt_lines->answer != NULL) sscanf(opt_lines->answer, "%d", &lines); thin = 1; if (opt_thin->answer != NULL) sscanf(opt_thin->answer, "%d", &thin); if (!thin) thin = 1; if (opt_labelnum->answer != NULL) sscanf(opt_labelnum->answer, "%d", &steps); if ((opt_tstep->answer) || (opt_ticks->answer)) steps = 0; if (opt_tstep->answer != NULL) t_step = atof(opt_tstep->answer); ticksCount = 0; if (opt_ticks->answer != NULL) { tick_values = (double *)G_calloc(100 + 1, sizeof(double)); for (i = 0; i < 100; i++) /* fill with dummy values */ tick_values[i] = 1.0 * (i + 1); tick_values[i] = 0; for (i = 0; (opt_ticks->answers[i] != NULL) && i < 100; i++) tick_values[i] = atof(opt_ticks->answers[i]); ticksCount = i; } catlistCount = 0; if (opt_use->answer != NULL) { /* should this be answerS ? */ use_catlist = TRUE; catlist = (double *)G_calloc(100 + 1, sizeof(double)); for (i = 0; i < 100; i++) /* fill with dummy values */ catlist[i] = 1.0 * (i + 1); catlist[i] = 0; for (i = 0; (opt_use->answers[i] != NULL) && i < 100; i++) catlist[i] = atof(opt_use->answers[i]); catlistCount = i; } else use_catlist = FALSE; UserRange = FALSE; if (opt_range->answer != NULL) { /* should this be answerS ? */ sscanf(opt_range->answers[0], "%lf", &UserRangeMin); sscanf(opt_range->answers[1], "%lf", &UserRangeMax); UserRange = TRUE; if (UserRangeMin > UserRangeMax) { UserRangeTemp = UserRangeMax; UserRangeMax = UserRangeMin; UserRangeMin = UserRangeTemp; flip = !flip; } } if (maptype == MAP_TYPE_RASTER2D) { if (Rast_read_colors(map_name, "", &colors) == -1) G_fatal_error(_("Color file for <%s> not available"), map_name); fp = Rast_map_is_fp(map_name, ""); Rast_read_cats(map_name, "", &cats); } else { if (Rast3d_read_colors(map_name, "", &colors) == -1) G_fatal_error(_("Color file for <%s> not available"), map_name); fp = TRUE; /* currently raster 3D is always floating point */ Rast3d_read_cats(map_name, "", &cats); } if (fp && !use_catlist) { do_smooth = TRUE; /* fprintf(stderr, "FP map found - switching gradient legend on\n"); */ flip = !flip; } D_open_driver(); /* Parse and select background color */ colorb = D_parse_color(opt_brdcolor->answer, TRUE); colorbg = D_parse_color(opt_bgcolor->answer, TRUE); if (opt_font->answer) D_font(opt_font->answer); else if (opt_path->answer) D_font(opt_path->answer); if (opt_fontsize->answer != NULL) fontsize = atof(opt_fontsize->answer); else fontsize = 12; /* dummy placeholder, should never be called */ if (opt_charset->answer) D_encoding(opt_charset->answer); if (opt_tit_fontsize->answer != NULL) tit_fontsize = atof(opt_tit_fontsize->answer); else tit_fontsize = 0; if (opt_at->answer != NULL) { sscanf(opt_at->answers[0], "%lf", &Y1); sscanf(opt_at->answers[1], "%lf", &Y0); sscanf(opt_at->answers[2], "%lf", &X0); sscanf(opt_at->answers[3], "%lf", &X1); } else { /* default */ Y1 = 12; Y0 = 88; X0 = 3; X1 = 7; if (histo->answer) { X0 += 5; X1 += 5; } } if (show_bg) draw(map_name, maptype, color, thin, lines, steps, fp, label_indent, hide_catnum, hide_catstr, show_ticks, hide_nodata, do_smooth, cats, colors, X0, X1, Y0, Y1, flip, UserRange, UserRangeMin, UserRangeMax, catlist, catlistCount, use_catlist, ticksCount, fontsize, tit_fontsize, title, tick_values, t_step, colorb, colorbg, opt_use, opt_at, opt_fontsize, opt_tstep, opt_range, histo, hidestr, log_scale, 0, digits, units); draw(map_name, maptype, color, thin, lines, steps, fp, label_indent, hide_catnum, hide_catstr, show_ticks, hide_nodata, do_smooth, cats, colors, X0, X1, Y0, Y1, flip, UserRange, UserRangeMin, UserRangeMax, catlist, catlistCount, use_catlist, ticksCount, fontsize, tit_fontsize, title, tick_values, t_step, colorb, colorbg, opt_use, opt_at, opt_fontsize, opt_tstep, opt_range, histo, hidestr, log_scale, 1, digits, units); D_close_driver(); exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { struct GModule *module; struct Option *bg_color_opt, *fg_color_opt, *coords, *fsize, *barstyle, *text_placement, *length_opt, *segm_opt, *units_opt, *label_opt, *width_scale_opt; struct Flag *feet, *no_text, *n_symbol; struct Cell_head W; double east, north; double fontsize; int bar_style, text_position, units; double length; int segm; char *label; double width_scale; /* Initialize the GIS calls */ G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("display")); G_add_keyword(_("cartography")); module->description = _("Displays a barscale on the graphics monitor."); feet = G_define_flag(); feet->key = 'f'; feet->description = _("Use feet/miles instead of meters"); no_text = G_define_flag(); no_text->key = 't'; no_text->description = _("Draw the scale bar without text"); no_text->guisection = _("Text"); n_symbol = G_define_flag(); n_symbol->key = 'n'; n_symbol->description = _("Display north-arrow symbol."); n_symbol->guisection = _("Style"); barstyle = G_define_option(); barstyle->key = "style"; barstyle->description = _("Type of barscale to draw"); barstyle->options = "classic,line,solid,hollow,full_checker,part_checker,mixed_checker,tail_checker,up_ticks,down_ticks,both_ticks,arrow_ends"; barstyle->answer = "classic"; barstyle->gisprompt = "old,barscale,barscale"; barstyle->guisection = _("Style"); G_asprintf((char **)&(barstyle->descriptions), "classic;%s;" "line;%s;" "solid;%s;" "hollow;%s;" "full_checker;%s;" "part_checker;%s;" "mixed_checker;%s;" "tail_checker;%s;" "up_ticks;%s;" "down_ticks;%s;" "both_ticks;%s;" "arrow_ends;%s", _("Classic style"), _("Line style"), _("Solid style"), _("Hollow style"), _("Full checker style"), _("Part checker style"), _("Mixed checker style"), _("Tail checker style"), _("Up ticks style"), _("Down ticks style"), _("Both ticks style"), _("Arrow ends style")); coords = G_define_option(); coords->key = "at"; coords->key_desc = "x,y"; coords->type = TYPE_DOUBLE; coords->answer = "0.0,10.0"; coords->options = "0-100"; coords->label = _("Screen coordinates of the rectangle's top-left corner"); coords->description = _("(0,0) is lower-left of the display frame"); length_opt = G_define_option(); length_opt->key = "length"; length_opt->key_desc = "integer"; length_opt->type = TYPE_INTEGER; length_opt->answer = "0"; length_opt->options = "0-"; length_opt->label = _("Length of barscale in map units"); units_opt = G_define_option(); units_opt->key = "units"; units_opt->description = _("Barscale units to display"); units_opt->options = "meters, kilometers, feet, miles"; label_opt = G_define_option(); label_opt->key = "label"; label_opt->description = _("Custom label of unit"); label_opt->type = TYPE_STRING; label_opt->guisection = _("Text"); segm_opt = G_define_option(); segm_opt->key = "segment"; segm_opt->type = TYPE_INTEGER; segm_opt->answer = "10"; segm_opt->options = "1-100"; segm_opt->label = _("Number of segments"); segm_opt->guisection = _("Style"); fg_color_opt = G_define_standard_option(G_OPT_C); fg_color_opt->label = _("Bar scale and text color"); fg_color_opt->guisection = _("Colors"); bg_color_opt = G_define_standard_option(G_OPT_CN); bg_color_opt->key = "bgcolor"; bg_color_opt->answer = "white"; bg_color_opt->label = _("Background color (drawn behind the bar)"); bg_color_opt->guisection = _("Colors"); text_placement = G_define_option(); text_placement->key = "text_position"; text_placement->description = _("Text position"); text_placement->options = "under,over,left,right"; text_placement->answer = "right"; text_placement->guisection = _("Text"); width_scale_opt = G_define_option(); width_scale_opt->key = "width_scale"; width_scale_opt->type = TYPE_DOUBLE; width_scale_opt->required = NO; width_scale_opt->answer = "1"; width_scale_opt->options = "0.5-100"; width_scale_opt->description = _("Scale factor to change bar width"); fsize = G_define_option(); fsize->key = "fontsize"; fsize->type = TYPE_DOUBLE; fsize->required = NO; fsize->answer = "12"; fsize->options = "1-360"; fsize->description = _("Font size"); fsize->guisection = _("Text"); G_option_exclusive(feet, units_opt, NULL); if (G_parser(argc, argv)) exit(EXIT_FAILURE); G_get_window(&W); if (W.proj == PROJECTION_LL) G_fatal_error(_("%s does not work with a latitude-longitude location"), argv[0]); north_arrow = n_symbol->answer ? TRUE : FALSE; switch (barstyle->answer[0]) { case 'c': bar_style = STYLE_CLASSIC_BAR; break; case 'p': bar_style = STYLE_PART_CHECKER; break; case 'f': bar_style = STYLE_FULL_CHECKER; break; case 'm': bar_style = STYLE_MIXED_CHECKER; break; case 't': bar_style = STYLE_TAIL_CHECKER; break; case 'l': bar_style = STYLE_THIN_WITH_ENDS; break; case 's': bar_style = STYLE_SOLID_BAR; break; case 'h': bar_style = STYLE_HOLLOW_BAR; break; case 'u': bar_style = STYLE_TICKS_UP; break; case 'd': bar_style = STYLE_TICKS_DOWN; break; case 'b': bar_style = STYLE_TICKS_BOTH; break; case 'a': bar_style = STYLE_ARROW_ENDS; break; default: G_fatal_error(_("Programmer error")); } switch (text_placement->answer[0]) { case 'u': text_position = TEXT_UNDER; break; case 'o': text_position = TEXT_OVER; break; case 'l': text_position = TEXT_LEFT; break; case 'r': text_position = TEXT_RIGHT; break; default: G_fatal_error(_("Programmer error")); } sscanf(coords->answers[0], "%lf", &east); sscanf(coords->answers[1], "%lf", &north); length = atof(length_opt->answer); sscanf(segm_opt->answer, "%d", &segm); if (feet->answer == 1){ use_feet = 1; units = U_FEET; label = "ft"; } else { if (!units_opt->answer) units = G_database_unit(); else units = G_units(units_opt->answer); switch (units) { case U_METERS: label = "m"; break; case U_KILOMETERS: label = "km"; break; case U_FEET: use_feet = 1; label = "ft"; break; case U_USFEET: use_feet = 1; label = "ft"; break; case U_MILES: use_feet = 1; label = "mi"; break; default: units = U_METERS; label = "m"; } } if (label_opt->answer){ label = label_opt->answer; } fontsize = atof(fsize->answer); if (no_text->answer) fontsize = -1; width_scale = atof(width_scale_opt->answer); /* Parse and select foreground color */ fg_color = D_parse_color(fg_color_opt->answer, 0); /* Parse and select background color */ bg_color = D_parse_color(bg_color_opt->answer, 1); if (bg_color == 0) do_background = FALSE; D_open_driver(); D_setup(0); draw_scale(east, north, length, segm, units, label, bar_style, text_position, width_scale, fontsize); D_save_command(G_recreate_command()); D_close_driver(); exit(EXIT_SUCCESS); }
int main(int argc, char *argv[]) { int out_fd, base_raster; char *infile, *outmap; int percent; double zrange_min, zrange_max, d_tmp; double irange_min, irange_max; unsigned long estimated_lines; RASTER_MAP_TYPE rtype, base_raster_data_type; struct History history; char title[64]; SEGMENT base_segment; struct PointBinning point_binning; void *base_array; void *raster_row; struct Cell_head region; struct Cell_head input_region; int rows, last_rows, row0, cols; /* scan box size */ int row; /* counters */ int pass, npasses; unsigned long line, line_total; unsigned int counter; unsigned long n_invalid; char buff[BUFFSIZE]; double x, y, z; double intensity; int arr_row, arr_col; unsigned long count, count_total; int point_class; double zscale = 1.0; double iscale = 1.0; double res = 0.0; struct BinIndex bin_index_nodes; bin_index_nodes.num_nodes = 0; bin_index_nodes.max_nodes = 0; bin_index_nodes.nodes = 0; struct GModule *module; struct Option *input_opt, *output_opt, *percent_opt, *type_opt, *filter_opt, *class_opt; struct Option *method_opt, *base_raster_opt; struct Option *zrange_opt, *zscale_opt; struct Option *irange_opt, *iscale_opt; struct Option *trim_opt, *pth_opt, *res_opt; struct Option *file_list_opt; struct Flag *print_flag, *scan_flag, *shell_style, *over_flag, *extents_flag; struct Flag *intens_flag, *intens_import_flag; struct Flag *set_region_flag; struct Flag *base_rast_res_flag; struct Flag *only_valid_flag; /* LAS */ LASReaderH LAS_reader; LASHeaderH LAS_header; LASSRSH LAS_srs; LASPointH LAS_point; int return_filter; const char *projstr; struct Cell_head cellhd, loc_wind; unsigned int n_filtered; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("raster")); G_add_keyword(_("import")); G_add_keyword(_("LIDAR")); G_add_keyword(_("statistics")); G_add_keyword(_("conversion")); G_add_keyword(_("aggregation")); G_add_keyword(_("binning")); module->description = _("Creates a raster map from LAS LiDAR points using univariate statistics."); input_opt = G_define_standard_option(G_OPT_F_BIN_INPUT); input_opt->required = NO; input_opt->label = _("LAS input file"); input_opt->description = _("LiDAR input files in LAS format (*.las or *.laz)"); input_opt->guisection = _("Input"); output_opt = G_define_standard_option(G_OPT_R_OUTPUT); output_opt->required = NO; output_opt->guisection = _("Output"); file_list_opt = G_define_standard_option(G_OPT_F_INPUT); file_list_opt->key = "file"; file_list_opt->label = _("File containing names of LAS input files"); file_list_opt->description = _("LiDAR input files in LAS format (*.las or *.laz)"); file_list_opt->required = NO; file_list_opt->guisection = _("Input"); method_opt = G_define_option(); method_opt->key = "method"; method_opt->type = TYPE_STRING; method_opt->required = NO; method_opt->description = _("Statistic to use for raster values"); method_opt->options = "n,min,max,range,sum,mean,stddev,variance,coeff_var,median,percentile,skewness,trimmean"; method_opt->answer = "mean"; method_opt->guisection = _("Statistic"); G_asprintf((char **)&(method_opt->descriptions), "n;%s;" "min;%s;" "max;%s;" "range;%s;" "sum;%s;" "mean;%s;" "stddev;%s;" "variance;%s;" "coeff_var;%s;" "median;%s;" "percentile;%s;" "skewness;%s;" "trimmean;%s", _("Number of points in cell"), _("Minimum value of point values in cell"), _("Maximum value of point values in cell"), _("Range of point values in cell"), _("Sum of point values in cell"), _("Mean (average) value of point values in cell"), _("Standard deviation of point values in cell"), _("Variance of point values in cell"), _("Coefficient of variance of point values in cell"), _("Median value of point values in cell"), _("pth (nth) percentile of point values in cell"), _("Skewness of point values in cell"), _("Trimmed mean of point values in cell")); type_opt = G_define_standard_option(G_OPT_R_TYPE); type_opt->required = NO; type_opt->answer = "FCELL"; base_raster_opt = G_define_standard_option(G_OPT_R_INPUT); base_raster_opt->key = "base_raster"; base_raster_opt->required = NO; base_raster_opt->label = _("Subtract raster values from the Z coordinates"); base_raster_opt->description = _("The scale for Z is applied beforehand, the range filter for" " Z afterwards"); base_raster_opt->guisection = _("Transform"); zrange_opt = G_define_option(); zrange_opt->key = "zrange"; zrange_opt->type = TYPE_DOUBLE; zrange_opt->required = NO; zrange_opt->key_desc = "min,max"; zrange_opt->description = _("Filter range for Z data (min,max)"); zrange_opt->guisection = _("Selection"); zscale_opt = G_define_option(); zscale_opt->key = "zscale"; zscale_opt->type = TYPE_DOUBLE; zscale_opt->required = NO; zscale_opt->answer = "1.0"; zscale_opt->description = _("Scale to apply to Z data"); zscale_opt->guisection = _("Transform"); irange_opt = G_define_option(); irange_opt->key = "intensity_range"; irange_opt->type = TYPE_DOUBLE; irange_opt->required = NO; irange_opt->key_desc = "min,max"; irange_opt->description = _("Filter range for intensity values (min,max)"); irange_opt->guisection = _("Selection"); iscale_opt = G_define_option(); iscale_opt->key = "intensity_scale"; iscale_opt->type = TYPE_DOUBLE; iscale_opt->required = NO; iscale_opt->answer = "1.0"; iscale_opt->description = _("Scale to apply to intensity values"); iscale_opt->guisection = _("Transform"); percent_opt = G_define_option(); percent_opt->key = "percent"; percent_opt->type = TYPE_INTEGER; percent_opt->required = NO; percent_opt->answer = "100"; percent_opt->options = "1-100"; percent_opt->description = _("Percent of map to keep in memory"); /* I would prefer to call the following "percentile", but that has too * much namespace overlap with the "percent" option above */ pth_opt = G_define_option(); pth_opt->key = "pth"; pth_opt->type = TYPE_INTEGER; pth_opt->required = NO; pth_opt->options = "1-100"; pth_opt->description = _("pth percentile of the values"); pth_opt->guisection = _("Statistic"); trim_opt = G_define_option(); trim_opt->key = "trim"; trim_opt->type = TYPE_DOUBLE; trim_opt->required = NO; trim_opt->options = "0-50"; trim_opt->label = _("Discard given percentage of the smallest and largest values"); trim_opt->description = _("Discard <trim> percent of the smallest and <trim> percent of the largest observations"); trim_opt->guisection = _("Statistic"); res_opt = G_define_option(); res_opt->key = "resolution"; res_opt->type = TYPE_DOUBLE; res_opt->required = NO; res_opt->description = _("Output raster resolution"); res_opt->guisection = _("Output"); filter_opt = G_define_option(); filter_opt->key = "return_filter"; filter_opt->type = TYPE_STRING; filter_opt->required = NO; filter_opt->label = _("Only import points of selected return type"); filter_opt->description = _("If not specified, all points are imported"); filter_opt->options = "first,last,mid"; filter_opt->guisection = _("Selection"); class_opt = G_define_option(); class_opt->key = "class_filter"; class_opt->type = TYPE_INTEGER; class_opt->multiple = YES; class_opt->required = NO; class_opt->label = _("Only import points of selected class(es)"); class_opt->description = _("Input is comma separated integers. " "If not specified, all points are imported."); class_opt->guisection = _("Selection"); print_flag = G_define_flag(); print_flag->key = 'p'; print_flag->description = _("Print LAS file info and exit"); extents_flag = G_define_flag(); extents_flag->key = 'e'; extents_flag->label = _("Use the extent of the input for the raster extent"); extents_flag->description = _("Set internally computational region extents based on the" " point cloud"); extents_flag->guisection = _("Output"); set_region_flag = G_define_flag(); set_region_flag->key = 'n'; set_region_flag->label = _("Set computation region to match the new raster map"); set_region_flag->description = _("Set computation region to match the 2D extent and resolution" " of the newly created new raster map"); set_region_flag->guisection = _("Output"); over_flag = G_define_flag(); over_flag->key = 'o'; over_flag->label = _("Override projection check (use current location's projection)"); over_flag->description = _("Assume that the dataset has same projection as the current location"); scan_flag = G_define_flag(); scan_flag->key = 's'; scan_flag->description = _("Scan data file for extent then exit"); shell_style = G_define_flag(); shell_style->key = 'g'; shell_style->description = _("In scan mode, print using shell script style"); intens_flag = G_define_flag(); intens_flag->key = 'i'; intens_flag->label = _("Use intensity values rather than Z values"); intens_flag->description = _("Uses intensity values everywhere as if they would be Z" " coordinates"); intens_import_flag = G_define_flag(); intens_import_flag->key = 'j'; intens_import_flag->description = _("Use Z values for filtering, but intensity values for statistics"); base_rast_res_flag = G_define_flag(); base_rast_res_flag->key = 'd'; base_rast_res_flag->label = _("Use base raster resolution instead of computational region"); base_rast_res_flag->description = _("For getting values from base raster, use its actual" " resolution instead of computational region resolution"); only_valid_flag = G_define_flag(); only_valid_flag->key = 'v'; only_valid_flag->label = _("Use only valid points"); only_valid_flag->description = _("Points invalid according to APSRS LAS specification will be" " filtered out"); only_valid_flag->guisection = _("Selection"); G_option_required(input_opt, file_list_opt, NULL); G_option_exclusive(input_opt, file_list_opt, NULL); G_option_required(output_opt, print_flag, scan_flag, shell_style, NULL); G_option_exclusive(intens_flag, intens_import_flag, NULL); G_option_requires(base_rast_res_flag, base_raster_opt, NULL); if (G_parser(argc, argv)) exit(EXIT_FAILURE); int only_valid = FALSE; n_invalid = 0; if (only_valid_flag->answer) only_valid = TRUE; /* we could use rules but this gives more info and allows continuing */ if (set_region_flag->answer && !(extents_flag->answer || res_opt->answer)) { G_warning(_("Flag %c makes sense only with %s option or -%c flag"), set_region_flag->key, res_opt->key, extents_flag->key); /* avoid the call later on */ set_region_flag->answer = '\0'; } struct StringList infiles; if (file_list_opt->answer) { if (access(file_list_opt->answer, F_OK) != 0) G_fatal_error(_("File <%s> does not exist"), file_list_opt->answer); string_list_from_file(&infiles, file_list_opt->answer); } else { string_list_from_one_item(&infiles, input_opt->answer); } /* parse input values */ outmap = output_opt->answer; if (shell_style->answer && !scan_flag->answer) { scan_flag->answer = 1; /* pointer not int, so set = shell_style->answer ? */ } /* check zrange and extent relation */ if (scan_flag->answer || extents_flag->answer) { if (zrange_opt->answer) G_warning(_("zrange will not be taken into account during scan")); } Rast_get_window(®ion); /* G_get_window seems to be unreliable if the location has been changed */ G_get_set_window(&loc_wind); /* TODO: v.in.lidar uses G_get_default_window() */ estimated_lines = 0; int i; for (i = 0; i < infiles.num_items; i++) { infile = infiles.items[i]; /* don't if file not found */ if (access(infile, F_OK) != 0) G_fatal_error(_("Input file <%s> does not exist"), infile); /* Open LAS file*/ LAS_reader = LASReader_Create(infile); if (LAS_reader == NULL) G_fatal_error(_("Unable to open file <%s> as a LiDAR point cloud"), infile); LAS_header = LASReader_GetHeader(LAS_reader); if (LAS_header == NULL) { G_fatal_error(_("Unable to read LAS header of <%s>"), infile); } LAS_srs = LASHeader_GetSRS(LAS_header); /* print info or check projection if we are actually importing */ if (print_flag->answer) { /* print filename when there is more than one file */ if (infiles.num_items > 1) fprintf(stdout, "File: %s\n", infile); /* Print LAS header */ print_lasinfo(LAS_header, LAS_srs); } else { /* report that we are checking more files */ if (i == 1) G_message(_("First file's projection checked," " checking projection of the other files...")); /* Fetch input map projection in GRASS form. */ projstr = LASSRS_GetWKT_CompoundOK(LAS_srs); /* we are printing the non-warning messages only for first file */ projection_check_wkt(cellhd, loc_wind, projstr, over_flag->answer, shell_style->answer || i); /* if there is a problem in some other file, first OK message * is printed but than a warning, this is not ideal but hopefully * not so confusing when importing multiple files */ } if (scan_flag->answer || extents_flag->answer) { /* we assign to the first one (i==0) but update for the rest */ scan_bounds(LAS_reader, shell_style->answer, extents_flag->answer, i, zscale, ®ion); } /* number of estimated point across all files */ /* TODO: this should be ull which won't work with percent report */ estimated_lines += LASHeader_GetPointRecordsCount(LAS_header); /* We are closing all again and we will be opening them later, * so we don't have to worry about limit for open files. */ LASSRS_Destroy(LAS_srs); LASHeader_Destroy(LAS_header); LASReader_Destroy(LAS_reader); } /* if we are not importing, end */ if (print_flag->answer || scan_flag->answer) exit(EXIT_SUCCESS); return_filter = LAS_ALL; if (filter_opt->answer) { if (strcmp(filter_opt->answer, "first") == 0) return_filter = LAS_FIRST; else if (strcmp(filter_opt->answer, "last") == 0) return_filter = LAS_LAST; else if (strcmp(filter_opt->answer, "mid") == 0) return_filter = LAS_MID; else G_fatal_error(_("Unknown filter option <%s>"), filter_opt->answer); } struct ReturnFilter return_filter_struct; return_filter_struct.filter = return_filter; struct ClassFilter class_filter; class_filter_create_from_strings(&class_filter, class_opt->answers); percent = atoi(percent_opt->answer); /* TODO: we already used zscale */ /* TODO: we don't report intensity range */ if (zscale_opt->answer) zscale = atof(zscale_opt->answer); if (iscale_opt->answer) iscale = atof(iscale_opt->answer); /* parse zrange */ if (zrange_opt->answer != NULL) { if (zrange_opt->answers[0] == NULL) G_fatal_error(_("Invalid zrange")); sscanf(zrange_opt->answers[0], "%lf", &zrange_min); sscanf(zrange_opt->answers[1], "%lf", &zrange_max); if (zrange_min > zrange_max) { d_tmp = zrange_max; zrange_max = zrange_min; zrange_min = d_tmp; } } /* parse irange */ if (irange_opt->answer != NULL) { if (irange_opt->answers[0] == NULL) G_fatal_error(_("Invalid %s"), irange_opt->key); sscanf(irange_opt->answers[0], "%lf", &irange_min); sscanf(irange_opt->answers[1], "%lf", &irange_max); if (irange_min > irange_max) { d_tmp = irange_max; irange_max = irange_min; irange_min = d_tmp; } } point_binning_set(&point_binning, method_opt->answer, pth_opt->answer, trim_opt->answer, FALSE); base_array = NULL; if (strcmp("CELL", type_opt->answer) == 0) rtype = CELL_TYPE; else if (strcmp("DCELL", type_opt->answer) == 0) rtype = DCELL_TYPE; else rtype = FCELL_TYPE; if (point_binning.method == METHOD_N) rtype = CELL_TYPE; if (res_opt->answer) { /* align to resolution */ res = atof(res_opt->answer); if (!G_scan_resolution(res_opt->answer, &res, region.proj)) G_fatal_error(_("Invalid input <%s=%s>"), res_opt->key, res_opt->answer); if (res <= 0) G_fatal_error(_("Option '%s' must be > 0.0"), res_opt->key); region.ns_res = region.ew_res = res; region.north = ceil(region.north / res) * res; region.south = floor(region.south / res) * res; region.east = ceil(region.east / res) * res; region.west = floor(region.west / res) * res; G_adjust_Cell_head(®ion, 0, 0); } else if (extents_flag->answer) { /* align to current region */ Rast_align_window(®ion, &loc_wind); } Rast_set_output_window(®ion); rows = last_rows = region.rows; npasses = 1; if (percent < 100) { rows = (int)(region.rows * (percent / 100.0)); npasses = region.rows / rows; last_rows = region.rows - npasses * rows; if (last_rows) npasses++; else last_rows = rows; } cols = region.cols; G_debug(2, "region.n=%f region.s=%f region.ns_res=%f", region.north, region.south, region.ns_res); G_debug(2, "region.rows=%d [box_rows=%d] region.cols=%d", region.rows, rows, region.cols); /* using row-based chunks (used for output) when input and output * region matches and using segment library when they don't */ int use_segment = 0; int use_base_raster_res = 0; /* TODO: see if the input region extent is smaller than the raster * if yes, the we need to load the whole base raster if the -e * flag was defined (alternatively clip the regions) */ if (base_rast_res_flag->answer) use_base_raster_res = 1; if (base_raster_opt->answer && (res_opt->answer || use_base_raster_res || extents_flag->answer)) use_segment = 1; if (base_raster_opt->answer && !use_segment) { /* TODO: do we need to test existence first? mapset? */ base_raster = Rast_open_old(base_raster_opt->answer, ""); base_raster_data_type = Rast_get_map_type(base_raster); base_array = G_calloc((size_t)rows * (cols + 1), Rast_cell_size(base_raster_data_type)); } if (base_raster_opt->answer && use_segment) { if (use_base_raster_res) { /* read raster actual extent and resolution */ Rast_get_cellhd(base_raster_opt->answer, "", &input_region); /* TODO: make it only as small as the output is or points are */ Rast_set_input_window(&input_region); /* we have split window */ } else { Rast_get_input_window(&input_region); } rast_segment_open(&base_segment, base_raster_opt->answer, &base_raster_data_type); } if (!scan_flag->answer) { if (!check_rows_cols_fit_to_size_t(rows, cols)) G_fatal_error(_("Unable to process the hole map at once. " "Please set the '%s' option to some value lower than 100."), percent_opt->key); point_binning_memory_test(&point_binning, rows, cols, rtype); } /* open output map */ out_fd = Rast_open_new(outmap, rtype); /* allocate memory for a single row of output data */ raster_row = Rast_allocate_output_buf(rtype); G_message(_("Reading data ...")); count_total = line_total = 0; /* main binning loop(s) */ for (pass = 1; pass <= npasses; pass++) { if (npasses > 1) G_message(_("Pass #%d (of %d) ..."), pass, npasses); /* figure out segmentation */ row0 = (pass - 1) * rows; if (pass == npasses) { rows = last_rows; } if (base_array) { G_debug(2, "filling base raster array"); for (row = 0; row < rows; row++) { Rast_get_row(base_raster, base_array + ((size_t) row * cols * Rast_cell_size(base_raster_data_type)), row, base_raster_data_type); } } G_debug(2, "pass=%d/%d rows=%d", pass, npasses, rows); point_binning_allocate(&point_binning, rows, cols, rtype); line = 0; count = 0; counter = 0; G_percent_reset(); /* loop of input files */ for (i = 0; i < infiles.num_items; i++) { infile = infiles.items[i]; /* we already know file is there, so just do basic checks */ LAS_reader = LASReader_Create(infile); if (LAS_reader == NULL) G_fatal_error(_("Unable to open file <%s>"), infile); while ((LAS_point = LASReader_GetNextPoint(LAS_reader)) != NULL) { line++; counter++; if (counter == 100000) { /* speed */ if (line < estimated_lines) G_percent(line, estimated_lines, 3); counter = 0; } /* We always count them and report because behavior * changed in between 7.0 and 7.2 from undefined (but skipping * invalid points) to filtering them out only when requested. */ if (!LASPoint_IsValid(LAS_point)) { n_invalid++; if (only_valid) continue; } x = LASPoint_GetX(LAS_point); y = LASPoint_GetY(LAS_point); if (intens_flag->answer) /* use intensity as z here to allow all filters (and * modifications) below to be applied for intensity */ z = LASPoint_GetIntensity(LAS_point); else z = LASPoint_GetZ(LAS_point); int return_n = LASPoint_GetReturnNumber(LAS_point); int n_returns = LASPoint_GetNumberOfReturns(LAS_point); if (return_filter_is_out(&return_filter_struct, return_n, n_returns)) { n_filtered++; continue; } point_class = (int) LASPoint_GetClassification(LAS_point); if (class_filter_is_out(&class_filter, point_class)) continue; if (y <= region.south || y > region.north) { continue; } if (x < region.west || x >= region.east) { continue; } /* find the bin in the current array box */ arr_row = (int)((region.north - y) / region.ns_res) - row0; if (arr_row < 0 || arr_row >= rows) continue; arr_col = (int)((x - region.west) / region.ew_res); z = z * zscale; if (base_array) { double base_z; if (row_array_get_value_row_col(base_array, arr_row, arr_col, cols, base_raster_data_type, &base_z)) z -= base_z; else continue; } else if (use_segment) { double base_z; if (rast_segment_get_value_xy(&base_segment, &input_region, base_raster_data_type, x, y, &base_z)) z -= base_z; else continue; } if (zrange_opt->answer) { if (z < zrange_min || z > zrange_max) { continue; } } if (intens_import_flag->answer || irange_opt->answer) { intensity = LASPoint_GetIntensity(LAS_point); intensity *= iscale; if (irange_opt->answer) { if (intensity < irange_min || intensity > irange_max) { continue; } } /* use intensity for statistics */ if (intens_import_flag->answer) z = intensity; } count++; /* G_debug(5, "x: %f, y: %f, z: %f", x, y, z); */ update_value(&point_binning, &bin_index_nodes, cols, arr_row, arr_col, rtype, x, y, z); } /* while !EOF of one input file */ /* close input LAS file */ LASReader_Destroy(LAS_reader); } /* end of loop for all input files files */ G_percent(1, 1, 1); /* flush */ G_debug(2, "pass %d finished, %lu coordinates in box", pass, count); count_total += count; line_total += line; /* calc stats and output */ G_message(_("Writing to map ...")); for (row = 0; row < rows; row++) { /* potentially vector writing can be independent on the binning */ write_values(&point_binning, &bin_index_nodes, raster_row, row, cols, rtype, NULL); /* write out line of raster data */ Rast_put_row(out_fd, raster_row, rtype); } /* free memory */ point_binning_free(&point_binning, &bin_index_nodes); } /* passes loop */ if (base_array) Rast_close(base_raster); if (use_segment) Segment_close(&base_segment); G_percent(1, 1, 1); /* flush */ G_free(raster_row); /* close raster file & write history */ Rast_close(out_fd); sprintf(title, "Raw X,Y,Z data binned into a raster grid by cell %s", method_opt->answer); Rast_put_cell_title(outmap, title); Rast_short_history(outmap, "raster", &history); Rast_command_history(&history); Rast_set_history(&history, HIST_DATSRC_1, infile); Rast_write_history(outmap, &history); /* set computation region to the new raster map */ /* TODO: should be in the done message */ if (set_region_flag->answer) G_put_window(®ion); if (n_invalid && only_valid) G_message(_("%lu input points were invalid and filtered out"), n_invalid); if (n_invalid && !only_valid) G_message(_("%lu input points were invalid, use -%c flag to filter" " them out"), n_invalid, only_valid_flag->key); if (infiles.num_items > 1) { sprintf(buff, _("Raster map <%s> created." " %lu points from %d files found in region."), outmap, count_total, infiles.num_items); } else { sprintf(buff, _("Raster map <%s> created." " %lu points found in region."), outmap, count_total); } G_done_msg("%s", buff); G_debug(1, "Processed %lu points.", line_total); string_list_free(&infiles); exit(EXIT_SUCCESS); }