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.report: add JSON support #3935

Merged
merged 17 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion raster/r.report/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ MODULE_TOPDIR = ../..

PGM = r.report

LIBES = $(RASTERLIB) $(GISLIB)
LIBES = $(RASTERLIB) $(GISLIB) $(PARSONLIB)
DEPENDENCIES = $(RASTERDEP) $(GISDEP)

include $(MODULE_TOPDIR)/include/Make/Module.make
Expand Down
11 changes: 11 additions & 0 deletions raster/r.report/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#endif

#include <grass/raster.h>
#include <grass/parson.h>

#define SORT_DEFAULT 0
#define SORT_ASC 1
Expand Down Expand Up @@ -52,6 +53,8 @@ extern int nunits;
#define DEFAULT_PAGE_LENGTH "0"
#define DEFAULT_PAGE_WIDTH "79"

enum OutputFormat { PLAIN, JSON };

extern int page_width;
extern int page_length;
extern int masking;
Expand All @@ -67,6 +70,7 @@ extern char *stats_file;
extern char *no_data_str;
extern int stats_flag;
extern int nsteps, cat_ranges, as_int;
extern enum OutputFormat format;
extern int *is_fp;
extern DCELL *DMAX, *DMIN;

Expand Down Expand Up @@ -105,13 +109,20 @@ int parse_layer(char *);
int match(char *, char *, int);

/* prt_report.c */
int compute_unit_format(int, int, enum OutputFormat);
int print_report(int, int);
int construct_val_str(int, CELL *, char *);
char *construct_cat_label(int, CELL);

/* prt_unit.c */
int print_unit(int, int, int);

/* prt_json.c */
JSON_Value *make_units(int, int);
JSON_Value *make_category(int, int, JSON_Value *);
JSON_Value *make_categories(int, int, int);
void print_json();

/* report.c */
int report(void);

Expand Down
2 changes: 2 additions & 0 deletions raster/r.report/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ int maskfd;
CELL *mask;
CELL NULL_CELL;

enum OutputFormat format;

char fs[2];
struct Categories *labels;

Expand Down
11 changes: 11 additions & 0 deletions raster/r.report/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ int parse_command_line(int argc, char *argv[])
struct Option *nv;
struct Option *nsteps;
struct Option *sort;
struct Option *format;
} parms;
struct {
struct Flag *f;
Expand Down Expand Up @@ -103,6 +104,9 @@ int parse_command_line(int argc, char *argv[])
_("Sort by cell counts in descending order"));
parms.sort->guisection = _("Formatting");

parms.format = G_define_standard_option(G_OPT_F_FORMAT);
parms.format->guisection = _("Formatting");

flags.h = G_define_flag();
flags.h->key = 'h';
flags.h->description = _("Suppress page headers");
Expand Down Expand Up @@ -172,6 +176,13 @@ int parse_command_line(int argc, char *argv[])
cat_ranges = flags.C->answer;
as_int = flags.i->answer;

if (strcmp(parms.format->answer, "json") == 0) {
format = JSON;
}
else {
format = PLAIN;
}

for (i = 0; parms.cell->answers[i]; i++)
parse_layer(parms.cell->answers[i]);
if (parms.units->answers)
Expand Down
186 changes: 186 additions & 0 deletions raster/r.report/prt_json.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#include <stdio.h>
#include <string.h>
#include "global.h"
#include <grass/parson.h>
#include <grass/glocale.h>

