Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

r.mask.status: Check mask status through a tool #2390

Merged
merged 25 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
dd39de1
r.mask.status: Check mask status through module
wenzeslaus May 20, 2022
d88dd02
Add a new mask info/status function and add doc for the file.
wenzeslaus May 20, 2022
c92ae7f
Provide all information about the possible reclass with the API and t…
wenzeslaus May 20, 2022
ac64423
Merge remote-tracking branch 'upstream/main' into r_mask_status
neteler Nov 7, 2023
62c83b7
Merge branch 'main' into r_mask_status
echoix Sep 9, 2024
f84b041
Apply suggestions from code review
echoix Sep 9, 2024
8994d40
Apply suggestions from code review
echoix Sep 9, 2024
c7e55b6
Merge remote-tracking branch 'upstream/main' into r_mask_status
wenzeslaus Sep 24, 2024
ac83e11
Use parson for the JSON output
wenzeslaus Sep 24, 2024
b22c85b
Use lib function to get full name
wenzeslaus Sep 25, 2024
1f2fcdc
Make all three formats work in a similar way
wenzeslaus Sep 25, 2024
99929c8
Limit mask name hardcoding to the library. Polish comments.
wenzeslaus Sep 26, 2024
caad7ea
Add missing space
wenzeslaus Sep 26, 2024
cc53fb8
Add examples
wenzeslaus Sep 26, 2024
f522e5a
Add tests
wenzeslaus Sep 27, 2024
c68e41f
Add plain text output (YAML is not translatable and plain text is 'pl…
wenzeslaus Sep 27, 2024
2841aeb
Add test for return code
wenzeslaus Sep 27, 2024
3480a25
Add doc, optimize name reporting
wenzeslaus Oct 11, 2024
fd8d76c
Add more doc
wenzeslaus Oct 11, 2024
50a5f42
For now, use shell, not bash for format
wenzeslaus Oct 11, 2024
c8c9696
Merge remote-tracking branch 'upstream/main' into r_mask_status
wenzeslaus Oct 11, 2024
5f31745
For now, use shell, not bash for format
wenzeslaus Oct 11, 2024
2922763
Comment clean up
wenzeslaus Oct 11, 2024
7822abd
Fix typo
wenzeslaus Oct 11, 2024
12061b4
Remove parentheses for fixture without parameters
wenzeslaus Oct 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/grass/defs/raster.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ int Rast_option_to_interp_type(const struct Option *);

/* mask_info.c */
char *Rast_mask_info(void);
bool Rast_mask_status(char *, char *, bool *, char *, char *);
int Rast__mask_info(char *, char *);

/* maskfd.c */
Expand Down
2 changes: 1 addition & 1 deletion lib/init/grass.py
Original file line number Diff line number Diff line change
Expand Up @@ -1728,8 +1728,8 @@
)
)

mask2d_test = 'r.mask.status -t'

Check failure on line 1731 in lib/init/grass.py

View workflow job for this annotation

GitHub Actions / Python Code Quality Checks (ubuntu-22.04)

Ruff (Q000)

lib/init/grass.py:1731:19: Q000 Single quotes found but double quotes preferred
# TODO: have a function and/or module to test this
mask2d_test = 'test -f "$MAPSET_PATH/cell/MASK"'
mask3d_test = 'test -d "$MAPSET_PATH/grid3/RASTER3D_MASK"'

specific_addition = ""
Expand Down
101 changes: 75 additions & 26 deletions lib/raster/mask_info.c
Original file line number Diff line number Diff line change
@@ -1,37 +1,33 @@
/*
*************************************************************
* char * Rast_mask_info ()
/**
* \file lib/raster/mask_info.c
*
* returns a printable text of mask information
* \brief Raster Library - Get mask information
*
************************************************************
* Rast__mask_info (name, mapset)
* (C) 1999-2022 by Vaclav Petras and the GRASS Development Team
*
* char name[GNAME_MAX], mapset[GMAPSET_MAX];
* This program is free software under the GNU General Public
* License (>=v2). Read the file COPYING that comes with GRASS
* for details.
*
* function:
* determine the status off the automatic masking
* and the name of the cell file which forms the mask
*
* (the mask file is actually MASK in the current mapset,
* but is usually a reclassed cell file, and the reclass
* name and mapset are returned)
*
* returns:
* -1 no masking (name, mapset undefined)
* name, mapset are undefined
*
* 1 mask file present, masking on
* name, mapset hold mask file name, mapset
*
***************************************************************/
* \author CERL
* \author Vaclav Petras, NC State University, Center for Geospatial Analytics
*/

