[GRASS-SVN] r66387 - in grass/trunk/vector: . v.decimate
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Sep 30 18:55:00 PDT 2015
Author: wenzeslaus
Date: 2015-09-30 18:55:00 -0700 (Wed, 30 Sep 2015)
New Revision: 66387
Added:
grass/trunk/vector/v.decimate/
grass/trunk/vector/v.decimate/Makefile
grass/trunk/vector/v.decimate/count_decimation.c
grass/trunk/vector/v.decimate/count_decimation.h
grass/trunk/vector/v.decimate/grid_decimation.c
grass/trunk/vector/v.decimate/grid_decimation.h
grass/trunk/vector/v.decimate/main.c
grass/trunk/vector/v.decimate/v.decimate.html
grass/trunk/vector/v.decimate/v_decimate_count.png
grass/trunk/vector/v.decimate/v_decimate_grid_cat.png
grass/trunk/vector/v.decimate/v_decimate_original.png
Log:
v.decimate: grid and count based decimation [news]
Added: grass/trunk/vector/v.decimate/Makefile
===================================================================
--- grass/trunk/vector/v.decimate/Makefile (rev 0)
+++ grass/trunk/vector/v.decimate/Makefile 2015-10-01 01:55:00 UTC (rev 66387)
@@ -0,0 +1,14 @@
+
+MODULE_TOPDIR = ../..
+
+PGM = v.decimate
+
+LIBES = $(VECTORLIB) $(DBMILIB) $(RASTERLIB) $(GISLIB) $(BTREE2LIB) $(SEGMENTLIB)
+DEPENDENCIES = $(VECTORDEP) $(DBMIDEP) $(RASTERDEP) $(GISDEP) $(SEGMENTDEP)
+
+EXTRA_INC = $(VECT_INC)
+EXTRA_CFLAGS = $(VECT_CFLAGS)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd
Property changes on: grass/trunk/vector/v.decimate/Makefile
___________________________________________________________________
Added: svn:mime-type
+ text/x-makefile
Added: svn:eol-style
+ native
Added: grass/trunk/vector/v.decimate/count_decimation.c
===================================================================
--- grass/trunk/vector/v.decimate/count_decimation.c (rev 0)
+++ grass/trunk/vector/v.decimate/count_decimation.c 2015-10-01 01:55:00 UTC (rev 66387)
@@ -0,0 +1,132 @@
+/****************************************************************************
+ *
+ * MODULE: v.decimate
+ * AUTHOR(S): Vaclav Petras
+ * PURPOSE: Reduce the number of points in a vector map
+ * COPYRIGHT: (C) 2015 by the GRASS Development Team
+ *
+ * This program is free software under the GNU General Public
+ * License (>=v2). Read the COPYING file that comes with GRASS
+ * for details.
+ *
+ *****************************************************************************/
+
+
+/* TODO: change int */
+/* TODO: revise names */
+
+#include "count_decimation.h"
+
+#include <grass/gis.h>
+
+#include <stdlib.h>
+
+
+void count_decimation_init(struct CountDecimationControl *control,
+ int *skip, int *preserve,
+ int *offset, int *limit)
+{
+ control->skip_every = 0;
+ control->preserve_every = 0;
+ /* counter used by both but that's ok, skip and preserve are exclusive */
+ control->every_counter = 0;
+ control->n_count_filtered = 0;
+ control->offset_n = 0;
+ control->offset_n_counter = 0;
+ control->limit_n = 0;
+ control->limit_n_counter = 0;
+ if (skip)
+ control->skip_every = *skip;
+ if (preserve)
+ control->preserve_every = *preserve;
+ if (offset)
+ control->offset_n = *offset;
+ if (limit)
+ control->limit_n = *limit;
+}
+
+
+int count_decimation_is_valid(struct CountDecimationControl *control)
+{
+ if (control->skip_every == 1)
+ return FALSE;
+ if (control->skip_every && control->preserve_every > 1)
+ return FALSE;
+ return TRUE;
+}
+
+
+int count_decimation_is_noop(struct CountDecimationControl *control)
+{
+ if (control->skip_every < 2 && control->preserve_every < 2
+ && !control->offset_n && !control->limit_n)
+ return TRUE;
+ return FALSE;
+}
+
+void count_decimation_init_from_str(struct CountDecimationControl *control,
+ const char *skip, const char *preserve,
+ const char *offset, const char *limit)
+{
+ control->skip_every = 0;
+ control->preserve_every = 0;
+ control->every_counter = 0;
+ control->n_count_filtered = 0;
+ control->offset_n = 0;
+ control->offset_n_counter = 0;
+ control->limit_n = 0;
+ control->limit_n_counter = 0;
+ /* TODO: atoi is probably not appropriate */
+ if (skip)
+ control->skip_every = atoi(skip);
+ if (preserve)
+ control->preserve_every = atoi(preserve);
+ if (offset)
+ control->offset_n = atoi(offset);
+ if (limit)
+ control->limit_n = atoi(limit);
+}
+
+
+/* TODO: eliminate noop cases */
+int count_decimation_is_out(struct CountDecimationControl *control)
+{
+ if (control->offset_n) {
+ control->offset_n_counter++;
+ if (control->offset_n_counter < control->offset_n)
+ return TRUE;
+ else
+ control->offset_n = 0; /* disable offset check */
+ }
+ if (control->skip_every) {
+ control->every_counter++;
+ if (control->every_counter == control->skip_every) {
+ control->n_count_filtered++;
+ control->every_counter = 0;
+ return TRUE;
+ }
+ }
+ else if (control->preserve_every) {
+ control->every_counter++;
+ if (control->every_counter == control->preserve_every) {
+ control->every_counter = 0;
+ }
+ else {
+ control->n_count_filtered++;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+int count_decimation_is_end(struct CountDecimationControl *control)
+{
+ if (control->limit_n) {
+ control->limit_n_counter++;
+ /* this matches the last successfully imported point */
+ if (control->limit_n_counter == control->limit_n)
+ return TRUE;
+ }
+ return FALSE;
+}
Property changes on: grass/trunk/vector/v.decimate/count_decimation.c
___________________________________________________________________
Added: svn:mime-type
+ text/x-csrc
Added: svn:eol-style
+ native
Added: grass/trunk/vector/v.decimate/count_decimation.h
===================================================================
--- grass/trunk/vector/v.decimate/count_decimation.h (rev 0)
+++ grass/trunk/vector/v.decimate/count_decimation.h 2015-10-01 01:55:00 UTC (rev 66387)
@@ -0,0 +1,43 @@
+/****************************************************************************
+ *
+ * MODULE: v.decimate
+ * AUTHOR(S): Vaclav Petras
+ * PURPOSE: Reduce the number of points in a vector map
+ * COPYRIGHT: (C) 2015 by the GRASS Development Team
+ *
+ * This program is free software under the GNU General Public
+ * License (>=v2). Read the COPYING file that comes with GRASS
+ * for details.
+ *
+ *****************************************************************************/
+
+
+#ifndef GRASS_COUNT_DECIMATION_H
+#define GRASS_COUNT_DECIMATION_H
+
+/* TODO: change int to ul/ull */
+/* TODO: revise names (now partially on some vars in v.in.lidar code) */
+
+struct CountDecimationControl {
+ int offset_n;
+ int offset_n_counter;
+ int skip_every;
+ int preserve_every;
+ int every_counter;
+ int n_count_filtered;
+ int limit_n;
+ int limit_n_counter;
+};
+
+void count_decimation_init(struct CountDecimationControl *control,
+ int *skip, int *preserve,
+ int *offset, int *limit);
+int count_decimation_is_valid(struct CountDecimationControl *control);
+int count_decimation_is_noop(struct CountDecimationControl *control);
+void count_decimation_init_from_str(struct CountDecimationControl *control,
+ const char *skip, const char *preserve,
+ const char *offset, const char *limit);
+int count_decimation_is_out(struct CountDecimationControl *control);
+int count_decimation_is_end(struct CountDecimationControl *control);
+
+#endif /* GRASS_COUNT_DECIMATION_H */
Property changes on: grass/trunk/vector/v.decimate/count_decimation.h
___________________________________________________________________
Added: svn:mime-type
+ text/x-chdr
Added: svn:eol-style
+ native
Added: grass/trunk/vector/v.decimate/grid_decimation.c
===================================================================
--- grass/trunk/vector/v.decimate/grid_decimation.c (rev 0)
+++ grass/trunk/vector/v.decimate/grid_decimation.c 2015-10-01 01:55:00 UTC (rev 66387)
@@ -0,0 +1,179 @@
+/****************************************************************************
+ *
+ * MODULE: v.decimate
+ * AUTHOR(S): Vaclav Petras
+ * PURPOSE: Reduce the number of points in a vector map
+ * COPYRIGHT: (C) 2015 by the GRASS Development Team
+ *
+ * This program is free software under the GNU General Public
+ * License (>=v2). Read the COPYING file that comes with GRASS
+ * for details.
+ *
+ *****************************************************************************/
+
+
+#include "grid_decimation.h"
+
+#include <stdlib.h>
+
+
+/* max size: rows * cols < max of size_t (using 1D array) */
+void grid_decimation_create(struct GridDecimation *grid_decimation,
+ size_t rows, size_t cols)
+{
+ grid_decimation->grid_points =
+ G_calloc(rows * cols, sizeof(struct DecimationPoint *));
+ grid_decimation->grid_sizes = G_calloc(rows * cols, sizeof(size_t));
+ grid_decimation->rows = rows;
+ grid_decimation->cols = cols;
+ grid_decimation->if_add_point = NULL;
+ grid_decimation->on_add_point = NULL;
+ grid_decimation->if_context = NULL;
+ grid_decimation->on_context = NULL;
+}
+
+
+void grid_decimation_destroy(struct GridDecimation *grid_decimation)
+{
+ /* TODO: we could also offer mode without dealloc (faster) */
+ int row, col;
+ size_t point, npoints;
+ for (row = 0; row < grid_decimation->rows; row++) {
+ for (col = 0; col < grid_decimation->cols; col++) {
+ /* TODO: make index function */
+ size_t index = row * grid_decimation->cols + col;
+ if ((npoints = grid_decimation->grid_sizes[index])) {
+ /* delete points in list */
+ for (point = 0; point < npoints; point++)
+ G_free(grid_decimation->grid_points[index][point]);
+ /* delete list */
+ G_free(grid_decimation->grid_points[index]);
+ }
+ }
+ }
+ G_free(grid_decimation->grid_points);
+ G_free(grid_decimation->grid_sizes);
+}
+
+
+/* TODO: use Cell_head as storage? */
+void grid_decimation_create_from_region(struct GridDecimation
+ *grid_decimation,
+ struct Cell_head *region)
+{
+ grid_decimation_create(grid_decimation, region->rows, region->cols);
+ grid_decimation_set_region(grid_decimation, region->west, region->east,
+ region->south, region->north, region->ew_res,
+ region->ns_res);
+}
+
+
+/* TODO: change order of ns_res and ew_res to match xy */
+void grid_decimation_set_region(struct GridDecimation *grid_decimation,
+ double minx, double maxx, double miny,
+ double maxy, double ew_res, double ns_res)
+{
+ grid_decimation->minx = minx;
+ grid_decimation->maxx = maxx;
+ grid_decimation->miny = miny;
+ grid_decimation->maxy = maxy;
+ grid_decimation->ns_res = ns_res;
+ grid_decimation->ew_res = ew_res;
+}
+
+
+void grid_decimation_create_list_with_point(struct GridDecimation
+ *grid_decimation, size_t index,
+ struct DecimationPoint *point,
+ size_t npoints)
+{
+ struct DecimationPoint **point_list =
+ G_malloc(1 * sizeof(struct DecimationPoint *));
+ point_list[0] = point;
+ grid_decimation->grid_points[index] = point_list;
+ grid_decimation->grid_sizes[index] = 1;
+}
+
+
+void grid_decimation_add_point_to_list(struct GridDecimation *grid_decimation,
+ size_t index,
+ struct DecimationPoint *point,
+ size_t npoints)
+{
+ /* TODO: this might be too much reallocation */
+ /* TODO: line_ptns struct could be reused, it is not meant for this but it would work */
+ struct DecimationPoint **point_list =
+ G_realloc(grid_decimation->grid_points[index],
+ (npoints + 1) * sizeof(struct DecimationPoint *));
+
+ point_list[npoints] = point;
+ grid_decimation->grid_points[index] = point_list;
+ grid_decimation->grid_sizes[index] = npoints + 1;
+}
+
+
+static size_t grid_decimation_xy_to_index(struct GridDecimation
+ *grid_decimation, double x,
+ double y)
+{
+ /* TODO: test x, y */
+ int row = (y - grid_decimation->miny) / grid_decimation->ns_res;
+ int col = (x - grid_decimation->minx) / grid_decimation->ew_res;
+
+ if (row < 0 || row > grid_decimation->rows || col < 0 ||
+ col > grid_decimation->cols) {
+ G_fatal_error
+ ("Row (%d) or column (%d) outside of range (0 - %d, 0 - %d)", row,
+ col, grid_decimation->rows, grid_decimation->cols);
+ }
+ size_t index = row * grid_decimation->cols + col;
+
+ /* TODO: are the tests really needed, especially the second one? */
+ if (row * grid_decimation->cols + col >
+ grid_decimation->rows * grid_decimation->cols) {
+ G_fatal_error("Index (%d) out of range (max: %d)",
+ row * grid_decimation->cols + col,
+ grid_decimation->rows * grid_decimation->cols);
+ }
+ return index;
+}
+
+
+void grid_decimation_try_add_point(struct GridDecimation *grid_decimation,
+ int cat, double x, double y, double z, void *point_data)
+{
+ size_t index = grid_decimation_xy_to_index(grid_decimation, x, y);
+ int npoints = grid_decimation->grid_sizes[index];
+
+ /* TODO: when max is 1, we don't have to store the point at all */
+ if (grid_decimation->max_points && grid_decimation->max_points == npoints)
+ return;
+
+ struct DecimationPoint *point = G_malloc(sizeof(struct DecimationPoint));
+
+ point->cat = cat;
+ point->x = x;
+ point->y = y;
+ point->z = z;
+
+ if (!npoints) {
+ grid_decimation_create_list_with_point(grid_decimation, index, point,
+ npoints);
+ if (grid_decimation->on_add_point)
+ grid_decimation->on_add_point(point, point_data, grid_decimation->on_context);
+ }
+ else {
+ if (grid_decimation->if_add_point
+ (point, point_data, grid_decimation->grid_points[index], npoints,
+ grid_decimation->if_context)) {
+ grid_decimation_add_point_to_list(grid_decimation, index, point,
+ npoints);
+ if (grid_decimation->on_add_point)
+ grid_decimation->on_add_point(point, point_data,
+ grid_decimation->on_context);
+ }
+ else {
+ G_free(point);
+ }
+ }
+}
Property changes on: grass/trunk/vector/v.decimate/grid_decimation.c
___________________________________________________________________
Added: svn:mime-type
+ text/x-csrc
Added: svn:eol-style
+ native
Added: grass/trunk/vector/v.decimate/grid_decimation.h
===================================================================
--- grass/trunk/vector/v.decimate/grid_decimation.h (rev 0)
+++ grass/trunk/vector/v.decimate/grid_decimation.h 2015-10-01 01:55:00 UTC (rev 66387)
@@ -0,0 +1,79 @@
+/****************************************************************************
+ *
+ * MODULE: v.decimate
+ * AUTHOR(S): Vaclav Petras
+ * PURPOSE: Reduce the number of points in a vector map
+ * COPYRIGHT: (C) 2015 by the GRASS Development Team
+ *
+ * This program is free software under the GNU General Public
+ * License (>=v2). Read the COPYING file that comes with GRASS
+ * for details.
+ *
+ *****************************************************************************/
+
+
+#ifndef GRASS_GRID_DECIMATION_H
+#define GRASS_GRID_DECIMATION_H
+
+#include <grass/gis.h>
+
+struct DecimationPoint
+{
+ int cat;
+ double x;
+ double y;
+ double z;
+};
+
+
+struct GridDecimation
+{
+ struct DecimationPoint ***grid_points;
+ size_t *grid_sizes;
+ int rows;
+ int cols;
+ int max_points;
+ double minx;
+ double maxx;
+ double miny;
+ double maxy;
+ double ns_res;
+ double ew_res;
+ int (*if_add_point) (struct DecimationPoint * point, void *point_data,
+ struct DecimationPoint ** point_list, size_t npoints,
+ void *context);
+ void (*on_add_point) (struct DecimationPoint * point, void *point_data, void *context);
+ void *if_context;
+ void *on_context;
+};
+
+
+/* max size: rows * cols < max of size_t (using 1D array) */
+void grid_decimation_create(struct GridDecimation *grid_decimation,
+ size_t rows, size_t cols);
+
+void grid_decimation_create_from_region(struct GridDecimation
+ *grid_decimation,
+ struct Cell_head *region);
+
+/* TODO: possible use (also?) Cell_head as input or storage */
+void grid_decimation_set_region(struct GridDecimation *grid_decimation,
+ double minx, double maxx, double miny,
+ double maxy, double ns_res, double ew_res);
+
+void grid_decimation_create_list_with_point(struct GridDecimation
+ *grid_decimation, size_t index,
+ struct DecimationPoint *point,
+ size_t npoints);
+
+void grid_decimation_add_point_to_list(struct GridDecimation *grid_decimation,
+ size_t index,
+ struct DecimationPoint *point,
+ size_t npoints);
+
+void grid_decimation_try_add_point(struct GridDecimation *grid_decimation,
+ int cat, double x, double y, double z, void *point_data);
+
+void grid_decimation_destroy(struct GridDecimation *grid_decimation);
+
+#endif /* GRASS_GRID_DECIMATION_H */
Property changes on: grass/trunk/vector/v.decimate/grid_decimation.h
___________________________________________________________________
Added: svn:mime-type
+ text/x-chdr
Added: svn:eol-style
+ native
Added: grass/trunk/vector/v.decimate/main.c
===================================================================
--- grass/trunk/vector/v.decimate/main.c (rev 0)
+++ grass/trunk/vector/v.decimate/main.c 2015-10-01 01:55:00 UTC (rev 66387)
@@ -0,0 +1,465 @@
+/*
+ ****************************************************************************
+ *
+ * MODULE: v.decimate
+ * AUTHOR(S): Vaclav Petras
+ * PURPOSE: Reduce the number of points in a vector map
+ * COPYRIGHT: (C) 2015 by the GRASS Development Team
+ *
+ * This program is free software under the GNU General
+ * Public License (>=v2). Read the file COPYING that
+ * comes with GRASS for details.
+ *
+ *****************************************************************************/
+
+
+/* using the most-specific-first order of includes */
+#include "count_decimation.h"
+#include "grid_decimation.h"
+
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/vector.h>
+#include <grass/glocale.h>
+
+#include <stdlib.h>
+
+
+struct DecimationContext
+{
+ int use_z; /*!< TRUE or FALSE */
+ double zdiff;
+ int unique_cats; /*!< TRUE or FALSE */
+};
+
+
+static int if_add_point(struct DecimationPoint *point, void *point_data,
+ struct DecimationPoint **point_list, size_t npoints,
+ void *context)
+{
+ /* according to cat (which could be cluster, return or class) */
+ struct DecimationContext *dc = context;
+ double zdiff = dc->zdiff;
+ int j;
+
+ /* TODO: use something like Vect_cat_in_cat_list? */
+ for (j = 0; j < npoints; j++) {
+ if (dc->use_z && fabs(point_list[j]->z - point->z) < zdiff)
+ return FALSE;
+ if (dc->unique_cats && point_list[j]->cat == point->cat)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+struct WriteContext
+{
+ struct Map_info *voutput;
+ struct line_pnts *line;
+ struct line_cats *cats;
+ int write_cats;
+};
+
+
+static void write_point(struct WriteContext *context, int cat, double x,
+ double y, double z, struct line_cats *cats)
+{
+ if (Vect_append_point(context->line, x, y, z) != 1)
+ G_fatal_error
+ ("Unable to create a point in vector map (probably out of memory)");
+ struct line_cats *cats_to_write = context->cats;
+ /* only when writing cats use the ones from parameter, otherwise
+ * use the default (which is assumed to be empty) */
+ if (context->write_cats && cats)
+ cats_to_write = cats;
+ Vect_write_line(context->voutput, GV_POINT, context->line, cats_to_write);
+ Vect_reset_line(context->line);
+}
+
+
+static void on_add_point(struct DecimationPoint *point, void *point_data, void *context)
+{
+ write_point((struct WriteContext *)context, point->cat, point->x, point->y,
+ point->z, (struct line_cats *)point_data);
+}
+
+/* TODO: these have overlap with vector lib, really needed? */
+static int point_in_region_2d(struct Cell_head *region, double x, double y)
+{
+ if (x > region->east || x < region->west || y < region->south ||
+ y > region->north)
+ return FALSE;
+ return TRUE;
+}
+
+
+static int point_in_region_3d(struct Cell_head *region, double x, double y,
+ double z)
+{
+ if (x > region->east || x < region->west || y < region->south ||
+ y > region->north || z > region->top || z < region->bottom)
+ return FALSE;
+ return TRUE;
+}
+
+/* TODO: max tries per grid cell (useful?) */
+
+
+int main(int argc, char **argv)
+{
+ struct GModule *module;
+ struct Option *map_opt, *voutput_opt;
+ struct Option *field_opt, *cats_opt;
+ struct Option *skip_opt, *preserve_opt, *offset_opt, *limit_opt;
+ struct Option *zdiff_opt, *limit_per_cell_opt, *zrange_opt;
+ struct Flag *grid_decimation_flg, *first_point_flg, *cat_in_grid_flg;
+ struct Flag *use_z_flg, *nocats_flag, *notopo_flag;
+ struct Map_info vinput, voutput;
+
+ G_gisinit(argv[0]);
+
+ module = G_define_module();
+ G_add_keyword(_("vector"));
+ G_add_keyword(_("LIDAR"));
+ G_add_keyword(_("generalization"));
+ G_add_keyword(_("decimation"));
+ G_add_keyword(_("extract"));
+ G_add_keyword(_("select"));
+ G_add_keyword(_("points"));
+ module->label = _("Decimates a point cloud");
+ module->description = _("Copies points from one vector to another"
+ " while applying different decimations");
+
+ map_opt = G_define_standard_option(G_OPT_V_INPUT);
+
+ field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL);
+ field_opt->required = NO;
+
+ voutput_opt = G_define_standard_option(G_OPT_V_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->description = _("Filter range for z data (min,max)");
+ zrange_opt->guisection = _("Selection");
+
+ cats_opt = G_define_standard_option(G_OPT_V_CATS);
+ cats_opt->guisection = _("Selection");
+
+ /* TODO: -r region only (now enforced for grid), spatial */
+
+ skip_opt = G_define_option();
+ skip_opt->key = "skip";
+ skip_opt->type = TYPE_INTEGER;
+ skip_opt->multiple = NO;
+ skip_opt->required = NO;
+ skip_opt->label = _("Throw away every n-th point");
+ skip_opt->description =
+ _("For example, 5 will import 80 percent of points. "
+ "If not specified, all points are copied");
+ skip_opt->guisection = _("Count");
+
+ preserve_opt = G_define_option();
+ preserve_opt->key = "preserve";
+ preserve_opt->type = TYPE_INTEGER;
+ preserve_opt->multiple = NO;
+ preserve_opt->required = NO;
+ preserve_opt->label = _("Preserve only every n-th point");
+ preserve_opt->description =
+ _("For example, 4 will import 25 percent of points. "
+ "If not specified, all points are copied");
+ preserve_opt->guisection = _("Count");
+
+ offset_opt = G_define_option();
+ offset_opt->key = "offset";
+ offset_opt->type = TYPE_INTEGER;
+ offset_opt->multiple = NO;
+ offset_opt->required = NO;
+ offset_opt->label = _("Skip first n points");
+ offset_opt->description =
+ _("Skips the given number of points at the beginning.");
+ offset_opt->guisection = _("Count");
+
+ limit_opt = G_define_option();
+ limit_opt->key = "limit";
+ limit_opt->type = TYPE_INTEGER;
+ limit_opt->multiple = NO;
+ limit_opt->required = NO;
+ limit_opt->label = _("Copy only n points");
+ limit_opt->description = _("Copies only the given number of points");
+ limit_opt->guisection = _("Count");
+
+ zdiff_opt = G_define_option();
+ zdiff_opt->key = "zdiff";
+ zdiff_opt->type = TYPE_DOUBLE;
+ zdiff_opt->required = NO;
+ zdiff_opt->label = _("Minimal difference of z values");
+ zdiff_opt->description =
+ _("Minimal difference between z values in grid-based decimation");
+ zdiff_opt->guisection = _("Grid");
+
+ limit_per_cell_opt = G_define_option();
+ limit_per_cell_opt->key = "cell_limit";
+ limit_per_cell_opt->type = TYPE_INTEGER;
+ limit_per_cell_opt->multiple = NO;
+ limit_per_cell_opt->required = NO;
+ limit_per_cell_opt->label = _("Preserve only n points per grid cell");
+ limit_per_cell_opt->description =
+ _("Preserves only the given number of points per grid cell in grid-based decimation");
+ limit_per_cell_opt->guisection = _("Grid");
+
+ grid_decimation_flg = G_define_flag();
+ grid_decimation_flg->key = 'g';
+ grid_decimation_flg->description = _("Apply grid-based decimation");
+ grid_decimation_flg->guisection = _("Grid");
+
+ first_point_flg = G_define_flag();
+ first_point_flg->key = 'f';
+ first_point_flg->description =
+ _("Use only first point in grid cell during grid-based decimation");
+ first_point_flg->guisection = _("Grid");
+
+ cat_in_grid_flg = G_define_flag();
+ cat_in_grid_flg->key = 'c';
+ cat_in_grid_flg->description = _("Only one point per cat in grid cell");
+ cat_in_grid_flg->guisection = _("Grid");
+
+ use_z_flg = G_define_flag();
+ use_z_flg->key = 'z';
+ use_z_flg->description = _("Use z in grid decimation");
+ use_z_flg->guisection = _("Grid");
+
+ nocats_flag = G_define_flag();
+ nocats_flag->key = 'x';
+ nocats_flag->label =
+ _("Store only the coordinates, throw away categories");
+ nocats_flag->description =
+ _("Do not story any categories even if they are present in input data");
+ nocats_flag->guisection = _("Speed");
+
+ notopo_flag = G_define_standard_flag(G_FLG_V_TOPO);
+ notopo_flag->guisection = _("Speed");
+
+ /* here we have different decimations but also selections/filters */
+ G_option_required(skip_opt, preserve_opt, offset_opt, limit_opt,
+ grid_decimation_flg, zrange_opt, cats_opt, NULL);
+ /* this doesn't play well with GUI dialog unless we add defaults to options
+ * the default values would solve it but looks strange in the manual
+ * this we use explicit check in the code */
+ /* G_option_exclusive(skip_opt, preserve_opt, NULL); */
+ G_option_requires(grid_decimation_flg, first_point_flg,
+ limit_per_cell_opt, use_z_flg, zdiff_opt,
+ cat_in_grid_flg, NULL);
+ G_option_requires(first_point_flg, grid_decimation_flg, NULL);
+ G_option_requires(limit_per_cell_opt, grid_decimation_flg, NULL);
+ G_option_requires(use_z_flg, grid_decimation_flg, NULL);
+ G_option_requires(zdiff_opt, grid_decimation_flg, NULL);
+ G_option_requires(cat_in_grid_flg, grid_decimation_flg, NULL);
+ G_option_exclusive(zdiff_opt, first_point_flg, limit_per_cell_opt, NULL);
+
+ if (G_parser(argc, argv))
+ exit(EXIT_FAILURE);
+
+ Vect_check_input_output_name(map_opt->answer, voutput_opt->answer,
+ G_FATAL_EXIT);
+
+ if (Vect_open_old2(&vinput, map_opt->answer, "", field_opt->answer) < 0)
+ G_fatal_error(_("Unable to open vector map <%s>"), map_opt->answer);
+ int layer = Vect_get_field_number(&vinput, field_opt->answer);
+
+ if (layer < 1 && (cats_opt->answer || cat_in_grid_flg->answer))
+ G_fatal_error(_("Input layer must be set to a particular layer"
+ ", not <%s>, when using <%s> option or <-%c> flag"),
+ field_opt->answer, cats_opt->key, cat_in_grid_flg->key);
+
+ struct cat_list *allowed_cats = NULL;
+
+ if (layer > 0)
+ allowed_cats = Vect_cats_set_constraint(&vinput, layer, NULL,
+ cats_opt->answer);
+
+ struct line_pnts *line = Vect_new_line_struct();
+ struct line_cats *cats = Vect_new_cats_struct();
+
+ double zrange_min, zrange_max;
+ int use_zrange = FALSE;
+
+ if (zrange_opt->answer != NULL) {
+ if (zrange_opt->answers[0] == NULL || zrange_opt->answers[1] == NULL)
+ G_fatal_error(_("Invalid zrange <%s>"), zrange_opt->answer);
+ sscanf(zrange_opt->answers[0], "%lf", &zrange_min);
+ sscanf(zrange_opt->answers[1], "%lf", &zrange_max);
+ /* for convenience, switch order to make valid input */
+ if (zrange_min > zrange_max) {
+ double tmp = zrange_max;
+
+ zrange_max = zrange_min;
+ zrange_min = tmp;
+ }
+ use_zrange = TRUE;
+ }
+
+ int use_z = FALSE;
+ double zdiff;
+
+ if (use_z_flg->answer) {
+ use_z = TRUE;
+ zdiff = atof(zdiff_opt->answer);
+ }
+
+ /* z input checks */
+ if (!Vect_is_3d(&vinput)) {
+ if (use_z)
+ G_fatal_error(_("Cannot use z for decimation, input is not 3D"));
+ if (use_zrange)
+ G_fatal_error(_("Cannot select by z range, input is not 3D"));
+ }
+
+ int do_grid_decimation = FALSE;
+
+ if (grid_decimation_flg->answer)
+ do_grid_decimation = TRUE;
+ int limit_per_cell = 0;
+
+ if (limit_per_cell_opt->answer)
+ limit_per_cell = atof(limit_per_cell_opt->answer);
+ if (first_point_flg->answer)
+ limit_per_cell = 1;
+
+ /* when user enters 1 or zero e.g. for skip, we accept it and use it
+ * but the is no advantage, however, we count it as an error when
+ * no other options are selected
+ */
+ struct CountDecimationControl count_decimation_control;
+
+ count_decimation_init_from_str(&count_decimation_control,
+ skip_opt->answer, preserve_opt->answer,
+ offset_opt->answer, limit_opt->answer);
+ if (!count_decimation_is_valid(&count_decimation_control))
+ G_fatal_error(_("Settings for count-based decimation are not valid"));
+ /* TODO: implement count_decimation_is_invalid_reason() */
+ /* the following must be in sync with required options */
+ if (count_decimation_is_noop(&count_decimation_control) &&
+ !grid_decimation_flg->answer && !zrange_opt->answer &&
+ !cats_opt->answer)
+ G_fatal_error(_("Settings for count-based decimation would cause it"
+ " to do nothing and no other options has been set."));
+
+ struct Cell_head comp_region;
+ Rast_get_window(&comp_region);
+ if (use_zrange) {
+ comp_region.bottom = zrange_min;
+ comp_region.top = zrange_max;
+ }
+ struct GridDecimation grid_decimation;
+ struct DecimationContext decimation_context;
+ struct WriteContext write_context;
+
+ write_context.line = Vect_new_line_struct();
+ write_context.cats = Vect_new_cats_struct();
+ if (!nocats_flag->answer)
+ write_context.write_cats = TRUE;
+ else
+ write_context.write_cats = FALSE;
+ write_context.voutput = &voutput;
+ if (do_grid_decimation) {
+ grid_decimation_create_from_region(&grid_decimation, &comp_region);
+ grid_decimation.max_points = limit_per_cell;
+
+ if (cat_in_grid_flg->answer)
+ decimation_context.unique_cats = TRUE;
+ else
+ decimation_context.unique_cats = FALSE;
+ decimation_context.use_z = FALSE;
+ if (use_z) {
+ decimation_context.use_z = TRUE;
+ decimation_context.zdiff = zdiff;
+ }
+ grid_decimation.if_add_point = if_add_point;
+ grid_decimation.if_context = &decimation_context;
+
+ grid_decimation.on_add_point = on_add_point;
+ grid_decimation.on_context = &write_context;
+ }
+
+ if (Vect_open_new(&voutput, voutput_opt->answer, Vect_is_3d(&vinput)) < 0)
+ G_fatal_error(_("Unable to create vector map <%s>"),
+ voutput_opt->answer);
+
+ /* some constraints can be set on the map */
+ Vect_set_constraint_type(&vinput, GV_POINT);
+ /* noop for layer=-1 and non-native format, skips lines without cat */
+ Vect_set_constraint_field(&vinput, layer);
+ /* TODO: replace region checks by Vect_set_constraint_region? */
+
+ int ltype;
+ int cat;
+
+ while (TRUE) {
+ ltype = Vect_read_next_line(&vinput, line, cats);
+ if (ltype == -1)
+ G_fatal_error(_("Unable to read vector map"));
+ if (ltype == -2)
+ break; /* end of the map */
+
+ double x, y, z;
+ Vect_line_get_point(line, 0, &x, &y, &z);
+
+ /* selections/filters */
+ /* TODO: use region only when actually needed */
+ if (!use_zrange && !point_in_region_2d(&comp_region, x, y))
+ continue;
+ /* TODO: allow zrange to be used without region */
+ if (use_zrange && !point_in_region_3d(&comp_region, x, y, z))
+ continue;
+ if (allowed_cats &&
+ !Vect_cats_in_constraint(cats, layer, allowed_cats))
+ continue;
+
+ /* decimation */
+ if (count_decimation_is_out(&count_decimation_control))
+ continue;
+
+ /* TODO: test: skip points without category, unless layer=-1 */
+ /* Use cases:
+ * - all points have category (correct)
+ * - no categories for any point (correct, layer=-1 required)
+ * - some points miss category (not handled)
+ * Here we assume that only one cat has meaning for grid decimation.
+ * If no layer available, cat contains junk and shouldn't be used.
+ */
+ if (layer > 0)
+ Vect_cat_get(cats, layer, &cat);
+
+ /* using callback when using grid, direct call otherwise */
+ if (do_grid_decimation)
+ grid_decimation_try_add_point(&grid_decimation, cat, x, y, z,
+ cats);
+ else
+ write_point(&write_context, cat, x, y, z, cats);
+
+ if (count_decimation_is_end(&count_decimation_control))
+ break;
+ }
+
+ /* partially unnecessary as deallocated by the system */
+ Vect_destroy_line_struct(line);
+ Vect_destroy_cats_struct(cats);
+ Vect_destroy_line_struct(write_context.line);
+ Vect_destroy_cats_struct(write_context.cats);
+
+ Vect_hist_command(&voutput);
+
+ Vect_close(&vinput);
+ if (!notopo_flag->answer)
+ Vect_build(&voutput);
+ Vect_close(&voutput);
+
+ if (do_grid_decimation)
+ grid_decimation_destroy(&grid_decimation);
+
+ return EXIT_SUCCESS;
+}
Property changes on: grass/trunk/vector/v.decimate/main.c
___________________________________________________________________
Added: svn:mime-type
+ text/x-csrc
Added: svn:eol-style
+ native
Added: grass/trunk/vector/v.decimate/v.decimate.html
===================================================================
--- grass/trunk/vector/v.decimate/v.decimate.html (rev 0)
+++ grass/trunk/vector/v.decimate/v.decimate.html 2015-10-01 01:55:00 UTC (rev 66387)
@@ -0,0 +1,138 @@
+<h2>DESCRIPTION</h2>
+
+<em>v.decimate</em> reduces number of points in the input vector map
+and copies them over to the output vector map. Different point decimation
+techniques can be applied to reduce the number of points.
+
+<p>
+Two main decimation techniques are:
+<ul>
+<li>count-based decimation (<b>skip</b>, <b>preserve</b>, <b>offset</b>
+ and <b>limit</b> options)
+<li>grid-based decimation (<b>-g</b> flag)
+</ul>
+
+<p>
+The grid-based decimation will remove points based on:
+<ul>
+<li>similar z coordinates (<b>-z</b> flag and <b>zdiff</b> option)
+<li>same categories (<b>-c</b> flag)
+<li>count of points (<b>-f</b> flag and <b>cell_limit</b> option)
+</ul>
+
+<p>
+The grid-based decimation is currently using a 2D grid, so the points
+are placed and compared within this 2D grid. The comparison can happen
+using z coordinates or categories.
+Note that although the grid is only 2D, the module works with 3D points.
+
+<p>
+The grid-based decimation extent and resolution depend on the current
+computational region as set by <em><a href="g.region.html">g.region</a></em>.
+As a consequence, the output is limited only to computational region
+in this case.
+
+<p>
+TODO: Currently, any output is limited by the region.
+
+<p>
+The count-based decimation result highly depends on how the data are
+ordered in the input. This applies especially to <b>offset</b> and
+<b>limit</b> options where the resulting shape and densities can be
+surprising. The options <b>skip</b> and <b>preserve</b> are influenced
+by order of points in a similar way but they usually keep relative
+density of points (which may or may not be desired).
+On the other hand, the grid-based decimation will generally result in
+more even density of output points (see Figure 1).
+
+<p>
+Besides decimation, point count can be reduced by applying different
+selections or filters, these are:
+<ul>
+<li>selection by category (<b>cats</b> option)
+<li>selection by z values (<b>zrange</b> option)
+</ul>
+
+
+<h2>NOTES</h2>
+
+The grid-based decimation requires all points which will be saved in output
+to fit into the computer's memory (RAM).
+It is advantageous to have the region only in the area
+with the points, otherwise unnecessary memory is allocated.
+Higher (finer) resolutions and higher amount of preserved points
+per cell require more memory.
+The count-based decimation has no limitation regarding the available memory.
+
+<p>
+Significant speed up can be gained using <b>-b</b> flag which disables
+building of topology for the output vector map. This may limit the use
+of the vector map by some modules, but for example, this module works
+without topology as well.
+
+
+<h2>EXAMPLES</h2>
+
+Keep only every forth point, throw away the rest:
+
+<div class="code"><pre>
+v.decimate input=points_all output=points_decimated_every_4 preserve=4
+</pre></div>
+
+<p>
+Keep only points within a grid cell (given by the current computational
+region) which has unique categories (e.g. LIDAR classes):
+
+<div class="code"><pre>
+v.decimate input=points_all output=points_decimated_unique_cats layer=1 -g -c
+</pre></div>
+
+<center>
+ <img src="v_decimate_original.png">
+ <img src="v_decimate_count.png">
+ <img src="v_decimate_grid_cat.png">
+ <p><em>
+ Figure 1: Comparison of original points, decimation result
+ with every forth point preserved, and grid-based decimation
+ result with points with unique categories in each grid cell
+ </em></p>
+</center>
+
+<p>
+Keep only points with category 2 and keep only approximately 80% of the points:
+
+<div class="code"><pre>
+v.decimate input=points_all output=points_decimated_ skip=5 cats=2 layer=1
+</pre></div>
+
+<!--
+g.region map=elev_lid792_1m
+v.colors map=points_all use=cat rules=file.txt
+2 brown
+3:5 green
+6 red
+9 blue
+11 black
+13-14 gray
+d.vect map=points color=none width=1 icon=basic/point
+-->
+
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="v.extract.html">v.extract</a>,
+<a href="v.outlier.html">v.outlier</a>,
+<a href="v.select.html">v.select</a>,
+<a href="v.category.html">v.category</a>,
+<a href="v.build.html">v.build</a>,
+<a href="v.in.lidar.html">v.in.lidar</a>,
+<a href="g.region.html">g.region</a>
+</em>
+
+
+<h2>AUTHORS</h2>
+
+Vaclav Petras, <a href="http://geospatial.ncsu.edu/osgeorel/">NCSU OSGeoREL</a>
+
+<p><i>Last changed: $Date$</i>
Property changes on: grass/trunk/vector/v.decimate/v.decimate.html
___________________________________________________________________
Added: svn:mime-type
+ text/html
Added: svn:keywords
+ Author Date Id
Added: svn:eol-style
+ native
Added: grass/trunk/vector/v.decimate/v_decimate_count.png
===================================================================
(Binary files differ)
Property changes on: grass/trunk/vector/v.decimate/v_decimate_count.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/trunk/vector/v.decimate/v_decimate_grid_cat.png
===================================================================
(Binary files differ)
Property changes on: grass/trunk/vector/v.decimate/v_decimate_grid_cat.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/trunk/vector/v.decimate/v_decimate_original.png
===================================================================
(Binary files differ)
Property changes on: grass/trunk/vector/v.decimate/v_decimate_original.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
More information about the grass-commit
mailing list