JSON_Value *make_units(int ns, int nl)
{
JSON_Value *units_value = json_value_init_array();
JSON_Array *units_array = json_array(units_value);
for (int i = 0; i < nunits; i++) {
int _ns = ns;

JSON_Value *unit_value = json_value_init_object();
JSON_Object *unit_object = json_object(unit_value);

if (unit[i].type == CELL_COUNTS) {
json_object_set_string(unit_object, "unit", "cell counts");
json_object_set_number(unit_object, "value", count_sum(&_ns, nl));
}
else if (unit[i].type == PERCENT_COVER) {
json_object_set_string(unit_object, "unit", "% cover");
int k = ns - 1;
while (k >= 0 && same_cats(k, ns, nl - 1))
k--;
k++;
double area = area_sum(&k, nl - 1);
area = 100.0 * area_sum(&_ns, nl) / area;
json_object_set_number(unit_object, "value", area);
}
else {
char *unit_name = NULL;
if (unit[i].type == ACRES) {
unit_name = "acres";
}
else if (unit[i].type == HECTARES) {
unit_name = "hectares";
}
else if (unit[i].type == SQ_MILES) {
unit_name = "square miles";
}
else if (unit[i].type == SQ_METERS) {
unit_name = "square meters";
}
else if (unit[i].type == SQ_KILOMETERS) {
unit_name = "square kilometers";
}
json_object_set_string(unit_object, "unit", unit_name);
json_object_set_number(unit_object, "value",
area_sum(&_ns, nl) * unit[i].factor);
}
json_array_append_value(units_array, unit_value);
}
return units_value;
}

JSON_Value *make_category(int ns, int nl, JSON_Value *sub_categories)
kritibirda26 marked this conversation as resolved.
Show resolved Hide resolved
{
JSON_Value *object_value = json_value_init_object();
JSON_Object *object = json_object(object_value);

CELL *cats = Gstats[ns].cats;
json_object_set_number(object, "category", cats[nl]);

DCELL dLow, dHigh;

if (!is_fp[nl] || as_int)
kritibirda26 marked this conversation as resolved.
Show resolved Hide resolved
json_object_set_string(object, "label",
Rast_get_c_cat(&cats[nl], &layers[nl].labels));
else {
/* find or construct the label for floating point range to print */
if (Rast_is_c_null_value(&cats[nl]))
json_object_set_null(object, "label");
else if (cat_ranges) {
json_object_set_string(object, "label",
Rast_get_ith_d_cat(&layers[nl].labels,
cats[nl], &dLow, &dHigh));
}
else {
dLow = (DMAX[nl] - DMIN[nl]) / (double)nsteps *
(double)(cats[nl] - 1) +
DMIN[nl];
dHigh = (DMAX[nl] - DMIN[nl]) / (double)nsteps * (double)cats[nl] +
DMIN[nl];

json_object_set_string(object, "label", "from to");

JSON_Value *range_value = json_value_init_object();
JSON_Object *range_object = json_object(range_value);
json_object_set_number(range_object, "from", dLow);
json_object_set_number(range_object, "to", dHigh);
json_object_set_value(object, "range", range_value);
}
}

JSON_Value *units_value = make_units(ns, nl);
json_object_set_value(object, "units", units_value);

if (sub_categories != NULL) {
json_object_set_value(object, "categories", sub_categories);
}
return object_value;
}

JSON_Value *make_categories(int start, int end, int level)
{
JSON_Value *array_value = json_value_init_array();
JSON_Array *array = json_array(array_value);
if (level == nlayers - 1) {
for (int i = start; i < end; i++) {
JSON_Value *category = make_category(i, level, NULL);
json_array_append_value(array, category);
}
}
else {
while (start < end) {
int curr = start;
while ((curr < end) && same_cats(start, curr, level)) {
curr++;
}
JSON_Value *sub_categories =
make_categories(start, curr, level + 1);
JSON_Value *category = make_category(start, level, sub_categories);
json_array_append_value(array, category);
start = curr;
}
}
return array_value;
}