#include <string.h>

#include <grass/gis.h>
#include <grass/raster.h>
#include <grass/glocale.h>

/**
* @brief Get a printable text with information about raster mask
*
* Determines if 2D raster mask is present and returns textual information about
* the mask suitable for end-user display. The resulting text is translated.
* Caller is responsible for freeing the memory of the returned string.
*
* @return New string with textual information
*/
char *Rast_mask_info(void)
{
char text[GNAME_MAX + GMAPSET_MAX + 16];
Expand All @@ -53,16 +49,69 @@ char *Rast_mask_info(void)
return G_store(text);
}

/**
* @brief Get raster mask status information
*
* @param[out] name Name of the raster map used as mask
* @param[out] mapset Mapset name of the map
* @param[out] is_mask_reclass True, if MASK raster is a reclass
*
wenzeslaus marked this conversation as resolved.
Show resolved Hide resolved
* @return true if mask is present, false otherwise
*/
bool Rast_mask_status(char *name, char *mapset, bool *is_mask_reclass,
char *reclass_name, char *reclass_mapset)
{
int present = Rast__mask_info(name, mapset);

if (is_mask_reclass && reclass_name && reclass_mapset) {
if (present) {
*is_mask_reclass = Rast_is_reclass("MASK", G_mapset(), reclass_name,
reclass_mapset) > 0;
}
else {
*is_mask_reclass = false;
}
}

if (present == 1)
return true;
else
return false;
}

