1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
/****************************************************************************
*
* 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 UNUSED)
{
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);
}
}
}
|