Skip to content

Commit

Permalink
r.grow.distance: add minimum and maximum distance options (#1453)
Browse files Browse the repository at this point in the history
* r.grow.distance: mindist must be smaller than maxdist
* r.grow.distance: update COPYRIGHT
 * explain result with both minimum_distance and maximum_distance

Co-authored-by: Markus Neteler <neteler@gmail.com>
  • Loading branch information
metzm and neteler committed Mar 22, 2021
1 parent 7869fa6 commit 78f45c4
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 18 deletions.
119 changes: 101 additions & 18 deletions raster/r.grow.distance/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
* AUTHOR(S): Marjorie Larson - CERL
* Glynn Clements
*
* PURPOSE: Generates a raster map layer with contiguous areas
* PURPOSE: Generates a raster map layer with contiguous areas
* grown by one cell.
*
* COPYRIGHT: (C) 2006-2013 by the GRASS Development Team
* COPYRIGHT: (C) 2006-2021 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
Expand Down Expand Up @@ -124,7 +124,7 @@ int main(int argc, char **argv)
struct GModule *module;
struct
{
struct Option *in, *dist, *val, *met;
struct Option *in, *dist, *val, *met, *min, *max;
} opt;
struct
{
Expand All @@ -140,8 +140,9 @@ int main(int argc, char **argv)
int row, col;
struct Colors colors;
struct History hist;
DCELL *out_row;
DCELL *out_row, *dist_row_max, *val_row_max;
double scale = 1.0;
double mindist, maxdist;
int invert;

G_gisinit(argv[0]);
Expand Down Expand Up @@ -175,6 +176,18 @@ int main(int argc, char **argv)
opt.met->options = "euclidean,squared,maximum,manhattan,geodesic";
opt.met->answer = "euclidean";

opt.min = G_define_option();
opt.min->key = "minimum_distance";
opt.min->type = TYPE_DOUBLE;
opt.min->required = NO;
opt.min->description = _("Minimum distance threshold");

opt.max = G_define_option();
opt.max->key = "maximum_distance";
opt.max->type = TYPE_DOUBLE;
opt.max->required = NO;
opt.max->description = _("Maximum distance threshold");

flag.m = G_define_flag();
flag.m->key = 'm';
flag.m->description = _("Output distances in meters instead of map units");
Expand All @@ -190,7 +203,43 @@ int main(int argc, char **argv)
dist_name = opt.dist->answer;
val_name = opt.val->answer;

if ((invert = flag.n->answer)) {
dist_row_max = val_row_max = NULL;
mindist = -1;
if (opt.min->answer) {
if (sscanf(opt.min->answer, "%lf", &mindist) != 1) {
G_warning(_("Invalid %s value '%s', ignoring."),
opt.min->key, opt.min->answer);

mindist = -1;
}
}

maxdist = -1;
if (opt.max->answer) {
if (sscanf(opt.max->answer, "%lf", &maxdist) != 1) {
G_warning(_("Invalid %s value '%s', ignoring."),
opt.max->key, opt.max->answer);

maxdist = -1;
}
}

if (mindist > 0 && maxdist > 0 && mindist >= maxdist) {
/* GTC error because given minimum_distance is not smaller than
* given maximum_distance */
G_fatal_error(_("'%s' must be smaller than '%s'."),
opt.min->key, opt.max->key);
}

if (mindist > 0 || maxdist > 0) {
dist_row_max = Rast_allocate_d_buf();
val_row_max = Rast_allocate_d_buf();
}

invert = flag.n->answer;
if (mindist <= 0 && maxdist <= 0 && invert) {
/* value output for distance to NULL cells makes sense
* if mindist or maxdist is given */
if (!dist_name)
G_fatal_error(_("Distance output is required for distance to NULL cells"));
if (val_name) {
Expand Down Expand Up @@ -224,7 +273,7 @@ int main(int argc, char **argv)
G_fatal_error(_("Unknown metric: '%s'"), opt.met->answer);

if (flag.m->answer) {
if (window.proj == PROJECTION_LL &&
if (window.proj == PROJECTION_LL &&
strcmp(opt.met->answer, "geodesic") != 0) {
G_fatal_error(_("Output distance in meters for lat/lon is only possible with '%s=%s'"),
opt.met->key, "geodesic");
Expand Down Expand Up @@ -265,7 +314,7 @@ int main(int argc, char **argv)

dist_row = Rast_allocate_d_buf();

if (dist_name && strcmp(opt.met->answer, "euclidean") == 0)
if ((mindist > 0 || maxdist > 0 || dist_name) && strcmp(opt.met->answer, "euclidean") == 0)
out_row = Rast_allocate_d_buf();
else
out_row = dist_row;
Expand Down Expand Up @@ -349,21 +398,55 @@ int main(int argc, char **argv)
for (col = ncols - 1; col >= 0; col--)
check(row, col, 1, 0);

if (dist_name) {
if (out_row != dist_row)
for (col = 0; col < ncols; col++)
out_row[col] = sqrt(dist_row[col]);
if (mindist > 0 || maxdist > 0) {
/* do not modify dist_row or new_val_row,
* thus copy */
if (out_row != dist_row) {
for (col = 0; col < ncols; col++) {
dist_row_max[col] = sqrt(dist_row[col]);
}
}
else {
for (col = 0; col < ncols; col++) {
dist_row_max[col] = dist_row[col];
}
}
for (col = 0; col < ncols; col++) {
if (scale != 1.0)
dist_row_max[col] *= scale;

val_row_max[col] = new_val_row[col];

if (mindist > 0 && dist_row_max[col] < mindist) {
Rast_set_d_null_value(&dist_row_max[col], 1);
Rast_set_d_null_value(&val_row_max[col], 1);
}
if (maxdist > 0 && dist_row_max[col] > maxdist) {
Rast_set_d_null_value(&dist_row_max[col], 1);
Rast_set_d_null_value(&val_row_max[col], 1);
}
}
if (dist_name)
Rast_put_d_row(dist_fd, dist_row_max);
if (val_name)
Rast_put_d_row(val_fd, val_row_max);
}
else {
if (dist_name) {
if (out_row != dist_row)
for (col = 0; col < ncols; col++)
out_row[col] = sqrt(dist_row[col]);

if (scale != 1.0)
for (col = 0; col < ncols; col++)
out_row[col] *= scale;
if (scale != 1.0)
for (col = 0; col < ncols; col++)
out_row[col] *= scale;

Rast_put_d_row(dist_fd, out_row);
Rast_put_d_row(dist_fd, out_row);
}
if (val_name)
Rast_put_d_row(val_fd, new_val_row);
}

if (val_name)
Rast_put_d_row(val_fd, new_val_row);

swap_rows();
}

Expand Down
15 changes: 15 additions & 0 deletions raster/r.grow.distance/r.grow.distance.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,21 @@ <h2>NOTES</h2>
to use it along with the <em>-m</em> flag in order to output
distances in meters instead of map units.

<p>
If <b>minimum_distance</b> is given, all cells with a distance smaller
than <b>minimum_distance</b> will be set to NULL.

<p>
If <b>maximum_distance</b> is given, all cells with a distance larger
than <b>maximum_distance</b> will be set to NULL. The resultant output
is equivalent to a buffer.

<p>
If both <b>minimum_distance</b> and <b>maximum_distance</b> are given,
the result will be similar to a doughnut, a restricted belt for a
given distance range. All cells outside this distance range will be set
to NULL.

<h2>EXAMPLES</h2>

<h3>Distance from the streams network</h3>
Expand Down

0 comments on commit 78f45c4

Please sign in to comment.