/**
* @brief Get information about the current mask
*
* Determines the status of the automatic masking and the name of the 2D
* raster which forms the mask. Typically, mask is raster called MASK in the
* current mapset, but when used with r.mask, it is usually a reclassed
* raster, and so when a MASK raster is present and it is a reclass raster,
* the name and mapset of the underlying reclassed raster are returned.
*
* The name and mapset is written to the parameter which need to be defined
* with a suffient size, least as `char name[GNAME_MAX], mapset[GMAPSET_MAX]`.
*
* When the masking is not active, -1 is returned and name and mapset are
* undefined. When the masking is active, 1 is returned and name and mapset
* will hold the name and mapset of the underlying raster.
*
* @param[out] name Name of the raster map used as mask
* @param[out] mapset Mapset name of the map
*
* @return 1 if mask is present, -1 otherwise
*/
int Rast__mask_info(char *name, char *mapset)
{
char rname[GNAME_MAX], rmapset[GMAPSET_MAX];

strcpy(name, "MASK");
strcpy(mapset, G_mapset());
strcpy(rname, "MASK");
strcpy(rmapset, G_mapset());

if (!G_find_raster(name, mapset))
if (!G_find_raster(rname, rmapset))
return -1;

strcpy(name, rname);
strcpy(mapset, rmapset);
if (Rast_is_reclass(name, mapset, rname, rmapset) > 0) {
strcpy(name, rname);
strcpy(mapset, rmapset);
Expand Down
1 change: 1 addition & 0 deletions raster/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ SUBDIRS = \
r.lake \
r.li \
r.mapcalc \
r.mask.status \
r.mfilter \
r.mode \
r.neighbors \
Expand Down
10 changes: 10 additions & 0 deletions raster/r.mask.status/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
MODULE_TOPDIR = ../..

PGM = r.mask.status

LIBES = $(MANAGELIB) $(RASTERLIB) $(GISLIB)
DEPENDENCIES = $(MANAGEDEP) $(RASTERDEP) $(GISDEP)

include $(MODULE_TOPDIR)/include/Make/Module.make

default: cmd
168 changes: 168 additions & 0 deletions raster/r.mask.status/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/****************************************************************************
*
* MODULE: r.mask.status
* AUTHORS: Vaclav Petras
* PURPOSE: Report status of raster mask
* COPYRIGHT: (C) 2022 by Vaclav Petras and 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.
*
*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <grass/gis.h>
#include <grass/raster.h>
#include <grass/glocale.h>

struct Parameters {
struct Option *format;
struct Flag *like_test;
};

void parse_parameters(struct Parameters *params, int argc, char **argv)
{
struct GModule *module;

module = G_define_module();
G_add_keyword(_("raster"));
G_add_keyword(_("reclassification"));
module->label = _("Reclassify raster map based on category values.");
module->description =
_("Creates a new raster map whose category values are based "
"upon a reclassification of the categories in an existing "
"raster map.");

params->format = G_define_option();
params->format->key = "format";
params->format->type = TYPE_STRING;
params->format->required = NO;
params->format->answer = "yaml";
params->format->options = "yaml,json,bash";
params->format->description = _("Format for reporting");

params->like_test = G_define_flag();
params->like_test->key = 't';
params->like_test->label =
_("Return code 0 when mask present, 1 otherwise");
params->like_test->description =
_("Behave like the test utility, 0 for true, 1 for false, no output");
//flags.like_test->guisection = _("");
// suppress_required
echoix marked this conversation as resolved.
Show resolved Hide resolved

if (G_parser(argc, argv))
exit(EXIT_FAILURE);
}

char *min_json_escape(const char *str)
{
char *tmp1 = G_str_replace(str, "\\", "\\\\");
char *tmp2 = G_str_replace(tmp1, "\"", "\\\"");

G_free(tmp1);
return tmp2;
}

void json_print_name_mapset(const char *name, const char *mapset)
{
// Being paranoid about what is in the name.
char *escaped_name = min_json_escape(name);
char *escaped_mapset = min_json_escape(mapset);

printf("\"%s@%s\"", name, mapset);
G_free(escaped_name);
G_free(escaped_mapset);
}

int report_status(struct Parameters *params)
{

char name[GNAME_MAX];
char mapset[GMAPSET_MAX];
char reclass_name[GNAME_MAX];
char reclass_mapset[GMAPSET_MAX];

bool is_mask_reclass;
bool present =
Rast_mask_status(name, mapset, &is_mask_reclass, reclass_name, reclass_mapset);
// bool present = Rast_mask_present(name, mapset); // This would check the map presence rather than the automasking state in the library.
echoix marked this conversation as resolved.
Show resolved Hide resolved

// printf("%s", Rast_mask_info());

if (params->like_test->answer) {
if (present)
return 0;
else
return 1;
}
else if (strcmp(params->format->answer, "json") == 0) {
printf("{\"present\":");
if (present)
printf("true");
else
printf("false");
printf(",\n\"full_name\":");
if (present)
json_print_name_mapset("MASK", G_mapset()); // Too much mask details here, move this to the library.
echoix marked this conversation as resolved.
Show resolved Hide resolved
else
printf("null");
printf(",\n\"is_reclass_of\": ");
if (is_mask_reclass)
json_print_name_mapset(name, mapset);
else
printf("null");
printf("}\n");
}
else if (strcmp(params->format->answer, "bash") == 0) {
printf("present=");
if (present)
printf("1"); // Good choice here or not?
else
printf("0");
printf("\nfull_name=");
if (present) {
json_print_name_mapset(name, mapset);
}
printf("\n");
}
else {
printf("present: ");
if (present)
printf("true");
else
printf("false");
printf("\nfull_name: ");
if (present)
printf("|-\n MASK@%s", G_mapset()); // MASK or MASK@current_mapset
else
printf("null");
printf("\nis_reclass_of: ");
// Using block scalar with |- to avoid need for escaping.
if (is_mask_reclass)
printf("|-\n %s@%s", name, mapset);
else
printf("null");
// true if MASK in current mapset and is reclass, false otherwise,
// then also outputting mask cats is needed to inform user about the portion of the map
// printf("\nmask_reclass: ");
// if (is_mask_reclass)
wenzeslaus marked this conversation as resolved.
Show resolved Hide resolved
// printf("true");
// else
// printf("false");
printf("\n");
}
return EXIT_SUCCESS;
}

int main(int argc, char **argv)
{
struct Parameters params;

G_gisinit(argv[0]);
parse_parameters(&params, argc, argv);
return report_status(&params);
}
35 changes: 35 additions & 0 deletions raster/r.mask.status/r.mask.status.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<h2>DESCRIPTION</h2>

<em>r.mask.status</em> reports presence or absence of a raster mask.

<h2>NOTES</h2>

<h2>EXAMPLES</h2>

<h3>Generate JSON output</h3>

<div class="code"><pre>
r.mask.status format=json
</pre></div>

<h3>Use as the test utility</h3>

The POSIX <em>test</em> utility uses return code 0 to indicate true
and 1 to indicate false, so testing existence of a file with <code>test -f</code>
gives return code 0 when the file exists. <em>r.mask.status</em> can be used
in the same with the the <b>-t</b> flag:

<div class="code"><pre>
r.mask.status -t
</pre></div>

<h2>SEE ALSO</h2>

<em>
<a href="r.mask.html">r.mask</a>,
<a href="g.region.html">g.region</a>
</em>

<h2>AUTHORS</h2>

Vaclav Petras, NC State University, Center for Geospatial Analytics
Loading