main.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. /****************************************************************************
  2. *
  3. * MODULE: r3.in.Lidar
  4. *
  5. * AUTHOR(S): Vaclav Petras
  6. *
  7. * PURPOSE: Imports LAS LiDAR point clouds to a 3D raster map using
  8. * aggregate statistics.
  9. *
  10. * COPYRIGHT: (C) 2016 Vaclav Petras and the The GRASS Development Team
  11. *
  12. * This program is free software under the GNU General Public
  13. * License (>=v2). Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. *****************************************************************************/
  17. #include <stdlib.h>
  18. #include <grass/gis.h>
  19. #include <grass/raster3d.h>
  20. #include <grass/glocale.h>
  21. #include <liblas/capi/liblas.h>
  22. #include "info.h"
  23. #include "string_list.h"
  24. #include "projection.h"
  25. #include "rast_segment.h"
  26. #include "filters.h"
  27. struct PointBinning3D
  28. {
  29. RASTER3D_Region region, flat_region;
  30. RASTER3D_Map *count_raster, *sum_raster, *mean_raster;
  31. RASTER3D_Map *count_flat_raster, *sum_flat_raster;
  32. RASTER3D_Map *prop_count_raster, *prop_sum_raster;
  33. };
  34. /* TODO: do this in some more efficient way, perhaps function in the lib */
  35. static void raster3d_set_value_float(RASTER3D_Map * raster,
  36. RASTER3D_Region * region, float value)
  37. {
  38. int col, row, depth;
  39. for (depth = 0; depth < region->depths; depth++)
  40. for (row = 0; row < region->rows; row++)
  41. for (col = 0; col < region->cols; col++)
  42. Rast3d_put_float(raster, col, row, depth, value);
  43. }
  44. /* c = a / b */
  45. static void raster3d_divide(RASTER3D_Map * a, RASTER3D_Map * b,
  46. RASTER3D_Map * c, RASTER3D_Region * region)
  47. {
  48. int col, row, depth;
  49. double tmp;
  50. G_percent_reset();
  51. for (depth = 0; depth < region->depths; depth++) {
  52. G_percent(depth, region->depths, 5);
  53. for (row = 0; row < region->rows; row++) {
  54. for (col = 0; col < region->cols; col++) {
  55. tmp = Rast3d_get_double(b, col, row, 0);
  56. /* TODO: compare to epsilon */
  57. if (tmp > 0) {
  58. tmp = Rast3d_get_double(a, col, row, depth) / tmp;
  59. Rast3d_put_double(c, col, row, depth, tmp);
  60. }
  61. else {
  62. /* TODO: check this implementation */
  63. Rast3d_set_null_value(&tmp, 1, DCELL_TYPE);
  64. Rast3d_put_double(c, col, row, depth, tmp);
  65. }
  66. }
  67. }
  68. }
  69. G_percent(1, 1, 1); /* flush */
  70. }
  71. /* c = a / b where b has depth 1 */
  72. static void raster3d_divide_by_flat(RASTER3D_Map * a, RASTER3D_Map * b,
  73. RASTER3D_Map * c,
  74. RASTER3D_Region * region)
  75. {
  76. int col, row, depth;
  77. double tmp;
  78. G_percent_reset();
  79. for (depth = 0; depth < region->depths; depth++) {
  80. G_percent(depth, region->depths, 5);
  81. for (row = 0; row < region->rows; row++) {
  82. for (col = 0; col < region->cols; col++) {
  83. tmp = Rast3d_get_double(b, col, row, 0);
  84. /* since it is count, using cast to integer to check
  85. againts zero, limits the value to max of CELL */
  86. if (((CELL) tmp) > 0) {
  87. tmp = Rast3d_get_double(a, col, row, depth) / tmp;
  88. Rast3d_put_double(c, col, row, depth, tmp);
  89. }
  90. else {
  91. /* TODO: check this implementation */
  92. Rast3d_set_null_value(&tmp, 1, DCELL_TYPE);
  93. Rast3d_put_double(c, col, row, depth, tmp);
  94. }
  95. }
  96. }
  97. }
  98. G_percent(1, 1, 1); /* flush */
  99. }
  100. /* initialize raster pointers */
  101. void binning_init(struct PointBinning3D *binning)
  102. {
  103. binning->count_raster = binning->sum_raster = binning->mean_raster = NULL;
  104. binning->count_flat_raster = binning->sum_flat_raster = NULL;
  105. binning->prop_count_raster = binning->prop_sum_raster = NULL;
  106. }
  107. void binning_add_point(struct PointBinning3D *binning, int row, int col,
  108. int depth, double value)
  109. {
  110. double tmp; /* TODO: check if these should be in binning struct */
  111. if (binning->count_raster) {
  112. tmp = Rast3d_get_double(binning->count_raster, col, row, depth);
  113. Rast3d_put_double(binning->count_raster, col, row, depth, tmp + 1);
  114. }
  115. if (binning->count_flat_raster) {
  116. tmp = Rast3d_get_double(binning->count_flat_raster, col, row, 0);
  117. Rast3d_put_double(binning->count_flat_raster, col, row, 0, tmp + 1);
  118. }
  119. if (binning->sum_raster) {
  120. tmp = Rast3d_get_double(binning->sum_raster, col, row, depth);
  121. Rast3d_put_double(binning->sum_raster, col, row, depth, tmp + value);
  122. }
  123. if (binning->sum_flat_raster) {
  124. tmp = Rast3d_get_double(binning->sum_flat_raster, col, row, 0);
  125. Rast3d_put_double(binning->sum_flat_raster, col, row, 0, tmp + value);
  126. }
  127. }
  128. int main(int argc, char *argv[])
  129. {
  130. struct GModule *module;
  131. struct Option *input_opt;
  132. struct Option *file_list_opt;
  133. struct Option *count_output_opt, *sum_output_opt, *mean_output_opt;
  134. struct Option *prop_count_output_opt, *prop_sum_output_opt;
  135. struct Option *filter_opt, *class_opt;
  136. struct Option *zscale_opt;
  137. struct Option *iscale_opt;
  138. struct Option *irange_opt;
  139. struct Option *base_raster_opt;
  140. struct Flag *base_rast_res_flag;
  141. struct Flag *only_valid_flag;
  142. struct Flag *print_flag, *scan_flag, *shell_style;
  143. struct Flag *over_flag;
  144. G_gisinit(argv[0]);
  145. module = G_define_module();
  146. G_add_keyword(_("raster3d"));
  147. G_add_keyword(_("import"));
  148. G_add_keyword(_("LIDAR"));
  149. G_add_keyword(_("statistics"));
  150. G_add_keyword(_("conversion"));
  151. G_add_keyword(_("aggregation"));
  152. G_add_keyword(_("binning"));
  153. module->description =
  154. _("Creates a 3D raster map from LAS LiDAR points using univariate statistics.");
  155. input_opt = G_define_standard_option(G_OPT_F_BIN_INPUT);
  156. input_opt->required = NO;
  157. input_opt->label = _("LAS input file");
  158. input_opt->description =
  159. _("LiDAR input file in LAS format (*.las or *.laz)");
  160. input_opt->guisection = _("Input");
  161. file_list_opt = G_define_standard_option(G_OPT_F_INPUT);
  162. file_list_opt->key = "file";
  163. file_list_opt->label = _("File containing names of LAS input files");
  164. file_list_opt->description = _("LiDAR input files in LAS format (*.las or *.laz)");
  165. file_list_opt->required = NO;
  166. file_list_opt->guisection = _("Input");
  167. count_output_opt = G_define_standard_option(G_OPT_R3_OUTPUT);
  168. count_output_opt->key = "n";
  169. count_output_opt->required = NO;
  170. count_output_opt->label = _("Count of points per cell");
  171. count_output_opt->guisection = _("Output");
  172. sum_output_opt = G_define_standard_option(G_OPT_R3_OUTPUT);
  173. sum_output_opt->key = "sum";
  174. sum_output_opt->required = NO;
  175. sum_output_opt->label = _("Sum of values of point intensities per cell");
  176. sum_output_opt->guisection = _("Output");
  177. mean_output_opt = G_define_standard_option(G_OPT_R3_OUTPUT);
  178. mean_output_opt->key = "mean";
  179. mean_output_opt->required = NO;
  180. mean_output_opt->label = _("Mean of point intensities per cell");
  181. mean_output_opt->guisection = _("Output");
  182. /* TODO: proportional versus relative in naming */
  183. prop_count_output_opt = G_define_standard_option(G_OPT_R3_OUTPUT);
  184. prop_count_output_opt->key = "proportional_n";
  185. prop_count_output_opt->required = NO;
  186. prop_count_output_opt->label =
  187. _("3D raster map of proportional point count");
  188. prop_count_output_opt->description =
  189. _("Point count per 3D cell divided by point count per vertical"
  190. " column");
  191. prop_count_output_opt->guisection = _("Proportional output");
  192. prop_sum_output_opt = G_define_standard_option(G_OPT_R3_OUTPUT);
  193. prop_sum_output_opt->key = "proportional_sum";
  194. prop_sum_output_opt->required = NO;
  195. prop_sum_output_opt->label =
  196. _("3D raster map of proportional sum of values");
  197. prop_sum_output_opt->description =
  198. _("Sum of values per 3D cell divided by sum of values per"
  199. " vertical column");
  200. prop_sum_output_opt->guisection = _("Proportional output");
  201. filter_opt = G_define_option();
  202. filter_opt->key = "return_filter";
  203. filter_opt->type = TYPE_STRING;
  204. filter_opt->required = NO;
  205. filter_opt->label = _("Only import points of selected return type");
  206. filter_opt->description = _("If not specified, all points are imported");
  207. filter_opt->options = "first,last,mid";
  208. filter_opt->guisection = _("Selection");
  209. class_opt = G_define_option();
  210. class_opt->key = "class_filter";
  211. class_opt->type = TYPE_INTEGER;
  212. class_opt->multiple = YES;
  213. class_opt->required = NO;
  214. class_opt->label = _("Only import points of selected class(es)");
  215. class_opt->description = _("Input is comma separated integers. "
  216. "If not specified, all points are imported.");
  217. class_opt->guisection = _("Selection");
  218. base_raster_opt = G_define_standard_option(G_OPT_R_INPUT);
  219. base_raster_opt->key = "base_raster";
  220. base_raster_opt->required = NO;
  221. base_raster_opt->label =
  222. _("Subtract raster values from the z coordinates");
  223. base_raster_opt->description =
  224. _("The scale for z is applied beforehand, the filter afterwards");
  225. base_raster_opt->guisection = _("Transform");
  226. base_rast_res_flag = G_define_flag();
  227. base_rast_res_flag->key = 'd';
  228. base_rast_res_flag->description =
  229. _("Use base raster actual resolution instead of computational region");
  230. zscale_opt = G_define_option();
  231. zscale_opt->key = "zscale";
  232. zscale_opt->type = TYPE_DOUBLE;
  233. zscale_opt->required = NO;
  234. zscale_opt->answer = "1.0";
  235. zscale_opt->description = _("Scale to apply to Z data");
  236. zscale_opt->guisection = _("Transform");
  237. irange_opt = G_define_option();
  238. irange_opt->key = "intensity_range";
  239. irange_opt->type = TYPE_DOUBLE;
  240. irange_opt->required = NO;
  241. irange_opt->key_desc = "min,max";
  242. irange_opt->description = _("Filter range for intensity values (min,max)");
  243. irange_opt->guisection = _("Selection");
  244. iscale_opt = G_define_option();
  245. iscale_opt->key = "intensity_scale";
  246. iscale_opt->type = TYPE_DOUBLE;
  247. iscale_opt->required = NO;
  248. iscale_opt->answer = "1.0";
  249. iscale_opt->description = _("Scale to apply to intensity values");
  250. iscale_opt->guisection = _("Transform");
  251. only_valid_flag = G_define_flag();
  252. only_valid_flag->key = 'v';
  253. only_valid_flag->label = _("Use only valid points");
  254. only_valid_flag->description =
  255. _("Points invalid according to APSRS LAS specification will be"
  256. " filtered out");
  257. only_valid_flag->guisection = _("Selection");
  258. over_flag = G_define_flag();
  259. over_flag->key = 'o';
  260. over_flag->label =
  261. _("Override projection check (use current location's projection)");
  262. over_flag->description =
  263. _("Assume that the dataset has same projection as the current location");
  264. print_flag = G_define_flag();
  265. print_flag->key = 'p';
  266. print_flag->description = _("Print LAS file info and exit");
  267. scan_flag = G_define_flag();
  268. scan_flag->key = 's';
  269. scan_flag->description = _("Scan data file for extent then exit");
  270. shell_style = G_define_flag();
  271. shell_style->key = 'g';
  272. shell_style->description = _("In scan mode, print using shell script style");
  273. G_option_required(input_opt, file_list_opt, NULL);
  274. G_option_exclusive(input_opt, file_list_opt, NULL);
  275. G_option_required(count_output_opt, sum_output_opt, mean_output_opt,
  276. prop_count_output_opt, prop_sum_output_opt,
  277. print_flag, scan_flag, shell_style, NULL);
  278. G_option_requires(base_rast_res_flag, base_raster_opt, NULL);
  279. G_option_requires_all(mean_output_opt, count_output_opt, sum_output_opt, NULL);
  280. G_option_requires_all(prop_count_output_opt, count_output_opt, NULL);
  281. G_option_requires_all(prop_sum_output_opt, sum_output_opt, NULL);
  282. if (G_parser(argc, argv))
  283. exit(EXIT_FAILURE);
  284. if (shell_style->answer && !scan_flag->answer) {
  285. scan_flag->answer = TRUE;
  286. }
  287. /* check intensity range and extent relation */
  288. if (scan_flag->answer) {
  289. if (irange_opt->answer)
  290. G_warning(_("%s will not be taken into account during scan"), irange_opt->key);
  291. }
  292. int only_valid = FALSE;
  293. if (only_valid_flag->answer)
  294. only_valid = TRUE;
  295. struct StringList infiles;
  296. if (file_list_opt->answer) {
  297. if (access(file_list_opt->answer, F_OK) != 0)
  298. G_fatal_error(_("File <%s> does not exist"), file_list_opt->answer);
  299. string_list_from_file(&infiles, file_list_opt->answer);
  300. }
  301. else {
  302. string_list_from_one_item(&infiles, input_opt->answer);
  303. }
  304. double zscale = 1.0;
  305. double iscale = 1.0;
  306. if (zscale_opt->answer)
  307. zscale = atof(zscale_opt->answer);
  308. if (iscale_opt->answer)
  309. iscale = atof(iscale_opt->answer);
  310. LASReaderH LAS_reader;
  311. LASHeaderH LAS_header;
  312. LASSRSH LAS_srs;
  313. char *infile;
  314. /* for the CRS info */
  315. const char *projstr;
  316. struct Cell_head current_region;
  317. struct Cell_head file_region;
  318. G_get_set_window(&current_region);
  319. /* extent for all data */
  320. struct Cell_head data_region;
  321. long unsigned header_count = 0;
  322. int i;
  323. for (i = 0; i < infiles.num_items; i++) {
  324. infile = infiles.items[i];
  325. /* don't if file not found */
  326. if (access(infile, F_OK) != 0)
  327. G_fatal_error(_("Input file <%s> does not exist"), infile);
  328. /* Open LAS file*/
  329. LAS_reader = LASReader_Create(infile);
  330. if (LAS_reader == NULL)
  331. G_fatal_error(_("Unable to open file <%s> as a LiDAR point cloud"),
  332. infile);
  333. LAS_header = LASReader_GetHeader(LAS_reader);
  334. if (LAS_header == NULL) {
  335. G_fatal_error(_("Unable to read LAS header of <%s>"), infile);
  336. }
  337. LAS_srs = LASHeader_GetSRS(LAS_header);
  338. /* print info or check projection if we are actually importing */
  339. if (print_flag->answer) {
  340. /* print filename when there is more than one file */
  341. if (infiles.num_items > 1)
  342. fprintf(stdout, "File: %s\n", infile);
  343. /* Print LAS header */
  344. print_lasinfo(LAS_header, LAS_srs);
  345. }
  346. else {
  347. /* report that we are checking more files */
  348. if (i == 1)
  349. G_message(_("First file's projection checked,"
  350. " checking projection of the other files..."));
  351. /* Fetch input map projection in GRASS form. */
  352. projstr = LASSRS_GetWKT_CompoundOK(LAS_srs);
  353. /* we are printing the non-warning messages only for first file */
  354. projection_check_wkt(file_region, current_region, projstr,
  355. over_flag->answer, shell_style->answer || i);
  356. /* if there is a problem in some other file, first OK message
  357. * is printed but than a warning, this is not ideal but hopefully
  358. * not so confusing when importing multiple files */
  359. }
  360. if (scan_flag->answer) {
  361. /* we assign to the first one (i==0) but update for the rest */
  362. scan_bounds(LAS_reader, shell_style->answer, FALSE, i,
  363. zscale, &data_region);
  364. }
  365. /* number of estimated point across all files */
  366. /* TODO: this should be ull which won't work with percent report */
  367. header_count += LASHeader_GetPointRecordsCount(LAS_header);
  368. /* We are closing all again and we will be opening them later,
  369. * so we don't have to worry about limit for open files. */
  370. LASSRS_Destroy(LAS_srs);
  371. LASHeader_Destroy(LAS_header);
  372. LASReader_Destroy(LAS_reader);
  373. }
  374. /* if we are not importing, end */
  375. if (print_flag->answer || scan_flag->answer)
  376. exit(EXIT_SUCCESS);
  377. Rast3d_init_defaults();
  378. Rast3d_set_error_fun(Rast3d_fatal_error_noargs);
  379. double irange_min;
  380. double irange_max;
  381. int use_irange =
  382. range_filter_from_option(irange_opt, &irange_min, &irange_max);
  383. struct ReturnFilter return_filter_struct;
  384. int use_return_filter =
  385. return_filter_create_from_string(&return_filter_struct,
  386. filter_opt->answer);
  387. struct ClassFilter class_filter;
  388. int use_class_filter =
  389. class_filter_create_from_strings(&class_filter, class_opt->answers);
  390. /* TODO: rename */
  391. struct Cell_head input_region;
  392. SEGMENT base_segment;
  393. RASTER_MAP_TYPE base_raster_data_type;
  394. int use_segment = FALSE;
  395. int use_base_raster_res = FALSE;
  396. if (base_rast_res_flag->answer)
  397. use_base_raster_res = TRUE;
  398. if (base_raster_opt->answer) {
  399. use_segment = TRUE;
  400. if (use_base_raster_res) {
  401. /* read raster's actual extent and resolution */
  402. Rast_get_cellhd(base_raster_opt->answer, "", &input_region);
  403. /* TODO: make it only as small as the output */
  404. Rast_set_input_window(&input_region); /* we use split window */
  405. }
  406. else {
  407. Rast_get_input_window(&input_region);
  408. }
  409. rast_segment_open(&base_segment, base_raster_opt->answer,
  410. &base_raster_data_type);
  411. }
  412. struct PointBinning3D binning;
  413. int cache = RASTER3D_USE_CACHE_DEFAULT;
  414. int type = FCELL_TYPE;
  415. int max_tile_size = 32;
  416. binning_init(&binning);
  417. /* TODO: this should probably happen before we change 2D region just to be sure */
  418. Rast3d_get_window(&binning.region);
  419. Rast3d_get_window(&binning.flat_region);
  420. binning.flat_region.depths = 1;
  421. Rast3d_adjust_region(&binning.flat_region);
  422. if (count_output_opt->answer) {
  423. binning.count_raster =
  424. Rast3d_open_new_opt_tile_size(count_output_opt->answer, cache,
  425. &binning.region, type, max_tile_size);
  426. if (!binning.count_raster)
  427. Rast3d_fatal_error(_("Unable to create 3D raster map <%s>"),
  428. count_output_opt->answer);
  429. }
  430. if (sum_output_opt->answer) {
  431. binning.sum_raster =
  432. Rast3d_open_new_opt_tile_size(sum_output_opt->answer, cache,
  433. &binning.region, type,
  434. max_tile_size);
  435. if (!binning.sum_raster)
  436. Rast3d_fatal_error(_("Unable to create 3D raster map <%s>"),
  437. sum_output_opt->answer);
  438. }
  439. if (mean_output_opt->answer) {
  440. binning.mean_raster =
  441. Rast3d_open_new_opt_tile_size(mean_output_opt->answer, cache,
  442. &binning.region, type, max_tile_size);
  443. if (!binning.mean_raster)
  444. Rast3d_fatal_error(_("Unable to create 3D raster map <%s>"),
  445. mean_output_opt->answer);
  446. }
  447. if (prop_count_output_opt->answer) {
  448. binning.prop_count_raster =
  449. Rast3d_open_new_opt_tile_size(prop_count_output_opt->answer, cache,
  450. &binning.region, type, max_tile_size);
  451. if (!binning.prop_count_raster)
  452. Rast3d_fatal_error(_("Unable to create 3D raster map <%s>"),
  453. prop_count_output_opt->answer);
  454. }
  455. if (prop_sum_output_opt->answer) {
  456. binning.prop_sum_raster =
  457. Rast3d_open_new_opt_tile_size(prop_sum_output_opt->answer, cache,
  458. &binning.region, type, max_tile_size);
  459. if (!binning.prop_sum_raster)
  460. Rast3d_fatal_error(_("Unable to create 3D raster map <%s>"),
  461. prop_sum_output_opt->answer);
  462. }
  463. if (prop_count_output_opt->answer) {
  464. binning.count_flat_raster =
  465. Rast3d_open_new_opt_tile_size("r3_in_lidar_tmp_sum_flat", cache,
  466. &binning.flat_region, type,
  467. max_tile_size);
  468. if (!binning.count_flat_raster)
  469. Rast3d_fatal_error(_("Unable to create 3D raster map <%s>"),
  470. count_output_opt->answer);
  471. }
  472. if (prop_sum_output_opt->answer) {
  473. binning.sum_flat_raster =
  474. Rast3d_open_new_opt_tile_size("r3_in_lidar_tmp_count_flat", cache,
  475. &binning.flat_region, type,
  476. max_tile_size);
  477. if (!binning.sum_flat_raster)
  478. Rast3d_fatal_error(_("Unable to create 3D raster map <%s>"),
  479. count_output_opt->answer);
  480. }
  481. G_verbose_message(_("Preparing the maps..."));
  482. G_percent_reset();
  483. if (binning.count_raster)
  484. raster3d_set_value_float(binning.count_raster, &binning.region, 0);
  485. G_percent(25, 100, 1);
  486. if (binning.sum_raster)
  487. raster3d_set_value_float(binning.sum_raster, &binning.region, 0);
  488. G_percent(50, 100, 1);
  489. if (binning.count_flat_raster)
  490. raster3d_set_value_float(binning.count_flat_raster, &binning.flat_region,
  491. 0);
  492. G_percent(75, 100, 1);
  493. if (binning.sum_flat_raster)
  494. raster3d_set_value_float(binning.sum_flat_raster, &binning.flat_region,
  495. 0);
  496. G_percent(1, 1, 1); /* flush */
  497. LASPointH LAS_point;
  498. double east, north, top;
  499. int row, col, depth;
  500. double value;
  501. double base_z;
  502. /* TODO: use long long */
  503. long unsigned inside = 0;
  504. long unsigned outside = 0;
  505. long unsigned in_nulls = 0; /* or outside */
  506. long unsigned n_return_filtered = 0;
  507. long unsigned n_class_filtered = 0;
  508. long unsigned irange_filtered = 0;
  509. long unsigned n_invalid = 0;
  510. long unsigned counter = 0;
  511. G_verbose_message(_("Reading points..."));
  512. G_percent_reset();
  513. /* loop of input files */
  514. for (i = 0; i < infiles.num_items; i++) {
  515. infile = infiles.items[i];
  516. /* we already know file is there, so just do basic checks */
  517. LAS_reader = LASReader_Create(infile);
  518. while ((LAS_point = LASReader_GetNextPoint(LAS_reader)) != NULL) {
  519. if (counter == 100000) { /* report only some for speed */
  520. if (inside < header_count) /* TODO: inside can greatly underestimate */
  521. G_percent(inside, header_count, 3);
  522. counter = 0;
  523. }
  524. counter++;
  525. /* We always count them and report because r.in.lidar behavior
  526. * changed in between 7.0 and 7.2 from undefined (but skipping
  527. * invalid points) to filtering them out only when requested. */
  528. if (!LASPoint_IsValid(LAS_point)) {
  529. n_invalid++;
  530. if (only_valid)
  531. continue;
  532. }
  533. if (use_return_filter) {
  534. int return_n = LASPoint_GetReturnNumber(LAS_point);
  535. int n_returns = LASPoint_GetNumberOfReturns(LAS_point);
  536. if (return_filter_is_out(&return_filter_struct, return_n, n_returns)) {
  537. n_return_filtered++;
  538. continue;
  539. }
  540. }
  541. if (use_class_filter) {
  542. int point_class = (int) LASPoint_GetClassification(LAS_point);
  543. if (class_filter_is_out(&class_filter, point_class)) {
  544. n_class_filtered++;
  545. continue;
  546. }
  547. }
  548. value = LASPoint_GetIntensity(LAS_point);
  549. value *= iscale;
  550. if (use_irange && (value < irange_min || value > irange_max)) {
  551. irange_filtered++;
  552. continue;
  553. }
  554. east = LASPoint_GetX(LAS_point);
  555. north = LASPoint_GetY(LAS_point);
  556. top = LASPoint_GetZ(LAS_point);
  557. top *= zscale;
  558. if (use_segment) {
  559. if (rast_segment_get_value_xy(&base_segment, &input_region,
  560. base_raster_data_type, east, north,
  561. &base_z)) {
  562. top -= base_z;
  563. }
  564. else {
  565. /* TODO: separate message for this */
  566. in_nulls += 1;
  567. continue;
  568. }
  569. }
  570. Rast3d_location2coord(&binning.region, north, east, top, &col, &row,
  571. &depth);
  572. if (col >= binning.region.cols || row >= binning.region.rows ||
  573. depth >= binning.region.depths || col < 0 || row < 0 ||
  574. depth < 0) {
  575. outside += 1;
  576. continue;
  577. }
  578. binning_add_point(&binning, row, col, depth, value);
  579. inside += 1;
  580. }
  581. /* close input LAS file */
  582. LASReader_Destroy(LAS_reader);
  583. }
  584. /* end of loop for all input files */
  585. G_percent(1, 1, 1); /* flush */
  586. if (binning.prop_count_raster) {
  587. G_verbose_message(_("Computing proportional count map..."));
  588. raster3d_divide_by_flat(binning.count_raster, binning.count_flat_raster,
  589. binning.prop_count_raster, &binning.region);
  590. }
  591. if (binning.prop_sum_raster) {
  592. G_verbose_message(_("Computing proportional sum map..."));
  593. raster3d_divide_by_flat(binning.sum_raster, binning.sum_flat_raster,
  594. binning.prop_sum_raster, &binning.region);
  595. }
  596. if (binning.mean_raster) {
  597. G_verbose_message(_("Computing mean map..."));
  598. raster3d_divide(binning.sum_raster, binning.count_raster,
  599. binning.mean_raster, &binning.region);
  600. }
  601. G_verbose_message(_("Closing the maps..."));
  602. G_percent_reset();
  603. if (binning.sum_flat_raster)
  604. Rast3d_close(binning.sum_flat_raster); /* TODO: delete */
  605. G_percent(1, 7, 1);
  606. if (binning.count_flat_raster)
  607. Rast3d_close(binning.count_flat_raster); /* TODO: delete */
  608. G_percent(2, 7, 1);
  609. if (binning.prop_sum_raster)
  610. Rast3d_close(binning.prop_sum_raster);
  611. G_percent(2, 7, 1);
  612. if (binning.prop_count_raster)
  613. Rast3d_close(binning.prop_count_raster);
  614. G_percent(4, 7, 1);
  615. if (binning.mean_raster)
  616. Rast3d_close(binning.mean_raster);
  617. G_percent(5, 7, 1);
  618. if (binning.sum_raster)
  619. Rast3d_close(binning.sum_raster);
  620. G_percent(6, 7, 1);
  621. if (binning.count_raster)
  622. Rast3d_close(binning.count_raster);
  623. G_percent(1, 1, 1);
  624. if (use_segment)
  625. Segment_close(&base_segment);
  626. G_message("Number of points inside: %lu", inside);
  627. if (use_segment)
  628. G_message
  629. ("Number of points outside or in base raster NULL cells: %lu",
  630. outside + in_nulls);
  631. else
  632. G_message("Number of points outside: %lu", outside);
  633. if (n_invalid && only_valid)
  634. G_message(_("%lu input points were not valid and filtered out"),
  635. n_invalid);
  636. if (n_return_filtered)
  637. G_message(_("%lu input points were filtered out by return number"), n_return_filtered);
  638. if (n_class_filtered)
  639. G_message(_("%lu input points were filtered out by class number"), n_class_filtered);
  640. if (irange_filtered)
  641. G_message(_("%lu input points had intensity out of range"), irange_filtered);
  642. if (n_invalid && !only_valid)
  643. G_message(_("%lu input points were not valid, use -%c flag to filter"
  644. " them out"), n_invalid, only_valid_flag->key);
  645. exit(EXIT_SUCCESS);
  646. }