void print_json()
{
compute_unit_format(0, nunits - 1, JSON);

JSON_Value *root_value = json_value_init_object();
JSON_Object *root_object = json_object(root_value);

json_object_set_string(root_object, "location", G_location());
json_object_set_string(root_object, "created", G_date());

JSON_Value *region_value = json_value_init_object();
JSON_Object *region_object = json_object(region_value);
json_object_set_number(region_object, "north", window.north);
json_object_set_number(region_object, "south", window.south);
json_object_set_number(region_object, "east", window.east);
json_object_set_number(region_object, "west", window.west);
json_object_set_number(region_object, "ew_res", window.ew_res);
json_object_set_number(region_object, "ns_res", window.ns_res);
json_object_set_value(root_object, "region", region_value);

char *mask = maskinfo();
if (strcmp(mask, "none") == 0) {
json_object_set_null(root_object, "mask");
}
else {
json_object_set_string(root_object, "mask", mask);
}

JSON_Value *maps_value = json_value_init_array();
JSON_Array *maps_array = json_array(maps_value);
for (int i = 0; i < nlayers; i++) {
JSON_Value *map_value = json_value_init_object();
JSON_Object *map_object = json_object(map_value);
json_object_set_string(map_object, "name", layers[i].name);
json_object_set_string(map_object, "description", layers[i].mapset);
json_object_set_string(map_object, "layer", layers[i].name);
json_object_set_string(map_object, "type", "raster");
json_array_append_value(maps_array, map_value);
}
json_object_set_value(root_object, "maps", maps_value);

JSON_Value *root_categories_value = make_categories(0, nstats, 0);
json_object_set_value(root_object, "categories", root_categories_value);

JSON_Value *totals = make_units(0, -1);
json_object_set_value(root_object, "totals", totals);

char *serialized_string = NULL;
serialized_string = json_serialize_to_string_pretty(root_value);
if (serialized_string == NULL) {
G_fatal_error(_("Failed to initialize pretty JSON string."));
}
puts(serialized_string);
json_free_serialized_string(serialized_string);
json_value_free(root_value);
}
67 changes: 43 additions & 24 deletions raster/r.report/prt_report.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,49 @@
#include <grass/raster.h>
#include "global.h"

int print_report(int unit1, int unit2)
int compute_unit_format(int unit1, int unit2, enum OutputFormat format)
{
int ns, nl, nx;
int i, ns, len;
char num[100];
int len, new;
CELL *cats, *prev;
int first;
int i;
int divider_level;
int after_header;
int need_format;
int with_stats;
char *cp;
int spacing;
char dot;

/* examine units, determine output format */
for (i = unit1; i <= unit2; i++) {
need_format = 1;
if (format == PLAIN) {
need_format = 1;
}
else {
need_format = 0;
}
unit[i].label[0] = "";
unit[i].label[1] = "";

switch (unit[i].type) {
case CELL_COUNTS:
need_format = 0;
unit[i].len = 5;
unit[i].label[0] = " cell";
unit[i].label[1] = "count";
ns = 0;
sprintf(num, "%ld", count_sum(&ns, -1));
len = strlen(num);
if (len > unit[i].len)
unit[i].len = len;

if (need_format) {
need_format = 0;
unit[i].len = 5;
ns = 0;
sprintf(num, "%ld", count_sum(&ns, -1));
len = strlen(num);
if (len > unit[i].len)
unit[i].len = len;
}
break;

case PERCENT_COVER:
need_format = 0;
unit[i].dp = 2;
unit[i].len = 6;
unit[i].label[0] = " % ";
unit[i].label[1] = "cover";
unit[i].eformat = 0;

if (need_format) {
need_format = 0;
unit[i].dp = 2;
unit[i].len = 6;
unit[i].eformat = 0;
}
break;

case SQ_METERS:
Expand Down Expand Up @@ -90,6 +91,24 @@ int print_report(int unit1, int unit2)
&unit[i].dp, &(unit[i].eformat), e_format);
}
}
}

int print_report(int unit1, int unit2)
{
int ns, nl, nx;
char num[100];
int len, new;
CELL *cats, *prev;
int first;
int i;
int divider_level;
int after_header;
int with_stats;
char *cp;
int spacing;
char dot;

compute_unit_format(unit1, unit2, PLAIN);

/* figure out how big the category numbers are when printed */
for (nl = 0; nl < nlayers; nl++)
Expand Down
Loading
Loading