main.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /*
  2. ****************************************************************************
  3. *
  4. * MODULE: v.decimate
  5. * AUTHOR(S): Vaclav Petras
  6. * PURPOSE: Reduce the number of points in a vector map
  7. * COPYRIGHT: (C) 2015 by the GRASS Development Team
  8. *
  9. * This program is free software under the GNU General
  10. * Public License (>=v2). Read the file COPYING that
  11. * comes with GRASS for details.
  12. *
  13. *****************************************************************************/
  14. /* using the most-specific-first order of includes */
  15. #include "count_decimation.h"
  16. #include "grid_decimation.h"
  17. #include <grass/gis.h>
  18. #include <grass/raster.h>
  19. #include <grass/vector.h>
  20. #include <grass/glocale.h>
  21. #include <stdlib.h>
  22. void copy_tabs(const struct Map_info *In, struct Map_info *Out);
  23. struct DecimationContext
  24. {
  25. int use_z; /*!< TRUE or FALSE */
  26. double zdiff;
  27. int unique_cats; /*!< TRUE or FALSE */
  28. };
  29. static int if_add_point(struct DecimationPoint *point, void *point_data,
  30. struct DecimationPoint **point_list, size_t npoints,
  31. void *context)
  32. {
  33. /* according to cat (which could be cluster, return or class) */
  34. struct DecimationContext *dc = context;
  35. double zdiff = dc->zdiff;
  36. int j;
  37. /* TODO: use something like Vect_cat_in_cat_list? */
  38. for (j = 0; j < npoints; j++) {
  39. if (dc->use_z && fabs(point_list[j]->z - point->z) < zdiff)
  40. return FALSE;
  41. if (dc->unique_cats && point_list[j]->cat == point->cat)
  42. return FALSE;
  43. }
  44. return TRUE;
  45. }
  46. struct WriteContext
  47. {
  48. struct Map_info *voutput;
  49. struct line_pnts *line;
  50. struct line_cats *cats;
  51. int write_cats;
  52. };
  53. static void write_point(struct WriteContext *context, int cat, double x,
  54. double y, double z, struct line_cats *cats)
  55. {
  56. if (Vect_append_point(context->line, x, y, z) != 1)
  57. G_fatal_error
  58. ("Unable to create a point in vector map (probably out of memory)");
  59. struct line_cats *cats_to_write = context->cats;
  60. /* only when writing cats use the ones from parameter, otherwise
  61. * use the default (which is assumed to be empty) */
  62. if (context->write_cats && cats)
  63. cats_to_write = cats;
  64. Vect_write_line(context->voutput, GV_POINT, context->line, cats_to_write);
  65. Vect_reset_line(context->line);
  66. }
  67. static void on_add_point(struct DecimationPoint *point, void *point_data, void *context)
  68. {
  69. write_point((struct WriteContext *)context, point->cat, point->x, point->y,
  70. point->z, (struct line_cats *)point_data);
  71. }
  72. /* TODO: these have overlap with vector lib, really needed? */
  73. static int point_in_region_2d(struct Cell_head *region, double x, double y)
  74. {
  75. if (x > region->east || x < region->west || y < region->south ||
  76. y > region->north)
  77. return FALSE;
  78. return TRUE;
  79. }
  80. static int point_in_region_3d(struct Cell_head *region, double x, double y,
  81. double z)
  82. {
  83. if (x > region->east || x < region->west || y < region->south ||
  84. y > region->north || z > region->top || z < region->bottom)
  85. return FALSE;
  86. return TRUE;
  87. }
  88. /* TODO: max tries per grid cell (useful?) */
  89. int main(int argc, char **argv)
  90. {
  91. struct GModule *module;
  92. struct Option *map_opt, *voutput_opt;
  93. struct Option *field_opt, *cats_opt;
  94. struct Option *skip_opt, *preserve_opt, *offset_opt, *limit_opt;
  95. struct Option *zdiff_opt, *limit_per_cell_opt, *zrange_opt;
  96. struct Flag *grid_decimation_flg, *first_point_flg, *cat_in_grid_flg;
  97. struct Flag *use_z_flg, *nocats_flag, *notopo_flag, *notab_flag;
  98. struct Map_info vinput, voutput;
  99. G_gisinit(argv[0]);
  100. module = G_define_module();
  101. G_add_keyword(_("vector"));
  102. G_add_keyword(_("LIDAR"));
  103. G_add_keyword(_("generalization"));
  104. G_add_keyword(_("decimation"));
  105. G_add_keyword(_("extract"));
  106. G_add_keyword(_("select"));
  107. G_add_keyword(_("points"));
  108. G_add_keyword(_("level1"));
  109. module->label = _("Decimates a point cloud");
  110. module->description = _("Copies points from one vector to another"
  111. " while applying different decimations");
  112. map_opt = G_define_standard_option(G_OPT_V_INPUT);
  113. field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);
  114. field_opt->required = NO;
  115. voutput_opt = G_define_standard_option(G_OPT_V_OUTPUT);
  116. zrange_opt = G_define_option();
  117. zrange_opt->key = "zrange";
  118. zrange_opt->type = TYPE_DOUBLE;
  119. zrange_opt->required = NO;
  120. zrange_opt->key_desc = "min,max";
  121. zrange_opt->description = _("Filter range for z data (min,max)");
  122. zrange_opt->guisection = _("Selection");
  123. cats_opt = G_define_standard_option(G_OPT_V_CATS);
  124. cats_opt->guisection = _("Selection");
  125. /* TODO: -r region only (now enforced for grid), spatial */
  126. skip_opt = G_define_option();
  127. skip_opt->key = "skip";
  128. skip_opt->type = TYPE_INTEGER;
  129. skip_opt->multiple = NO;
  130. skip_opt->required = NO;
  131. skip_opt->label = _("Throw away every n-th point");
  132. skip_opt->description =
  133. _("For example, 5 will import 80 percent of points. "
  134. "If not specified, all points are copied");
  135. skip_opt->guisection = _("Count");
  136. preserve_opt = G_define_option();
  137. preserve_opt->key = "preserve";
  138. preserve_opt->type = TYPE_INTEGER;
  139. preserve_opt->multiple = NO;
  140. preserve_opt->required = NO;
  141. preserve_opt->label = _("Preserve only every n-th point");
  142. preserve_opt->description =
  143. _("For example, 4 will import 25 percent of points. "
  144. "If not specified, all points are copied");
  145. preserve_opt->guisection = _("Count");
  146. offset_opt = G_define_option();
  147. offset_opt->key = "offset";
  148. offset_opt->type = TYPE_INTEGER;
  149. offset_opt->multiple = NO;
  150. offset_opt->required = NO;
  151. offset_opt->label = _("Skip first n points");
  152. offset_opt->description =
  153. _("Skips the given number of points at the beginning.");
  154. offset_opt->guisection = _("Count");
  155. limit_opt = G_define_option();
  156. limit_opt->key = "limit";
  157. limit_opt->type = TYPE_INTEGER;
  158. limit_opt->multiple = NO;
  159. limit_opt->required = NO;
  160. limit_opt->label = _("Copy only n points");
  161. limit_opt->description = _("Copies only the given number of points");
  162. limit_opt->guisection = _("Count");
  163. zdiff_opt = G_define_option();
  164. zdiff_opt->key = "zdiff";
  165. zdiff_opt->type = TYPE_DOUBLE;
  166. zdiff_opt->required = NO;
  167. zdiff_opt->label = _("Minimal difference of z values");
  168. zdiff_opt->description =
  169. _("Minimal difference between z values in grid-based decimation");
  170. zdiff_opt->guisection = _("Grid");
  171. limit_per_cell_opt = G_define_option();
  172. limit_per_cell_opt->key = "cell_limit";
  173. limit_per_cell_opt->type = TYPE_INTEGER;
  174. limit_per_cell_opt->multiple = NO;
  175. limit_per_cell_opt->required = NO;
  176. limit_per_cell_opt->label = _("Preserve only n points per grid cell");
  177. limit_per_cell_opt->description =
  178. _("Preserves only the given number of points per grid cell in grid-based decimation");
  179. limit_per_cell_opt->guisection = _("Grid");
  180. grid_decimation_flg = G_define_flag();
  181. grid_decimation_flg->key = 'g';
  182. grid_decimation_flg->description = _("Apply grid-based decimation");
  183. grid_decimation_flg->guisection = _("Grid");
  184. first_point_flg = G_define_flag();
  185. first_point_flg->key = 'f';
  186. first_point_flg->description =
  187. _("Use only first point in grid cell during grid-based decimation");
  188. first_point_flg->guisection = _("Grid");
  189. cat_in_grid_flg = G_define_flag();
  190. cat_in_grid_flg->key = 'c';
  191. cat_in_grid_flg->description = _("Only one point per cat in grid cell");
  192. cat_in_grid_flg->guisection = _("Grid");
  193. use_z_flg = G_define_flag();
  194. use_z_flg->key = 'z';
  195. use_z_flg->description = _("Use z in grid decimation");
  196. use_z_flg->guisection = _("Grid");
  197. nocats_flag = G_define_flag();
  198. nocats_flag->key = 'x';
  199. nocats_flag->label =
  200. _("Store only the coordinates, throw away categories");
  201. nocats_flag->description =
  202. _("Do not story any categories even if they are present in input data");
  203. nocats_flag->guisection = _("Speed");
  204. notopo_flag = G_define_standard_flag(G_FLG_V_TOPO);
  205. notopo_flag->guisection = _("Speed");
  206. notab_flag = G_define_standard_flag(G_FLG_V_TABLE);
  207. notab_flag->guisection = _("Speed");
  208. /* here we have different decimations but also selections/filters */
  209. G_option_required(skip_opt, preserve_opt, offset_opt, limit_opt,
  210. grid_decimation_flg, zrange_opt, cats_opt, NULL);
  211. /* this doesn't play well with GUI dialog unless we add defaults to options
  212. * the default values would solve it but looks strange in the manual
  213. * this we use explicit check in the code */
  214. /* G_option_exclusive(skip_opt, preserve_opt, NULL); */
  215. G_option_requires(grid_decimation_flg, first_point_flg,
  216. limit_per_cell_opt, use_z_flg, zdiff_opt,
  217. cat_in_grid_flg, NULL);
  218. G_option_requires(first_point_flg, grid_decimation_flg, NULL);
  219. G_option_requires(limit_per_cell_opt, grid_decimation_flg, NULL);
  220. G_option_requires(use_z_flg, grid_decimation_flg, NULL);
  221. G_option_requires(zdiff_opt, grid_decimation_flg, NULL);
  222. G_option_requires(cat_in_grid_flg, grid_decimation_flg, NULL);
  223. G_option_exclusive(zdiff_opt, first_point_flg, limit_per_cell_opt, NULL);
  224. if (G_parser(argc, argv))
  225. exit(EXIT_FAILURE);
  226. Vect_check_input_output_name(map_opt->answer, voutput_opt->answer,
  227. G_FATAL_EXIT);
  228. if (Vect_open_old2(&vinput, map_opt->answer, "", field_opt->answer) < 0)
  229. G_fatal_error(_("Unable to open vector map <%s>"), map_opt->answer);
  230. int layer = Vect_get_field_number(&vinput, field_opt->answer);
  231. if (layer < 1 && (cats_opt->answer || cat_in_grid_flg->answer))
  232. G_fatal_error(_("Input layer must be set to a particular layer"
  233. ", not <%s>, when using <%s> option or <-%c> flag"),
  234. field_opt->answer, cats_opt->key, cat_in_grid_flg->key);
  235. struct cat_list *allowed_cats = NULL;
  236. if (layer > 0)
  237. allowed_cats = Vect_cats_set_constraint(&vinput, layer, NULL,
  238. cats_opt->answer);
  239. struct line_pnts *line = Vect_new_line_struct();
  240. struct line_cats *cats = Vect_new_cats_struct();
  241. double zrange_min, zrange_max;
  242. int use_zrange = FALSE;
  243. if (zrange_opt->answer != NULL) {
  244. if (zrange_opt->answers[0] == NULL || zrange_opt->answers[1] == NULL)
  245. G_fatal_error(_("Invalid zrange <%s>"), zrange_opt->answer);
  246. sscanf(zrange_opt->answers[0], "%lf", &zrange_min);
  247. sscanf(zrange_opt->answers[1], "%lf", &zrange_max);
  248. /* for convenience, switch order to make valid input */
  249. if (zrange_min > zrange_max) {
  250. double tmp = zrange_max;
  251. zrange_max = zrange_min;
  252. zrange_min = tmp;
  253. }
  254. use_zrange = TRUE;
  255. }
  256. int use_z = FALSE;
  257. double zdiff;
  258. if (use_z_flg->answer) {
  259. use_z = TRUE;
  260. zdiff = atof(zdiff_opt->answer);
  261. }
  262. /* z input checks */
  263. if (!Vect_is_3d(&vinput)) {
  264. if (use_z)
  265. G_fatal_error(_("Cannot use z for decimation, input is not 3D"));
  266. if (use_zrange)
  267. G_fatal_error(_("Cannot select by z range, input is not 3D"));
  268. }
  269. int do_grid_decimation = FALSE;
  270. if (grid_decimation_flg->answer)
  271. do_grid_decimation = TRUE;
  272. int limit_per_cell = 0;
  273. if (limit_per_cell_opt->answer)
  274. limit_per_cell = atof(limit_per_cell_opt->answer);
  275. if (first_point_flg->answer)
  276. limit_per_cell = 1;
  277. /* when user enters 1 or zero e.g. for skip, we accept it and use it
  278. * but the is no advantage, however, we count it as an error when
  279. * no other options are selected
  280. */
  281. struct CountDecimationControl count_decimation_control;
  282. count_decimation_init_from_str(&count_decimation_control,
  283. skip_opt->answer, preserve_opt->answer,
  284. offset_opt->answer, limit_opt->answer);
  285. if (!count_decimation_is_valid(&count_decimation_control))
  286. G_fatal_error(_("Settings for count-based decimation are not valid"));
  287. /* TODO: implement count_decimation_is_invalid_reason() */
  288. /* the following must be in sync with required options */
  289. if (count_decimation_is_noop(&count_decimation_control) &&
  290. !grid_decimation_flg->answer && !zrange_opt->answer &&
  291. !cats_opt->answer)
  292. G_fatal_error(_("Settings for count-based decimation would cause it"
  293. " to do nothing and no other options has been set."));
  294. struct Cell_head comp_region;
  295. Rast_get_window(&comp_region);
  296. if (use_zrange) {
  297. comp_region.bottom = zrange_min;
  298. comp_region.top = zrange_max;
  299. }
  300. struct GridDecimation grid_decimation;
  301. struct DecimationContext decimation_context;
  302. struct WriteContext write_context;
  303. write_context.line = Vect_new_line_struct();
  304. write_context.cats = Vect_new_cats_struct();
  305. if (!nocats_flag->answer)
  306. write_context.write_cats = TRUE;
  307. else
  308. write_context.write_cats = FALSE;
  309. write_context.voutput = &voutput;
  310. if (do_grid_decimation) {
  311. grid_decimation_create_from_region(&grid_decimation, &comp_region);
  312. grid_decimation.max_points = limit_per_cell;
  313. if (cat_in_grid_flg->answer)
  314. decimation_context.unique_cats = TRUE;
  315. else
  316. decimation_context.unique_cats = FALSE;
  317. decimation_context.use_z = FALSE;
  318. if (use_z) {
  319. decimation_context.use_z = TRUE;
  320. decimation_context.zdiff = zdiff;
  321. }
  322. grid_decimation.if_add_point = if_add_point;
  323. grid_decimation.if_context = &decimation_context;
  324. grid_decimation.on_add_point = on_add_point;
  325. grid_decimation.on_context = &write_context;
  326. }
  327. if (Vect_open_new(&voutput, voutput_opt->answer, Vect_is_3d(&vinput)) < 0)
  328. G_fatal_error(_("Unable to create vector map <%s>"),
  329. voutput_opt->answer);
  330. /* some constraints can be set on the map */
  331. Vect_set_constraint_type(&vinput, GV_POINT);
  332. /* noop for layer=-1 and non-native format, skips lines without cat */
  333. Vect_set_constraint_field(&vinput, layer);
  334. /* TODO: replace region checks by Vect_set_constraint_region? */
  335. int ltype;
  336. int cat;
  337. while (TRUE) {
  338. ltype = Vect_read_next_line(&vinput, line, cats);
  339. if (ltype == -1)
  340. G_fatal_error(_("Unable to read vector map"));
  341. if (ltype == -2)
  342. break; /* end of the map */
  343. double x, y, z;
  344. Vect_line_get_point(line, 0, &x, &y, &z);
  345. /* selections/filters */
  346. /* TODO: use region only when actually needed */
  347. if (!use_zrange && !point_in_region_2d(&comp_region, x, y))
  348. continue;
  349. /* TODO: allow zrange to be used without region */
  350. if (use_zrange && !point_in_region_3d(&comp_region, x, y, z))
  351. continue;
  352. if (layer > 0 && allowed_cats &&
  353. !Vect_cats_in_constraint(cats, layer, allowed_cats))
  354. continue;
  355. /* decimation */
  356. if (count_decimation_is_out(&count_decimation_control))
  357. continue;
  358. /* TODO: test: skip points without category, unless layer=-1 */
  359. /* Use cases:
  360. * - all points have category (correct)
  361. * - no categories for any point (correct, layer=-1 required)
  362. * - some points miss category (not handled)
  363. * Here we assume that only one cat has meaning for grid decimation.
  364. * If no layer available, cat contains junk and shouldn't be used.
  365. *
  366. * TODO done
  367. */
  368. cat = -1;
  369. if (layer > 0) {
  370. if (allowed_cats) {
  371. int i;
  372. for (i = 0; i < cats->n_cats; i++) {
  373. if (cats->field[i] == layer &&
  374. Vect_cat_in_cat_list(cats->cat[i], allowed_cats)) {
  375. cat = cats->cat[i];
  376. break;
  377. }
  378. }
  379. return 0;
  380. }
  381. else
  382. Vect_cat_get(cats, layer, &cat);
  383. if (cat < 0)
  384. continue;
  385. }
  386. /* using callback when using grid, direct call otherwise */
  387. if (do_grid_decimation)
  388. grid_decimation_try_add_point(&grid_decimation, cat, x, y, z,
  389. cats);
  390. else
  391. write_point(&write_context, cat, x, y, z, cats);
  392. if (count_decimation_is_end(&count_decimation_control))
  393. break;
  394. }
  395. /* partially unnecessary as deallocated by the system */
  396. Vect_destroy_line_struct(line);
  397. Vect_destroy_cats_struct(cats);
  398. Vect_destroy_line_struct(write_context.line);
  399. Vect_destroy_cats_struct(write_context.cats);
  400. Vect_hist_command(&voutput);
  401. Vect_close(&vinput);
  402. if (!notopo_flag->answer) {
  403. Vect_build(&voutput);
  404. if (write_context.write_cats == TRUE && !notab_flag->answer) {
  405. copy_tabs(&vinput, &voutput);
  406. }
  407. }
  408. Vect_close(&voutput);
  409. if (do_grid_decimation)
  410. grid_decimation_destroy(&grid_decimation);
  411. return EXIT_SUCCESS;
  412. }