Skip to content
Open
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
4 changes: 2 additions & 2 deletions raster/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ build_program_in_subdir(
grass_bitmap
${LIBM})

build_program_in_subdir(r.geomorphon DEPENDS grass_gis grass_raster grass_gmath
${LIBM})
build_program_in_subdir(r.geomorphon DEPENDS grass_gis grass_raster grass_parson
grass_gmath ${LIBM})

build_program_in_subdir(r.grow.distance DEPENDS grass_gis grass_raster ${LIBM})

Expand Down
4 changes: 2 additions & 2 deletions raster/r.geomorphon/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ MODULE_TOPDIR = ../..

PGM = r.geomorphon

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

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

Expand Down
142 changes: 113 additions & 29 deletions raster/r.geomorphon/profile.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <stdio.h>
#include "local_proto.h"
#include <grass/gjson.h>

#define JSON_MIN_INDENT 1
#define YAML_MIN_INDENT 0
Expand Down Expand Up @@ -251,45 +252,128 @@ static const char *format_token_common(const struct token *t)
*/
static unsigned write_json(FILE *f)
{
unsigned i, indent = JSON_MIN_INDENT;
unsigned i;
G_JSON_Value *stack_vals[MAX_STACK_ELEMS];
unsigned stack_top = 0;
G_JSON_Value *root = G_json_value_init_object();
if (!root)
return 0;
stack_vals[stack_top++] = root;

WRITE_VAL(f, "%s\n", "{");
for (i = 0; i < size; i++) {
const char *val;

/* Add a comma unless there is no data tokens immediately after. */
const char *comma =
(i + 1 == size) || (i + 1 < size && token[i + 1].type == T_ESO)
? ""
: ",";
G_JSON_Object *parent = G_json_object(stack_vals[stack_top - 1]);
if (!parent) {
G_json_value_free(root);
return 0;
}

switch (token[i].type) {
case T_SSO:
WRITE_INDENT(f, indent);
indent++;
WRITE_VAL(f, "\"%s\": {\n", token[i].key);
continue;
case T_SSO: {
if (stack_top >= MAX_STACK_ELEMS) {
G_json_value_free(root);
return 0;
}
G_JSON_Value *obj = G_json_value_init_object();
if (!obj) {
G_json_value_free(root);
return 0;
}
if (G_json_object_set_value(parent, token[i].key, obj) !=
G_JSONSuccess) {
G_json_value_free(obj);
G_json_value_free(root);
return 0;
}
stack_vals[stack_top++] = obj;
} break;
case T_ESO:
if (indent == JSON_MIN_INDENT)
if (stack_top <= 1) {
/* can't pop root */
G_json_value_free(root);
return 0;
indent--;
WRITE_INDENT(f, indent);
WRITE_VAL(f, "}%s\n", comma);
continue;
default:
val = quote_val(token[i].type, format_token_common(token + i));
}
stack_top--;
break;
}
if (!val)
case T_BLN:
if (G_json_object_set_boolean(parent, token[i].key,
token[i].int_val ? 1 : 0) !=
G_JSONSuccess) {
G_json_value_free(root);
return 0;
}
break;
case T_INT:
if (G_json_object_set_number(parent, token[i].key,
(double)token[i].int_val) !=
G_JSONSuccess) {
G_json_value_free(root);
return 0;
}
break;
case T_DBL:
if (isnan(token[i].dbl_val)) {
if (G_json_object_set_null(parent, token[i].key) !=
G_JSONSuccess) {
G_json_value_free(root);
return 0;
}
}
else {
if (G_json_object_set_number(parent, token[i].key,
token[i].dbl_val) !=
G_JSONSuccess) {
G_json_value_free(root);
return 0;
}
}
break;
case T_MTR:
if (isnan(token[i].dbl_val)) {
if (G_json_object_set_null(parent, token[i].key) !=
G_JSONSuccess) {
G_json_value_free(root);
return 0;
}
}
else {
if (G_json_object_set_number(parent, token[i].key,
token[i].dbl_val) !=
G_JSONSuccess) {
G_json_value_free(root);
return 0;
}
}
break;
case T_STR:
if (G_json_object_set_string(parent, token[i].key,
token[i].str_val) != G_JSONSuccess) {
G_json_value_free(root);
return 0;
}
break;
default:
G_json_value_free(root);
return 0;
WRITE_INDENT(f, indent);
WRITE_VAL(f, "\"%s\": ", token[i].key);
WRITE_VAL(f, "%s", val);
WRITE_VAL(f, "%s\n", comma);
}
}
if (indent != JSON_MIN_INDENT || overflow)

if (stack_top != 1 || overflow) {
G_json_value_free(root);
return 0;
WRITE_VAL(f, "%s\n", "}");
}

char *s = G_json_serialize_to_string_pretty(root);
if (!s) {
G_json_value_free(root);
return 0;
}
if (fprintf(f, "%s\n", s) < 0) {
G_json_free_serialized_string(s);
G_json_value_free(root);
return 0;
}
G_json_free_serialized_string(s);
G_json_value_free(root);
return 1;
}

Expand Down
40 changes: 40 additions & 0 deletions raster/r.geomorphon/testsuite/test_r_geom.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
from grass.gunittest.case import TestCase
from grass.gunittest.main import test
from grass.script.core import read_command
import json
import os
from grass.script import core as gcore
import tempfile
import pathlib

synth_out = """1 flat
3 ridge
Expand Down Expand Up @@ -78,6 +83,41 @@ def test_sint(self):
category = read_command("r.category", map=self.outsint)
self.assertEqual(first=synth_out, second=category)

def test_profile_json(self):
# ensure region is set to the test elevation
self.runModule("g.region", raster=self.inele)
region = gcore.region()
east = float(region.get("east", region["e"]))
west = float(region.get("west", region["w"]))
north = float(region.get("north", region["n"]))
south = float(region.get("south", region["s"]))
e = (east + west) / 2.0
n = (north + south) / 2.0
fd, tmp = tempfile.mkstemp(prefix="rgeom_profile_", suffix=".json")
os.close(fd)
Comment on lines +96 to +97
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you creating it here?

try:
self.runModule(
"r.geomorphon",
elevation=self.inele,
search=3,
profiledata=tmp,
profileformat="json",
coordinates=(e, n),
overwrite=True,
)
self.assertTrue(pathlib.Path(tmp).exists())
self.assertGreater(pathlib.Path(tmp).stat().st_size, 0)
with open(tmp, encoding="utf-8") as fh:
data = json.load(fh)
# basic sanity checks on JSON structure
self.assertIn("final_results", data)
self.assertIn("computation_parameters", data)
self.assertIsInstance(data["final_results"], dict)
self.assertIsInstance(data["computation_parameters"], dict)
Comment on lines +112 to +116
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actual (current) values will need to be checked.

finally:
if pathlib.Path(tmp).exists():
os.remove(tmp)


if __name__ == "__main__":
test()
Loading