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[]) { int i; int print_flag = 0; int flat_flag; int set_flag; double x; int ival; int row_flag = 0, col_flag = 0; struct Cell_head window, temp_window; const char *value; const char *name; const char *mapset; char **rast_ptr, **vect_ptr; struct GModule *module; struct { struct Flag *update, *print, *gprint, *flprint, *lprint, *eprint, *nangle, *center, *res_set, *dist_res, *dflt, *z, *savedefault, *bbox, *gmt_style, *wms_style; } flag; struct { struct Option *north, *south, *east, *west, *top, *bottom, *res, *nsres, *ewres, *res3, *tbres, *rows, *cols, *save, *region, *raster, *raster3d, *align, *zoom, *vect; } parm; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("general")); G_add_keyword(_("settings")); module->description = _("Manages the boundary definitions for the " "geographic region."); /* flags */ flag.dflt = G_define_flag(); flag.dflt->key = 'd'; flag.dflt->description = _("Set from default region"); flag.dflt->guisection = _("Existing"); flag.savedefault = G_define_flag(); flag.savedefault->key = 's'; flag.savedefault->label = _("Save as default region"); flag.savedefault->description = _("Only possible from the PERMANENT mapset"); flag.savedefault->guisection = _("Existing"); flag.print = G_define_flag(); flag.print->key = 'p'; flag.print->description = _("Print the current region"); flag.print->guisection = _("Print"); flag.lprint = G_define_flag(); flag.lprint->key = 'l'; flag.lprint->description = _("Print the current region in lat/long " "using the current ellipsoid/datum"); flag.lprint->guisection = _("Print"); flag.eprint = G_define_flag(); flag.eprint->key = 'e'; flag.eprint->description = _("Print the current region extent"); flag.eprint->guisection = _("Print"); flag.center = G_define_flag(); flag.center->key = 'c'; flag.center->description = _("Print the current region map center coordinates"); flag.center->guisection = _("Print"); flag.gmt_style = G_define_flag(); flag.gmt_style->key = 't'; flag.gmt_style->description = _("Print the current region in GMT style"); flag.gmt_style->guisection = _("Print"); flag.wms_style = G_define_flag(); flag.wms_style->key = 'w'; flag.wms_style->description = _("Print the current region in WMS style"); flag.wms_style->guisection = _("Print"); flag.dist_res = G_define_flag(); flag.dist_res->key = 'm'; flag.dist_res->description = _("Print region resolution in meters (geodesic)"); flag.dist_res->guisection = _("Print"); flag.nangle = G_define_flag(); flag.nangle->key = 'n'; flag.nangle->label = _("Print the convergence angle (degrees CCW)"); flag.nangle->description = _("The difference between the projection's grid north and true north, " "measured at the center coordinates of the current region."); flag.nangle->guisection = _("Print"); flag.z = G_define_flag(); flag.z->key = '3'; flag.z->description = _("Print also 3D settings"); flag.z->guisection = _("Print"); flag.bbox = G_define_flag(); flag.bbox->key = 'b'; flag.bbox->description = _("Print the maximum bounding box in lat/long on WGS84"); flag.bbox->guisection = _("Print"); flag.gprint = G_define_flag(); flag.gprint->key = 'g'; flag.gprint->description = _("Print in shell script style"); flag.gprint->guisection = _("Print"); flag.flprint = G_define_flag(); flag.flprint->key = 'f'; flag.flprint->description = _("Print in shell script style, but in one line (flat)"); flag.flprint->guisection = _("Print"); flag.res_set = G_define_flag(); flag.res_set->key = 'a'; flag.res_set->description = _("Align region to resolution (default = align to bounds, " "works only for 2D resolution)"); flag.res_set->guisection = _("Bounds"); flag.update = G_define_flag(); flag.update->key = 'u'; flag.update->description = _("Do not update the current region"); flag.update->guisection = _("Effects"); /* parameters */ parm.region = G_define_standard_option(G_OPT_M_REGION); parm.region->description = _("Set current region from named region"); parm.region->guisection = _("Existing"); parm.raster = G_define_standard_option(G_OPT_R_MAP); parm.raster->key = "raster"; parm.raster->required = NO; parm.raster->multiple = YES; parm.raster->description = _("Set region to match raster map(s)"); parm.raster->guisection = _("Existing"); parm.raster3d = G_define_standard_option(G_OPT_R3_MAP); parm.raster3d->key = "raster_3d"; parm.raster3d->required = NO; parm.raster3d->multiple = NO; parm.raster3d->description = _("Set region to match 3D raster map(s) (both 2D and 3D " "values)"); parm.raster3d->guisection = _("Existing"); parm.vect = G_define_standard_option(G_OPT_V_MAP); parm.vect->key = "vector"; parm.vect->required = NO; parm.vect->multiple = YES; parm.vect->label = _("Set region to match vector map(s)"); parm.vect->description = NULL; parm.vect->guisection = _("Existing"); parm.north = G_define_option(); parm.north->key = "n"; parm.north->key_desc = "value"; parm.north->required = NO; parm.north->multiple = NO; parm.north->type = TYPE_STRING; parm.north->description = _("Value for the northern edge"); parm.north->guisection = _("Bounds"); parm.south = G_define_option(); parm.south->key = "s"; parm.south->key_desc = "value"; parm.south->required = NO; parm.south->multiple = NO; parm.south->type = TYPE_STRING; parm.south->description = _("Value for the southern edge"); parm.south->guisection = _("Bounds"); parm.east = G_define_option(); parm.east->key = "e"; parm.east->key_desc = "value"; parm.east->required = NO; parm.east->multiple = NO; parm.east->type = TYPE_STRING; parm.east->description = _("Value for the eastern edge"); parm.east->guisection = _("Bounds"); parm.west = G_define_option(); parm.west->key = "w"; parm.west->key_desc = "value"; parm.west->required = NO; parm.west->multiple = NO; parm.west->type = TYPE_STRING; parm.west->description = _("Value for the western edge"); parm.west->guisection = _("Bounds"); parm.top = G_define_option(); parm.top->key = "t"; parm.top->key_desc = "value"; parm.top->required = NO; parm.top->multiple = NO; parm.top->type = TYPE_STRING; parm.top->description = _("Value for the top edge"); parm.top->guisection = _("Bounds"); parm.bottom = G_define_option(); parm.bottom->key = "b"; parm.bottom->key_desc = "value"; parm.bottom->required = NO; parm.bottom->multiple = NO; parm.bottom->type = TYPE_STRING; parm.bottom->description = _("Value for the bottom edge"); parm.bottom->guisection = _("Bounds"); parm.rows = G_define_option(); parm.rows->key = "rows"; parm.rows->key_desc = "value"; parm.rows->required = NO; parm.rows->multiple = NO; parm.rows->type = TYPE_INTEGER; parm.rows->description = _("Number of rows in the new region"); parm.rows->guisection = _("Resolution"); parm.cols = G_define_option(); parm.cols->key = "cols"; parm.cols->key_desc = "value"; parm.cols->required = NO; parm.cols->multiple = NO; parm.cols->type = TYPE_INTEGER; parm.cols->description = _("Number of columns in the new region"); parm.cols->guisection = _("Resolution"); parm.res = G_define_option(); parm.res->key = "res"; parm.res->key_desc = "value"; parm.res->required = NO; parm.res->multiple = NO; parm.res->type = TYPE_STRING; parm.res->description = _("2D grid resolution (north-south and east-west)"); parm.res->guisection = _("Resolution"); parm.res3 = G_define_option(); parm.res3->key = "res3"; parm.res3->key_desc = "value"; parm.res3->required = NO; parm.res3->multiple = NO; parm.res3->type = TYPE_STRING; parm.res3->description = _("3D grid resolution (north-south, east-west and top-bottom)"); parm.res3->guisection = _("Resolution"); parm.nsres = G_define_option(); parm.nsres->key = "nsres"; parm.nsres->key_desc = "value"; parm.nsres->required = NO; parm.nsres->multiple = NO; parm.nsres->type = TYPE_STRING; parm.nsres->description = _("North-south 2D grid resolution"); parm.nsres->guisection = _("Resolution"); parm.ewres = G_define_option(); parm.ewres->key = "ewres"; parm.ewres->key_desc = "value"; parm.ewres->required = NO; parm.ewres->multiple = NO; parm.ewres->type = TYPE_STRING; parm.ewres->description = _("East-west 2D grid resolution"); parm.ewres->guisection = _("Resolution"); parm.tbres = G_define_option(); parm.tbres->key = "tbres"; parm.tbres->key_desc = "value"; parm.tbres->required = NO; parm.tbres->multiple = NO; parm.tbres->type = TYPE_STRING; parm.tbres->description = _("Top-bottom 3D grid resolution"); parm.tbres->guisection = _("Resolution"); parm.zoom = G_define_option(); parm.zoom->key = "zoom"; parm.zoom->key_desc = "name"; parm.zoom->required = NO; parm.zoom->multiple = NO; parm.zoom->type = TYPE_STRING; parm.zoom->description = _("Shrink region until it meets non-NULL data from this raster map"); parm.zoom->gisprompt = "old,cell,raster"; parm.zoom->guisection = _("Bounds"); parm.align = G_define_option(); parm.align->key = "align"; parm.align->key_desc = "name"; parm.align->required = NO; parm.align->multiple = NO; parm.align->type = TYPE_STRING; parm.align->description = _("Adjust region cells to cleanly align with this raster map"); parm.align->gisprompt = "old,cell,raster"; parm.align->guisection = _("Bounds"); parm.save = G_define_option(); parm.save->key = "save"; parm.save->key_desc = "name"; parm.save->required = NO; parm.save->multiple = NO; parm.save->type = TYPE_STRING; parm.save->description = _("Save current region settings in named region file"); parm.save->gisprompt = "new,windows,region"; parm.save->guisection = _("Effects"); G_option_required(flag.dflt, flag.savedefault, flag.print, flag.lprint, flag.eprint, flag.center, flag.gmt_style, flag.wms_style, flag.dist_res, flag.nangle, flag. z, flag.bbox, flag.gprint, flag.res_set, flag.update, parm.region, parm.raster, parm.raster3d, parm.vect, parm.north, parm.south, parm.east, parm.west, parm.top, parm.bottom, parm.rows, parm.cols, parm.res, parm.res3, parm.nsres, parm.ewres, parm.tbres, parm.zoom, parm.align, parm.save, NULL); if (G_parser(argc, argv)) exit(EXIT_FAILURE); G_get_default_window(&window); set_flag = !flag.update->answer; flat_flag = flag.flprint->answer; if (flag.print->answer) print_flag |= PRINT_REG; if (flag.gprint->answer) print_flag |= PRINT_SH; if (flag.lprint->answer) print_flag |= PRINT_LL; if (flag.eprint->answer) print_flag |= PRINT_EXTENT; if (flag.center->answer) print_flag |= PRINT_CENTER; if (flag.gmt_style->answer) print_flag |= PRINT_GMT; if (flag.wms_style->answer) print_flag |= PRINT_WMS; if (flag.nangle->answer) print_flag |= PRINT_NANGLE; if (flag.dist_res->answer) print_flag |= PRINT_METERS; if (flag.z->answer) print_flag |= PRINT_3D; if (flag.bbox->answer) print_flag |= PRINT_MBBOX; if (print_flag == PRINT_METERS) print_flag |= PRINT_SH; if (print_flag == PRINT_SH || print_flag & PRINT_3D || print_flag == PRINT_METERS + PRINT_SH) { print_flag |= PRINT_REG; } if (!flag.dflt->answer) G_get_window(&window); /* region= */ if ((name = parm.region->answer)) { mapset = G_find_file2("windows", name, ""); if (!mapset) G_fatal_error(_("Region <%s> not found"), name); G_get_element_window(&window, "windows", name, mapset); } /* raster= */ if (parm.raster->answer) { int first = 0; rast_ptr = parm.raster->answers; for (; *rast_ptr != NULL; rast_ptr++) { char rast_name[GNAME_MAX]; strcpy(rast_name, *rast_ptr); mapset = G_find_raster2(rast_name, ""); if (!mapset) G_fatal_error(_("Raster map <%s> not found"), rast_name); Rast_get_cellhd(rast_name, mapset, &temp_window); if (!first) { window = temp_window; first = 1; } else { window.north = (window.north > temp_window.north) ? window.north : temp_window.north; window.south = (window.south < temp_window.south) ? window.south : temp_window.south; window.east = (window.east > temp_window.east) ? window.east : temp_window.east; window.west = (window.west < temp_window.west) ? window.west : temp_window.west; } } G_adjust_Cell_head3(&window, 0, 0, 0); } /* raster3d= */ if ((name = parm.raster3d->answer)) { RASTER3D_Region win; if ((mapset = G_find_raster3d(name, "")) == NULL) G_fatal_error(_("3D raster map <%s> not found"), name); if (Rast3d_read_region_map(name, mapset, &win) < 0) G_fatal_error(_("Unable to read header of 3D raster map <%s@%s>"), name, mapset); Rast3d_region_to_cell_head(&win, &window); } /* vector= */ if (parm.vect->answer) { int first = 0; vect_ptr = parm.vect->answers; for (; *vect_ptr != NULL; vect_ptr++) { struct Map_info Map; struct bound_box box; char vect_name[GNAME_MAX]; struct Cell_head map_window; strcpy(vect_name, *vect_ptr); mapset = G_find_vector2(vect_name, ""); if (!mapset) G_fatal_error(_("Vector map <%s> not found"), vect_name); temp_window = window; Vect_set_open_level(2); if (2 > Vect_open_old_head(&Map, vect_name, mapset)) G_fatal_error(_("Unable to open vector map <%s> on topological level"), vect_name); Vect_get_map_box(&Map, &box); map_window = window; map_window.north = box.N; map_window.south = box.S; map_window.west = box.W; map_window.east = box.E; map_window.top = box.T; map_window.bottom = box.B; if (!first) { window = map_window; first = 1; } else { window.north = (window.north > map_window.north) ? window.north : map_window.north; window.south = (window.south < map_window.south) ? window.south : map_window.south; window.east = (window.east > map_window.east) ? window.east : map_window.east; window.west = (window.west < map_window.west) ? window.west : map_window.west; if (map_window.top > window.top) window.top = map_window.top; if (map_window.bottom < window.bottom) window.bottom = map_window.bottom; } if (window.north == window.south) { window.north = window.north + 0.5 * temp_window.ns_res; window.south = window.south - 0.5 * temp_window.ns_res; } if (window.east == window.west) { window.west = window.west - 0.5 * temp_window.ew_res; window.east = window.east + 0.5 * temp_window.ew_res; } if (window.top == window.bottom) { window.bottom = (window.bottom - 0.5 * temp_window.tb_res); window.top = (window.top + 0.5 * temp_window.tb_res); } if (flag.res_set->answer) Rast_align_window(&window, &temp_window); Vect_close(&Map); } } /* n= */ if ((value = parm.north->answer)) { if ((i = nsew(value, "n+", "n-", "s+"))) { if (!G_scan_resolution(value + 2, &x, window.proj)) die(parm.north); switch (i) { case 1: window.north += x; break; case 2: window.north -= x; break; case 3: window.north = window.south + x; break; } } else if (G_scan_northing(value, &x, window.proj)) window.north = x; else die(parm.north); } /* s= */ if ((value = parm.south->answer)) { if ((i = nsew(value, "s+", "s-", "n-"))) { if (!G_scan_resolution(value + 2, &x, window.proj)) die(parm.south); switch (i) { case 1: window.south += x; break; case 2: window.south -= x; break; case 3: window.south = window.north - x; break; } } else if (G_scan_northing(value, &x, window.proj)) window.south = x; else die(parm.south); } /* e= */ if ((value = parm.east->answer)) { if ((i = nsew(value, "e+", "e-", "w+"))) { if (!G_scan_resolution(value + 2, &x, window.proj)) die(parm.east); switch (i) { case 1: window.east += x; break; case 2: window.east -= x; break; case 3: window.east = window.west + x; break; } } else if (G_scan_easting(value, &x, window.proj)) window.east = x; else die(parm.east); } /* w= */ if ((value = parm.west->answer)) { if ((i = nsew(value, "w+", "w-", "e-"))) { if (!G_scan_resolution(value + 2, &x, window.proj)) die(parm.west); switch (i) { case 1: window.west += x; break; case 2: window.west -= x; break; case 3: window.west = window.east - x; break; } } else if (G_scan_easting(value, &x, window.proj)) window.west = x; else die(parm.west); } /* t= */ if ((value = parm.top->answer)) { if ((i = nsew(value, "t+", "t-", "b+"))) { if (sscanf(value + 2, "%lf", &x) != 1) die(parm.top); switch (i) { case 1: window.top += x; break; case 2: window.top -= x; break; case 3: window.top = window.bottom + x; break; } } else if (sscanf(value, "%lf", &x) == 1) window.top = x; else die(parm.top); } /* b= */ if ((value = parm.bottom->answer)) { if ((i = nsew(value, "b+", "b-", "t-"))) { if (sscanf(value + 2, "%lf", &x) != 1) die(parm.bottom); switch (i) { case 1: window.bottom += x; break; case 2: window.bottom -= x; break; case 3: window.bottom = window.top - x; break; } } else if (sscanf(value, "%lf", &x) == 1) window.bottom = x; else die(parm.bottom); } /* res= */ if ((value = parm.res->answer)) { if (!G_scan_resolution(value, &x, window.proj)) die(parm.res); window.ns_res = x; window.ew_res = x; if (flag.res_set->answer) { window.north = ceil(window.north / x) * x; window.south = floor(window.south / x) * x; window.east = ceil(window.east / x) * x; window.west = floor(window.west / x) * x; } } /* res3= */ if ((value = parm.res3->answer)) { if (!G_scan_resolution(value, &x, window.proj)) die(parm.res); window.ns_res3 = x; window.ew_res3 = x; window.tb_res = x; } /* nsres= */ if ((value = parm.nsres->answer)) { if (!G_scan_resolution(value, &x, window.proj)) die(parm.nsres); window.ns_res = x; if (flag.res_set->answer) { window.north = ceil(window.north / x) * x; window.south = floor(window.south / x) * x; } } /* ewres= */ if ((value = parm.ewres->answer)) { if (!G_scan_resolution(value, &x, window.proj)) die(parm.ewres); window.ew_res = x; if (flag.res_set->answer) { window.east = ceil(window.east / x) * x; window.west = floor(window.west / x) * x; } } /* tbres= */ if ((value = parm.tbres->answer)) { if (sscanf(value, "%lf", &x) != 1) die(parm.tbres); window.tb_res = x; if (flag.res_set->answer) { window.top = ceil(window.top / x) * x; window.bottom = floor(window.bottom / x) * x; } } /* rows= */ if ((value = parm.rows->answer)) { if (sscanf(value, "%i", &ival) != 1) die(parm.rows); window.rows = ival; row_flag = 1; } /* cols= */ if ((value = parm.cols->answer)) { if (sscanf(value, "%i", &ival) != 1) die(parm.cols); window.cols = ival; col_flag = 1; } /* zoom= */ if ((name = parm.zoom->answer)) { mapset = G_find_raster2(name, ""); if (!mapset) G_fatal_error(_("Raster map <%s> not found"), name); zoom(&window, name, mapset); } /* align= */ if ((name = parm.align->answer)) { mapset = G_find_raster2(name, ""); if (!mapset) G_fatal_error(_("Raster map <%s> not found"), name); Rast_get_cellhd(name, mapset, &temp_window); Rast_align_window(&window, &temp_window); } /* save= */ if ((name = parm.save->answer)) { temp_window = window; G_adjust_Cell_head3(&temp_window, 0, 0, 0); if (G_put_element_window(&temp_window, "windows", name) < 0) G_fatal_error(_("Unable to set region <%s>"), name); } G_adjust_Cell_head3(&window, row_flag, col_flag, 0); if (set_flag) { if (G_put_window(&window) < 0) G_fatal_error(_("Unable to update current region")); } if (flag.savedefault->answer) { if (strcmp(G_mapset(), "PERMANENT") == 0) { G_put_element_window(&window, "", "DEFAULT_WIND"); } else { G_fatal_error(_("Unable to change default region. " "The current mapset is not <PERMANENT>.")); } } /* / flag.savedefault->answer */ if (print_flag) print_window(&window, print_flag, flat_flag); 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); }
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 *voutput_opt, *routput_opt, *color_output_opt, *ply_opt, *zrange_opt, *trim_opt, *rotate_Z_opt, *smooth_radius_opt, *region_opt, *raster_opt, *zexag_opt, *resolution_opt, *method_opt, *calib_matrix_opt, *numscan_opt, *trim_tolerance_opt, *contours_map, *contours_step_opt, *draw_opt, *draw_vector_opt, *draw_threshold_opt; struct Flag *loop_flag, *calib_flag, *equalize_flag; struct Map_info Map; struct line_pnts *Points; struct line_cats *Cats; int cat = 1; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("scan")); G_add_keyword(_("points")); module->label = _("Imports a point cloud from Kinect v2"); module->description = _("Imports a point cloud from Kinect v2"); routput_opt = G_define_standard_option(G_OPT_R_OUTPUT); routput_opt->guisection = _("Output"); routput_opt->required = NO; resolution_opt = G_define_option(); resolution_opt->key = "resolution"; resolution_opt->type = TYPE_DOUBLE; resolution_opt->required = NO; resolution_opt->answer = "0.002"; resolution_opt->label = _("Raster resolution"); resolution_opt->description = _("Recommended values between 0.001-0.003"); resolution_opt->guisection = _("Output"); color_output_opt = G_define_standard_option(G_OPT_R_BASENAME_OUTPUT); color_output_opt->key = "color_output"; color_output_opt->description = _("Basename for color output"); color_output_opt->guisection = _("Output"); color_output_opt->required = NO; voutput_opt = G_define_standard_option(G_OPT_V_OUTPUT); voutput_opt->required = NO; voutput_opt->key = "vector"; voutput_opt->guisection = _("Output"); ply_opt = G_define_standard_option(G_OPT_F_OUTPUT); ply_opt->required = NO; ply_opt->key = "ply"; ply_opt->description = _("Name of output binary PLY file"); ply_opt->guisection = _("Output"); 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->label = _("Filter range for z data (min,max)"); zrange_opt->description = _("Z is distance from scanner in cm"); zrange_opt->guisection = _("Filter"); trim_opt = G_define_option(); trim_opt->key = "trim"; trim_opt->type = TYPE_DOUBLE; trim_opt->required = NO; trim_opt->key_desc = "N,S,E,W"; trim_opt->description = _("Clip box from center in cm"); trim_opt->guisection = _("Filter"); trim_tolerance_opt = G_define_option(); trim_tolerance_opt->key = "trim_tolerance"; trim_tolerance_opt->type = TYPE_DOUBLE; trim_tolerance_opt->required = NO; trim_tolerance_opt->description = _("Influences how much are model sides trimmed automatically, " " should be higher for rectangular models"); trim_tolerance_opt->label = _("Trim tolerance between 0 and 1"); trim_tolerance_opt->options = "0-1"; trim_tolerance_opt->guisection = _("Filter"); rotate_Z_opt = G_define_option(); rotate_Z_opt->key = "rotate"; rotate_Z_opt->type = TYPE_DOUBLE; rotate_Z_opt->required = NO; rotate_Z_opt->answer = "0"; rotate_Z_opt->description = _("Rotate along Z axis"); rotate_Z_opt->guisection = _("Georeferencing"); smooth_radius_opt = G_define_option(); smooth_radius_opt->key = "smooth_radius"; smooth_radius_opt->type = TYPE_DOUBLE; smooth_radius_opt->required = NO; smooth_radius_opt->label = _("Smooth radius"); smooth_radius_opt->description = _("Recommended values between 0.006-0.009"); region_opt = G_define_option(); region_opt->key = "region"; region_opt->key_desc = "name"; region_opt->required = NO; region_opt->multiple = NO; region_opt->type = TYPE_STRING; region_opt->description = _("Region of the resulting raster"); region_opt->gisprompt = "old,windows,region"; region_opt->guisection = _("Georeferencing"); raster_opt = G_define_standard_option(G_OPT_R_MAP); raster_opt->key = "raster"; raster_opt->required = NO; raster_opt->multiple = NO; raster_opt->description = _("Match resulting raster to this raster map"); raster_opt->guisection = _("Georeferencing"); zexag_opt = G_define_option(); zexag_opt->key = "zexag"; zexag_opt->type = TYPE_DOUBLE; zexag_opt->required = NO; zexag_opt->required = NO; zexag_opt->answer = "1"; zexag_opt->description = _("Vertical exaggeration"); zexag_opt->guisection = _("Georeferencing"); method_opt = G_define_option(); method_opt->key = "method"; method_opt->multiple = NO; method_opt->required = NO; method_opt->type = TYPE_STRING; method_opt->options = "interpolation,mean,min,max"; method_opt->answer = "mean"; method_opt->description = _("Surface reconstruction method"); calib_matrix_opt = G_define_option(); calib_matrix_opt->key = "calib_matrix"; calib_matrix_opt->multiple = YES; calib_matrix_opt->type = TYPE_DOUBLE; calib_matrix_opt->required = NO; calib_matrix_opt->description = _("Calibration matrix"); calib_matrix_opt->guisection = _("Calibration"); numscan_opt = G_define_option(); numscan_opt->answer = "1"; numscan_opt->key = "numscan"; numscan_opt->type = TYPE_INTEGER; numscan_opt->description = _("Number of scans to intergrate"); numscan_opt->required = NO; contours_map = G_define_standard_option(G_OPT_V_MAP); contours_map->key = "contours"; contours_map->required = NO; contours_map->description = _("Name of contour vector map"); contours_step_opt = G_define_option(); contours_step_opt->key = "contours_step"; contours_step_opt->description = _("Increment between contour levels"); contours_step_opt->type = TYPE_DOUBLE; contours_step_opt->required = NO; equalize_flag = G_define_flag(); equalize_flag->key = 'e'; equalize_flag->description = _("Histogram equalized color table"); loop_flag = G_define_flag(); loop_flag->key = 'l'; loop_flag->description = _("Keep scanning in a loop"); calib_flag = G_define_flag(); calib_flag->key = 'c'; calib_flag->description = _("Calibrate"); calib_flag->guisection = _("Calibration"); draw_opt = G_define_option(); draw_opt->key = "draw"; draw_opt->description = _("Draw with laser pointer"); draw_opt->type = TYPE_STRING; draw_opt->required = NO; draw_opt->options = "point,line,area"; draw_opt->answer = "point"; draw_opt->guisection = _("Drawing"); draw_threshold_opt = G_define_option(); draw_threshold_opt->key = "draw_threshold"; draw_threshold_opt->description = _("Brightness threshold for detecting laser pointer"); draw_threshold_opt->type = TYPE_INTEGER; draw_threshold_opt->required = YES; draw_threshold_opt->answer = "760"; draw_threshold_opt->guisection = _("Drawing"); draw_vector_opt = G_define_standard_option(G_OPT_V_OUTPUT); draw_vector_opt->key = "draw_output"; draw_vector_opt->guisection = _("Drawing"); draw_vector_opt->required = NO; G_option_required(calib_flag, routput_opt, voutput_opt, ply_opt, draw_vector_opt, NULL); G_option_requires(routput_opt, resolution_opt, NULL); G_option_requires(color_output_opt, resolution_opt, NULL); G_option_requires(contours_map, contours_step_opt, routput_opt, NULL); G_option_requires(equalize_flag, routput_opt, NULL); if (G_parser(argc, argv)) exit(EXIT_FAILURE); // initailization of variables double resolution = 0.002; if (resolution_opt->answer) resolution = atof(resolution_opt->answer); double smooth_radius = 0.008; if (smooth_radius_opt->answer) smooth_radius = atof(smooth_radius_opt->answer); char* routput = NULL; if (routput_opt->answer) routput = routput_opt->answer; /* parse zrange */ double zrange_min, zrange_max; if (zrange_opt->answer != NULL) { zrange_min = atof(zrange_opt->answers[0])/100; zrange_max = atof(zrange_opt->answers[1])/100; } /* parse trim */ double clip_N, clip_S, clip_E, clip_W; if (trim_opt->answer != NULL) { clip_N = atof(trim_opt->answers[0])/100; clip_S = atof(trim_opt->answers[1])/100; clip_E = atof(trim_opt->answers[2])/100; clip_W = atof(trim_opt->answers[3])/100; } double trim_tolerance; if (trim_tolerance_opt->answer) trim_tolerance = atof(trim_tolerance_opt->answer); double angle = pcl::deg2rad(atof(rotate_Z_opt->answer) + 180); double zexag = atof(zexag_opt->answer); Eigen::Matrix4f transform_matrix; if (calib_matrix_opt->answer) { transform_matrix = read_matrix(calib_matrix_opt); } char *method = method_opt->answer; int numscan = atoi(numscan_opt->answer); char *color_output = color_output_opt->answer; char *voutput = voutput_opt->answer; char *ply = ply_opt->answer; char *contours_output = contours_map->answer; double contours_step; if (contours_output) contours_step = atof(contours_step_opt->answer); bool use_equalized = false; if (equalize_flag->answer) use_equalized = true; // drawing int vect_type; get_draw_type(draw_opt->answer, vect_type); int draw_threshold = atoi(draw_threshold_opt->answer); char* draw_output = NULL; if (draw_vector_opt->answer) draw_output = draw_vector_opt->answer; std::vector<double> draw_x; std::vector<double> draw_y; std::vector<double> draw_z; bool drawing = false; unsigned int last_detected_loop_count = 1e6; struct Map_info Map_draw; struct line_pnts *Points_draw; struct line_cats *Cats_draw; Points_draw = Vect_new_line_struct(); Cats_draw = Vect_new_cats_struct(); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>(512, 424)); pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered_pass (new pcl::PointCloud<pcl::PointXYZRGB>(512, 424)); struct bound_box bbox; struct Cell_head cellhd, window; double offset, scale; bool region3D = false; bool paused = false; update_input_region(raster_opt->answer, region_opt->answer, window, offset, region3D); K2G k2g(OPENGL); k2g.getCloud(); cloud->sensor_orientation_.w() = 0.0; cloud->sensor_orientation_.x() = 1.0; cloud->sensor_orientation_.y() = 0.0; cloud->sensor_orientation_.z() = 0.0; int j = 0; // get terminating signals signal(SIGTERM, terminate); signal(SIGINT, terminate); signal(SIGUSR1, signal_read_new_input); while (j < 1) { if (signaled == 1) { break; } if (signal_new_input == 1) { signal_new_input = 0; read_new_input(routput, zrange_min, zrange_max, clip_N, clip_S, clip_E, clip_W, trim_tolerance, angle, zexag, method, numscan, smooth_radius, resolution, use_equalized, window, offset, region3D, color_output, voutput, ply, contours_output, contours_step, vect_type, draw_threshold, draw_output, paused); } cloud = k2g.getCloud(); if (paused) { continue; } if (!drawing) { for (int s = 0; s < numscan - 1; s++) *(cloud) += *(k2g.getCloud()); } // remove invalid points std::vector<int> index_nans; pcl::removeNaNFromPointCloud(*cloud, *cloud, index_nans); // calibration if(calib_flag->answer) { calibrate(cloud); j++; continue; } // rotation of the point cloud based on calibration if (calib_matrix_opt->answer) { rotate_with_matrix(cloud, transform_matrix); } // trim Z if (zrange_opt->answer != NULL) { trim_Z(cloud, zrange_min, zrange_max); } // rotation Z rotate_Z(cloud, angle); // specify bounding box from center if (trim_opt->answer != NULL) { clipNSEW(cloud, clip_N, clip_S, clip_E, clip_W); } // drawing if (draw_output) { int maxbright = 0; int maxbright_idx = 0; for (int i=0; i < cloud->points.size(); i++) { Eigen::Vector3i rgbv = cloud->points[i].getRGBVector3i(); int sum = rgbv[0] + rgbv[1] + rgbv[2]; if (sum > maxbright) { maxbright = sum; maxbright_idx = i; } } if (maxbright >= draw_threshold) { drawing = true; draw_x.push_back(cloud->points[maxbright_idx].x); draw_y.push_back(cloud->points[maxbright_idx].y); draw_z.push_back(cloud->points[maxbright_idx].z); last_detected_loop_count = 0; continue; } else { last_detected_loop_count++; if (last_detected_loop_count <= 2) { continue; } } } pcl::StatisticalOutlierRemoval<pcl::PointXYZRGB> sor; sor.setInputCloud(cloud); sor.setMeanK(20); sor.setStddevMulThresh(0.5); sor.filter(*cloud_filtered_pass); cloud_filtered_pass.swap (cloud); if (trim_tolerance_opt->answer != NULL) { double autoclip_N, autoclip_S, autoclip_E, autoclip_W; autotrim(cloud, autoclip_N, autoclip_S, autoclip_E, autoclip_W, trim_tolerance); if (autoclip_E > 0 || autoclip_N > 0 || autoclip_S > 0 || autoclip_W > 0) trimNSEW(cloud, autoclip_N, autoclip_S, autoclip_E, autoclip_W); } if (drawing) { // get Z scaling getMinMax(*cloud, bbox); if ((vect_type == GV_AREA && draw_x.size() > 2) || (vect_type == GV_LINE && draw_x.size() > 1) || (vect_type == GV_POINT && draw_x.size() > 0)) { save_vector(draw_output, Map_draw, Points_draw, Cats_draw, bbox, window, draw_x, draw_y, draw_z, vect_type, offset, zexag); } else G_warning(_("Tolopogically incorrect vector feature")); drawing = false; draw_x.clear(); draw_y.clear(); draw_z.clear(); last_detected_loop_count = 1e6; } if (voutput|| routput || ply || color_output) { if (smooth_radius_opt->answer) smooth(cloud, smooth_radius); // get Z scaling getMinMax(*cloud, bbox); scale = ((window.north - window.south) / (bbox.N - bbox.S) + (window.east - window.west) / (bbox.E - bbox.W)) / 2; } // write to vector if (voutput|| (routput && strcmp(method, "interpolation") == 0)) { double z; if (voutput) { if (Vect_open_new(&Map, voutput, WITH_Z) < 0) G_fatal_error(_("Unable to create temporary vector map <%s>"), voutput); } else { if (Vect_open_tmp_new(&Map, routput, WITH_Z) < 0) G_fatal_error(_("Unable to create temporary vector map <%s>"), routput); } for (int i=0; i < cloud->points.size(); i++) { Vect_reset_line(Points); Vect_reset_cats(Cats); if (region3D) z = (cloud->points[i].z + zrange_max) * scale / zexag + offset; else z = (cloud->points[i].z - bbox.B) * scale / zexag + offset; Vect_append_point(Points, cloud->points[i].x, cloud->points[i].y, z); Vect_cat_set(Cats, 1, cat); Vect_write_line(&Map, GV_POINT, Points, Cats); } if (strcmp(method, "interpolation") == 0) { // interpolate Vect_rewind(&Map); interpolate(&Map, routput, 20, 2, 50, 40, -1, &bbox, resolution); } Vect_close(&Map); } if (routput || color_output) { if (routput) { if (strcmp(method, "interpolation") != 0) { binning(cloud, routput, &bbox, resolution, scale, zexag, region3D ? -zrange_max : bbox.B, offset, method); } Rast_get_cellhd(routput, "", &cellhd); } if (color_output) { binning_color(cloud, color_output, &bbox, resolution); Rast_get_cellhd(get_color_name(color_output, "r"), "", &cellhd); } // georeference horizontally window.rows = cellhd.rows; window.cols = cellhd.cols; G_adjust_Cell_head(&window, 1, 1); cellhd.north = window.north; cellhd.south = window.south; cellhd.east = window.east; cellhd.west = window.west; if (routput) Rast_put_cellhd(routput, &cellhd); if (color_output) { char* output_r = get_color_name(color_output, "r"); char* output_g = get_color_name(color_output, "g"); char* output_b = get_color_name(color_output, "b"); Rast_put_cellhd(output_r, &cellhd); Rast_put_cellhd(output_g, &cellhd); Rast_put_cellhd(output_b, &cellhd); } set_default_color(routput); if (contours_output) { contours(routput, contours_output, atof(contours_step_opt->answer)); } if (use_equalized) { equalized(routput); } } // write to PLY if (ply) { pcl::PLYWriter writer; for (int i=0; i < cloud->points.size(); i++) { if (region3D) cloud->points[i].z = (cloud->points[i].z + zrange_max) * scale / zexag + offset; else cloud->points[i].z = (cloud->points[i].z - bbox.B) * scale / zexag + offset; cloud->points[i].x = (cloud->points[i].x - bbox.W) * scale + window.west; cloud->points[i].y = (cloud->points[i].y - bbox.S) * scale + window.south; } writer.write<pcl::PointXYZRGB>(ply, *cloud, true, true); } if (!loop_flag->answer) j++; } k2g.shutDown(); return EXIT_SUCCESS; }