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 module #2390

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -1727,8 +1727,8 @@ def sh_like_startup(location, location_name, grass_env_file, sh):
)
)

mask2d_test = "r.mask.status -t"
# 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
105 changes: 79 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-2024 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,73 @@ 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
*
* @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;
// The original mask values are overwritten, put back the original
// values, so that we can report them to the caller.
strcpy(name, "MASK");
strcpy(mapset, G_mapset());
}
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 sufficient 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 Name of the map's mapset
*
* @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) $(PARSONLIB)
DEPENDENCIES = $(MANAGEDEP) $(RASTERDEP) $(GISDEP)

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

default: cmd
184 changes: 184 additions & 0 deletions raster/r.mask.status/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/****************************************************************************
*
* MODULE: r.mask.status
* AUTHORS: Vaclav Petras
* PURPOSE: Report status of raster mask
* COPYRIGHT: (C) 2024 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/parson.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(_("mask"));
G_add_keyword(_("reclassification"));
module->label = _("Reports presence or absence of a raster mask");
module->description =
_("Provides information about present of a 2D raster mask"
" as text output or return code");

params->format = G_define_option();
params->format->key = "format";
params->format->type = TYPE_STRING;
params->format->required = NO;
params->format->answer = "plain";
params->format->options = "plain,json,bash,yaml";
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");
// suppress_required is not required given the default value for format.

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

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);

// This does not have to be exclusive with the printing, but perhaps there
// is a different boolean flag which does the return code and printing and
// this really behaves like the test utility facilitate the primary usage of
// this which is prompt building (there any output would be noise).
if (params->like_test->answer) {
if (present)
return 0;
return 1;
}

// Mask raster
char *full_mask = G_fully_qualified_name(name, mapset);
// Underlying raster if applicable
char *full_underlying = NULL;
if (is_mask_reclass)
full_underlying = G_fully_qualified_name(reclass_name, reclass_mapset);

if (strcmp(params->format->answer, "json") == 0) {
JSON_Value *root_value = json_value_init_object();
JSON_Object *root_object = json_object(root_value);
json_object_set_boolean(root_object, "present", present);
if (present)
json_object_set_string(root_object, "full_name", full_mask);
else
json_object_set_null(root_object, "full_name");
if (is_mask_reclass)
json_object_set_string(root_object, "is_reclass_of",
full_underlying);
else
json_object_set_null(root_object, "is_reclass_of");
char *serialized_string = json_serialize_to_string_pretty(root_value);
puts(serialized_string);
json_free_serialized_string(serialized_string);
json_value_free(root_value);
}
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)
printf("%s", full_mask);
printf("\nis_reclass_of=");
if (is_mask_reclass)
printf("%s", full_underlying);
printf("\n");
}
else if (strcmp(params->format->answer, "yaml") == 0) {
printf("present: ");
if (present)
printf("true");
else
printf("false");
printf("\nfull_name: ");
if (present)
printf("|-\n %s", full_mask);
else
printf("null");
// Null values in YAML can be an empty (no) value (rather than null),
// so we could use that.
printf("\nis_reclass_of: ");
// Using block scalar with |- to avoid need for escaping.
// Alternatively, we could check mapset naming limits against YAML
// escaping needs for different types of strings.
if (is_mask_reclass)
printf("|-\n %s", full_underlying);
else
printf("null");
// We could also produce true if is reclass, false otherwise.
// printf("\nmask_reclass: ");
// if (is_mask_reclass)
// printf("true");
// else
// printf("false");
// We could also outputting mask cats to inform user about the
// relevant portion of the map, but that should be done by accessing
// the actual mask anyway.
printf("\n");
}
else {
if (present)
printf(_("Mask is active"));
else
printf(_("Mask is not present"));
if (present) {
printf("\n");
printf(_("Mask name: %s"), full_mask);
}
if (is_mask_reclass) {
printf("\n");
printf(_("Mask is a raster reclassified from: %s"),
full_underlying);
}
printf("\n");
}

G_free(full_mask);
G_free(full_underlying);
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);
}
Loading
Loading