From 1a2efbe2a42a6f8928d7c217d9101b3401e480dc Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Tue, 21 May 2019 23:40:56 -0400 Subject: [PATCH 1/9] doc: examples for Segmement Library in dox and as code --- doc/raster/r.example.segment/Makefile | 13 ++ doc/raster/r.example.segment/README.md | 20 ++ doc/raster/r.example.segment/main.c | 163 +++++++++++++++ .../r.example.segment/r.example.segment.html | 34 ++++ include/Make/Doxyfile_arch_html.in | 4 +- include/Make/Doxyfile_arch_latex.in | 4 +- lib/segment/segmentlib.dox | 192 ++++++++++++++++-- 7 files changed, 407 insertions(+), 23 deletions(-) create mode 100644 doc/raster/r.example.segment/Makefile create mode 100644 doc/raster/r.example.segment/README.md create mode 100644 doc/raster/r.example.segment/main.c create mode 100644 doc/raster/r.example.segment/r.example.segment.html diff --git a/doc/raster/r.example.segment/Makefile b/doc/raster/r.example.segment/Makefile new file mode 100644 index 00000000000..b974cc614fe --- /dev/null +++ b/doc/raster/r.example.segment/Makefile @@ -0,0 +1,13 @@ +# to use this file, make this relative to GRASS include/ directory +# or set -DMODULE_TOPDIR=... in make command line +# or (when everything fails) use absolute path to the GRASS source code +MODULE_TOPDIR = ../../.. + +PGM = r.example.segment + +LIBES = $(GISLIB) $(RASTERLIB) $(SEGMENTLIB) +DEPENDENCIES = $(GISDEP) $(RASTERDEP) $(SEGMENTDEP) + +include $(MODULE_TOPDIR)/include/Make/Module.make + +default: cmd diff --git a/doc/raster/r.example.segment/README.md b/doc/raster/r.example.segment/README.md new file mode 100644 index 00000000000..d098a21d308 --- /dev/null +++ b/doc/raster/r.example.segment/README.md @@ -0,0 +1,20 @@ +To compile the example simply use `make` (in this directory): + +``` +make +``` + +To run (the asterisks will match your operating system and version +specific directory and file): + +``` +../../../bin.*/grass* --tmp-location XY --exec bash <=v2). Read the file COPYING that comes with + * GRASS for details. + * + *****************************************************************************/ + +#include + +#include +#include +#include +#include + +/* function declaration */ +static void process(SEGMENT * raster_seg); + +/* main function driving the execution */ +int main(int argc, char *argv[]) +{ + /* input and output raster names and file descriptors */ + char *input_name; + char *output_name; + int input_fd; + int output_fd; + + /* buffer for reading and writing rasters */ + void *buffer; + + /* type of the map (CELL/DCELL/...) */ + RASTER_MAP_TYPE map_type; + + /* variables for current and maximum rows and columns */ + int nrows, ncols; + int row; + + /* history structure holds meta-data (title, comments,..) */ + struct History history; + + /* options and description */ + struct GModule *module; + struct Option *input; + struct Option *output; + + /* initialize GRASS GIS library */ + G_gisinit(argv[0]); + + /* initialize module and its description */ + module = G_define_module(); + G_add_keyword(_("raster")); + G_add_keyword(_("example")); + G_add_keyword(_("segment library")); + G_add_keyword(_("random access")); + module->description = + _("Random access to raster using the Segment Library"); + + /* define parameters */ + input = G_define_standard_option(G_OPT_R_INPUT); + output = G_define_standard_option(G_OPT_R_OUTPUT); + + /* options and flags parser */ + if (G_parser(argc, argv)) + exit(EXIT_FAILURE); + + /* stores options and flags to variables */ + input_name = input->answer; + output_name = output->answer; + + /* determine the input map type (CELL/FCELL/DCELL) */ + map_type = Rast_map_type(input_name, ""); + size_t cell_size = Rast_cell_size(map_type); + + /* open existing raster map for reading */ + input_fd = Rast_open_old(input_name, ""); + + /* open the raster for writing (checks if it possible) */ + output_fd = Rast_open_new(output_name, map_type); + + /* allocate input buffer */ + buffer = Rast_allocate_buf(map_type); + + nrows = Rast_window_rows(); + ncols = Rast_window_cols(); + + /* size of a segment */ + int srows = 64; + int scols = 64; + + /* number of segments in memory */ + int num_seg = 4; + + /* segment structure */ + SEGMENT raster_seg; + + /* initialize the segment structures */ + if (Segment_open(&raster_seg, G_tempfile(), + nrows, ncols, srows, scols, cell_size, num_seg) != 1) + G_fatal_error("Unable to create temporary segment file"); + + /* load data into the segment structures */ + for (row = 0; row < Rast_window_rows(); row++) { + Rast_get_row(input_fd, buffer, row, map_type); + if (Segment_put_row(&raster_seg, buffer, row) < 1) + G_fatal_error(_("Unable to write temporary segment file")); + } + + /* run the actual processing */ + process(&raster_seg); + + /* make sure any pending disk operations take place */ + Segment_flush(&raster_seg); + /* store the data permanently in a raster map */ + for (row = 0; row < Rast_window_rows(); row++) { + Segment_get_row(&raster_seg, buffer, row); + Rast_put_row(output_fd, buffer, map_type); + } + + /* memory cleanup */ + G_free(buffer); + + /* closing raster maps and segment structures */ + Segment_close(&raster_seg); + Rast_close(input_fd); + Rast_close(output_fd); + + /* add command line incantation to history file */ + Rast_short_history(output_name, "raster", &history); + Rast_command_history(&history); + Rast_write_history(output_name, &history); + + exit(EXIT_SUCCESS); +} + +/* This would be the main processing function. + * Here we just hardcode a cell to modify. + */ +static void process(SEGMENT * raster_seg) +{ + /* variable we use to hold the value */ + DCELL value; + + /* row and column to access */ + int row = 4; + int col = 2; + + /* pass the pointer, get the value */ + Segment_get(raster_seg, (void *)&value, row, col); + + value = value + 100; + + /* pass the pointer, set the value */ + Segment_put(raster_seg, (void *)&value, row, col); +} diff --git a/doc/raster/r.example.segment/r.example.segment.html b/doc/raster/r.example.segment/r.example.segment.html new file mode 100644 index 00000000000..702c22860b1 --- /dev/null +++ b/doc/raster/r.example.segment/r.example.segment.html @@ -0,0 +1,34 @@ +

DESCRIPTION

+ +r.example.segment changes one cell value in hardcoded location. +It is meant to demonstrate how to use the Segment Library together with +GRASS GIS raster maps. + +

EXAMPLE

+ +Create a modified version of the raster map "elevation" +(North Carolina sample dataset): + +
+g.region raster=elevation
+r.example.segment input=elevation output=modified_elevation
+r.univar raster_map_1
+r.univar raster_map_2
+
+ +

SEE ALSO

+ + +r.example +v.example + + + +GRASS Programmer's Manual + + +

AUTHORS

+ +Vaclav Petras + +

Last changed: $Date$ diff --git a/include/Make/Doxyfile_arch_html.in b/include/Make/Doxyfile_arch_html.in index b966f06396c..92a5132d85b 100644 --- a/include/Make/Doxyfile_arch_html.in +++ b/include/Make/Doxyfile_arch_html.in @@ -982,7 +982,7 @@ EXCLUDE_SYMBOLS = # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = doc # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and @@ -996,7 +996,7 @@ EXAMPLE_PATTERNS = # irrespective of the value of the RECURSIVE tag. # The default value is: NO. -EXAMPLE_RECURSIVE = NO +EXAMPLE_RECURSIVE = YES # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the diff --git a/include/Make/Doxyfile_arch_latex.in b/include/Make/Doxyfile_arch_latex.in index ef5ebdc4d09..f5729d54d09 100644 --- a/include/Make/Doxyfile_arch_latex.in +++ b/include/Make/Doxyfile_arch_latex.in @@ -982,7 +982,7 @@ EXCLUDE_SYMBOLS = # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = doc # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and @@ -996,7 +996,7 @@ EXAMPLE_PATTERNS = # irrespective of the value of the RECURSIVE tag. # The default value is: NO. -EXAMPLE_RECURSIVE = NO +EXAMPLE_RECURSIVE = YES # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the diff --git a/lib/segment/segmentlib.dox b/lib/segment/segmentlib.dox index f5c59aba716..3045be98207 100644 --- a/lib/segment/segmentlib.dox +++ b/lib/segment/segmentlib.dox @@ -1,9 +1,14 @@ /*! \page segmentlib GRASS Segment Library - +\tableofcontents + \author CERL +\author Markus Metz \section segmentintro Introduction @@ -64,21 +69,168 @@ or undocumented, start with the prefix \c Segment_. To avoid name conflicts, programmers should not create variables or routines in their own modules which use this prefix. +\section Loading_the_Segment_Library Including and Loading the Segment Library -\section Segment_Routines Segment Routines +

+The functions and data structures needed in oder to use the Segment +Library are defined in the header file called +\c grass/segment.h and included using: + +\code +#include +\endcode

-The routines in the Segment Library are described below, more or -less in the order they would logically be used in a module. They use a data -structure called SEGMENT which is defined in the header file -\c grass/segment.h that must be included in any code using these -routines: +To compile (link) the code code, the library needs to be specified +by adding the associated variables to the Makefile: + +\code +LIBES = ... $(SEGMENTLIB) +DEPENDENCIES = ... $(SEGMENTDEP) +\endcode + +

+See \ref Compiling_and_Installing_GRASS_Modules for a complete +discussion of Makefiles. + +\section How_to_Use_the_Library How to Use the Library for Raster Maps + +The most typical use of the *Segment Library* in GRASS GIS is with +raster maps. Raster maps are read using row-by-row API and, at the same +time, they might be too large to store in memory. The *Segment Library* +can be used to make them accessible with random access when random +access is needed. +Here we discuss usage with one raster map of type \c DCELL +(double precision floating point). + +To have everything we need available, you need to do several includes: \code #include +#include +#include +#include +\endcode + +First, you need to initialize size-related variables: + +\code +/* size of the whole raster (aka input matrix) */ +int nrows = Rast_window_rows(); +int ncols = Rast_window_cols(); + +/* type and cell size we will work with */ +RASTER_MAP_TYPE map_type = DCELL_TYPE; +size_t cell_size = Rast_cell_size(map_type); + +/* size of a segment */ +int srows = 64; +int scols = 64; + +/* number of segments in memory */ +int num_seg = 4; +\endcode + +Then, you prepare for reading raster map as in any other case +and additionally you also initialize the segment storage: + +\code +/* typically, name of map would be a parameter */ +char *map_name = "raster_map_1"; + +/* buffer for holding one raster row */ +void *buffer = Rast_allocate_buf(map_type); + +/* open existing raster map for reading */ +int raster_fd = Rast_open_old(map_name, ""); + +SEGMENT raster_seg; + +/* initialize the segment structures */ +if (Segment_open(&raster_seg, G_tempfile(), + nrows, ncols, srows, scols, cell_size, num_seg) != 1) + G_fatal_error("Unable to create temporary segment file"); +\endcode + +Now you can set the values in the segment storage to the values of +the raster you need to access: + +\code +for (int row = 0; row < Rast_window_rows(); row++) { + Rast_get_row(raster_fd, buffer, row, map_type); + if (Segment_put_row(&raster_seg, buffer, row) < 1) + G_fatal_error(_("Unable to write temporary segment file")); +} \endcode -\see \ref Loading_the_Segment_Library. +At this point, you can use the *Segment Library* to access the values +in the loaded raster map in a random manner specifying row and column: + +\code +/* variable we use to hold the value */ +DCELL value; + +/* row and column to access */ +int row = 4; +int col = 2; + +/* pass the pointer, get the value */ +Segment_get(&raster_seg, (void *) &value, row, col); + +/* use value here */ +\endcode + +Similarly, we can also modify the values by specifying a row and column: + +\code +/* this is the value we want to use */ +value = 100; + +/* pass the pointer, set the value */ +Segment_put(&raster_seg, (void *) &value, row, col); +\endcode + +In both cases, the function takes pointer to void as a parameter, +so we cast to `void *` to make it clear to compiler that this is what +we intent to do. The library function will handle the value according to +the size of the \c DCELL type we set with Segment_open(). + +Now, we are done with processing and we want to save the data to a +GRASS GIS raster map. Often we this would be a different segment +structure, but here with will store the data we were operating on. + +\code +/* typically, name of map would be a parameter */ +char *output_map_name = "raster_map_2"; + +/* open new raster map for writing */ +int output_raster_fd = Rast_open_new(output_map_name, map_type); + +/* make sure any pending disk operations take place */ +Segment_flush(&raster_seg); + +/* store the data permanently in a raster map */ +for (int row = 0; row < Rast_window_rows(); row++) { + Segment_get_row(&raster_seg, buffer, row); + Rast_put_row(output_raster_fd, buffer, map_type); +} +\endcode + +At the end, close, free memory, and clean up: + +\code +G_free(buffer); +Segment_close(&raster_seg); +Rast_close(output_raster_fd); +Rast_close(raster_fd); +\endcode + +\section Segment_Routines Segment Routines + +

+The routines in the Segment Library are described below, more or +less in the order they would logically be used in a module. They use a data +structure called SEGMENT.

A temporary file needs to be prepared and a SEGMENT structure needs to @@ -393,17 +545,19 @@ the best performance. Calculating segment size as a fraction of the data matrix size, e.g. srows = nrows / 4 + 1, will result in very poor performance, particularly for larger datasets. -\section Loading_the_Segment_Library Loading the Segment Library +\section A_Complete_Example_With_Two_Rasters A Complete Example With Two Rasters -

-The library is loaded by specifying -\code -$(SEGMENTLIB) -\endcode -in the Makefile. +This complete example of a module which loads a raster map into +the *Segment Library* data structures, modifies the values, and +creates a new raster map with these values. -

-See \ref Compiling_and_Installing_GRASS_Modules for a complete -discussion of Makefiles. +\include doc/raster/r.example.segment/main.c + +Makefile for this module looks like this: + +\dontinclude doc/raster/r.example.segment/Makefile + +\skip MODULE_TOPDIR = .. +\until default */ From 992b39eb30af7a1e910741446d5136ecb33698e3 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Thu, 23 May 2019 16:19:29 -0400 Subject: [PATCH 2/9] doc: advanced example for segmentlib in dox from example code --- .../r.example.segment/r.example.segment.html | 1 + doc/raster/r.example.segmulti/Makefile | 13 ++ doc/raster/r.example.segmulti/README.md | 34 ++++ doc/raster/r.example.segmulti/main.c | 189 ++++++++++++++++++ .../r.example.segmulti.html | 44 ++++ lib/segment/segmentlib.dox | 85 ++++++++ 6 files changed, 366 insertions(+) create mode 100644 doc/raster/r.example.segmulti/Makefile create mode 100644 doc/raster/r.example.segmulti/README.md create mode 100644 doc/raster/r.example.segmulti/main.c create mode 100644 doc/raster/r.example.segmulti/r.example.segmulti.html diff --git a/doc/raster/r.example.segment/r.example.segment.html b/doc/raster/r.example.segment/r.example.segment.html index 702c22860b1..09cc8a5b01d 100644 --- a/doc/raster/r.example.segment/r.example.segment.html +++ b/doc/raster/r.example.segment/r.example.segment.html @@ -20,6 +20,7 @@

SEE ALSO

r.example +r.example.segmulti v.example diff --git a/doc/raster/r.example.segmulti/Makefile b/doc/raster/r.example.segmulti/Makefile new file mode 100644 index 00000000000..305e809dbfc --- /dev/null +++ b/doc/raster/r.example.segmulti/Makefile @@ -0,0 +1,13 @@ +# to use this file, make this relative to GRASS include/ directory +# or set -DMODULE_TOPDIR=... in make command line +# or (when everything fails) use absolute path to the GRASS source code +MODULE_TOPDIR = ../../.. + +PGM = r.example.segmulti + +LIBES = $(GISLIB) $(RASTERLIB) $(SEGMENTLIB) +DEPENDENCIES = $(GISDEP) $(RASTERDEP) $(SEGMENTDEP) + +include $(MODULE_TOPDIR)/include/Make/Module.make + +default: cmd diff --git a/doc/raster/r.example.segmulti/README.md b/doc/raster/r.example.segmulti/README.md new file mode 100644 index 00000000000..489896d490d --- /dev/null +++ b/doc/raster/r.example.segmulti/README.md @@ -0,0 +1,34 @@ +To compile the example simply use `make` (in this directory): + +``` +make +``` + +To run (the asterisks will match your operating system and version +specific directory and file): + +``` +../../../bin.*/grass* --tmp-location XY --exec bash <=v2). Read the file COPYING that comes with + * GRASS for details. + * + *****************************************************************************/ + +#include + +#include +#include +#include +#include + + +/* function declaration */ +static void process(SEGMENT * raster_seg, int ninputs); + + +/* main function driving the execution */ +int main(int argc, char *argv[]) +{ + /* input and output raster names and file descriptors */ + char *output_name; + int output_fd; + + /* type of the map (CELL/DCELL/...) */ + RASTER_MAP_TYPE map_type; + + /* variables for current and maximum dimensions */ + int nrows, ncols; + int row, col; + int input, ninputs; + + /* history structure holds meta-data (title, comments,..) */ + struct History history; + + /* options and description */ + struct GModule *module; + struct Option *opt_inputs; + struct Option *opt_output; + + /* initialize GRASS GIS library */ + G_gisinit(argv[0]); + + /* initialize module and its description */ + module = G_define_module(); + G_add_keyword(_("raster")); + G_add_keyword(_("example")); + G_add_keyword(_("segment library")); + G_add_keyword(_("random access")); + module->description = + _("Code explains use of Segment Library with multiple rasters"); + + /* define parameters */ + opt_inputs = G_define_standard_option(G_OPT_R_INPUTS); + opt_output = G_define_standard_option(G_OPT_R_OUTPUT); + + /* options and flags parser */ + if (G_parser(argc, argv)) + exit(EXIT_FAILURE); + + /* stores options and flags to variables */ + output_name = opt_output->answer; + + /* count input rasters */ + for (input = 0; opt_inputs->answers[input] != NULL; input++) ; + ninputs = input; + + nrows = Rast_window_rows(); + ncols = Rast_window_cols(); + + /* size of a segment */ + int srows = 64; + int scols = 64; + + /* number of segments in memory */ + int nsegs = 4; + + map_type = DCELL_TYPE; + size_t cell_size = Rast_cell_size(map_type); + size_t segment_cell_size = cell_size * ninputs; + + /* open the raster for writing (checks if it possible) */ + output_fd = Rast_open_new(output_name, map_type); + + /* segment structure */ + SEGMENT raster_seg; + + /* initialize the segment structures */ + if (Segment_open(&raster_seg, G_tempfile(), + nrows, ncols, srows, scols, segment_cell_size, + nsegs) != 1) + G_fatal_error(_("Unable to create temporary segment file")); + + /* array to store file descriptors */ + int *input_fds = G_malloc(ninputs * sizeof(int)); + + G_message(_("Loading %d raster maps"), ninputs); + + /* open existing raster maps for reading */ + for (input = 0; input < ninputs; input++) { + input_fds[input] = Rast_open_old(opt_inputs->answers[input], ""); + } + + /* allocate input buffer */ + DCELL *row_buffer = Rast_allocate_d_buf(); + DCELL *seg_buffer = G_malloc(ncols * ninputs * sizeof(DCELL)); + + for (row = 0; row < nrows; row++) { + for (input = 0; input < ninputs; input++) { + Rast_get_d_row(input_fds[input], row_buffer, row); + for (col = 0; col < ncols; col++) { + seg_buffer[col * ninputs + input] = row_buffer[col]; + } + } + if (Segment_put_row(&raster_seg, seg_buffer, row) < 1) + G_fatal_error(_("Unable to write temporary segment file")); + } + + /* now run the actual processing */ + process(&raster_seg, ninputs); + + /* make sure any pending disk operations take place */ + Segment_flush(&raster_seg); + /* store the data permanently in a raster map */ + + for (row = 0; row < nrows; row++) { + for (col = 0; col < ncols; col++) { + row_buffer[col] = 0; + } + Segment_get_row(&raster_seg, seg_buffer, row); + for (input = 0; input < ninputs; input++) { + for (col = 0; col < ncols; col++) { + row_buffer[col] += seg_buffer[col * ninputs + input]; + } + } + Rast_put_row(output_fd, row_buffer, map_type); + } + + /* memory cleanup */ + G_free(row_buffer); + G_free(seg_buffer); + + /* closing raster maps and segment structures */ + Segment_close(&raster_seg); + for (input = 0; input < ninputs; input++) { + Rast_close(input_fds[input]); + } + Rast_close(output_fd); + + /* add command line incantation to history file */ + Rast_short_history(output_name, "raster", &history); + Rast_command_history(&history); + Rast_write_history(output_name, &history); + + exit(EXIT_SUCCESS); +} + +/* This would be the main processing function. + * Here we just hardcode a cell to modify. + */ +static void process(SEGMENT * raster_seg, int ninputs) +{ + /* buffer we use to hold the values */ + DCELL *values = G_malloc(ninputs * sizeof(DCELL *)); + + /* row and column to access */ + int row = 1; + int col = 3; + + /* pass the pointer, get the value */ + Segment_get(raster_seg, values, row, col); + + for (int input = 0; input < ninputs; input++) { + values[input] = values[input] + 10000; + } + + /* pass the pointer, set the value */ + Segment_put(raster_seg, values, row, col); +} diff --git a/doc/raster/r.example.segmulti/r.example.segmulti.html b/doc/raster/r.example.segmulti/r.example.segmulti.html new file mode 100644 index 00000000000..601c7ff8d43 --- /dev/null +++ b/doc/raster/r.example.segmulti/r.example.segmulti.html @@ -0,0 +1,44 @@ +

DESCRIPTION

+ +r.example.segmulti changes one cell value in hardcoded location +and sums input rasters together. +It is meant to demonstrate how to use the Segment Library together with +GRASS GIS raster maps. Specifically is focuses on case when multiple +rasters are always accessed together (e.g. image bands) and when their +values can be stored as a same type (here double). + +

EXAMPLE

+ +Set computational region and generate synthetic data: + +
+g.region cols=100 rows=50 -p
+r.mapcalc -s expression='raster_1 = row()'
+r.mapcalc -s expression='raster_2 = 10 * col()'
+r.mapcalc -s expression='raster_3 = 1000'
+
+ +Test the module: + +
+r.example.segmulti input=raster_1,raster_2,raster_3 output=raster_out
+
+ +

SEE ALSO

+ + +r.example +r.example.segment +v.example + + + +GRASS Programmer's Manual + + +

AUTHORS

+ +Vaclav Petras, +NCSU Center for Geospatial Analytics + +

Last changed: $Date$ diff --git a/lib/segment/segmentlib.dox b/lib/segment/segmentlib.dox index 3045be98207..4ab6867d6d9 100644 --- a/lib/segment/segmentlib.dox +++ b/lib/segment/segmentlib.dox @@ -225,6 +225,91 @@ Rast_close(output_raster_fd); Rast_close(raster_fd); \endcode +\section Using_the_library_with_multiple_raster_maps Using the Library with Multiple Raster Maps + +In case we want to manipulate multiple raster maps at the same time, +we can use the fact that the *Segment Library* supports storage of +arbitrary data in cell. This is particularly advantageous when we are +always accessing values from all rasters at once since the look up +and possible reading from disk will need to happen just once for +each cell we access. We cover the case when the number of input raster +maps is not known in advance. + +In the following examples, we assume we can convert values from all +raster maps into the same type (we are using double). +We also assume that we got the raster names in command +line options as a GRASS GIS module. +Note that the code is not complete and some definitions or calls are +not shown. + +\dontinclude doc/raster/r.example.segmulti/main.c + +First, we count number of inputs to have the value at hand: + +\skip count +\until ninputs + +We define segment sizes (and other variables) as in the case of one +raster: + +\skip Rast_window_rows +\until nsegs + +However, we define size of one cell (item) stored in the segment +structures as multiplication of size of the raster cell and +number of input rasters: + +\skip DCELL_TYPE +\until segment_cell_size + +We proceed with creating and opening the segment structures in the usual +way: + +\skip Segment_open +\until G_fatal_error + +The opening of rasters needs to happen in a loop. We assume that we can +open that many raster maps at the same time (there is a limit of how +many open file operating system can handle): + +\skip file descriptors +\until } + +We allocate two buffers we will use. One for holding raster map row +and one for holding a row of cell (items) stored in the segment +structures. We will access the row of segment cells as a two-dimensional +field with first dimension being a column and second the ordinal number +of input raster map. + +\skip allocate +\until seg_buffer + +Now, we loop over rows and we load the given row for each of the raster +maps. Then, for each column, i.e., value in a row of the given raster, +we copy the value to its place in the segmentation buffer. + +\skip for (row +\until actual processing + +Now we can do the actual processing which we will discuss later as this +would be in a separate function anyway. After the processing, we write +the resulting rasters. In this example, we do additional processing and +store a sum of all the rasters, so we are writing only one raster: + +\skip Segment_flush +\until memory cleanup + +At the end, we free memory and close rasters: + +\skip G_free +\until Rast_close(output_fd); + +The actual processing with random access needs to get the individual +values stored in each cell in the segment storage. + +\skip hold the values +\until Segment_put + \section Segment_Routines Segment Routines

From 482494e482cdb29730fb393b8847a6a3e9405ee5 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Thu, 23 May 2019 22:56:22 -0400 Subject: [PATCH 3/9] doc: improved desc for open and get_row in segmentlib --- lib/segment/get_row.c | 19 ++++++++++++------- lib/segment/open.c | 25 ++++++++++++++++++++++--- lib/segment/segmentlib.dox | 2 +- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/lib/segment/get_row.c b/lib/segment/get_row.c index ca43969ffac..7ebba5cfe6f 100644 --- a/lib/segment/get_row.c +++ b/lib/segment/get_row.c @@ -22,17 +22,22 @@ #include "local_proto.h" /** - * \fn int Segment_get_row (SEGMENT *SEG, void *buf, int row) - * * \brief Read row from segment file. * * Transfers data from a segment file, row by row, into memory - * (which can then be written to a regular matrix file). Seg is the - * segment structure that was configured from a call to - * Segment_init(). + * (which can then be written to a regular matrix file, typically raster + * map). *SEG* is the + * segment structure that was configured from a call to + * Segment_init() or Segment_open(). + * + * *buf* will be filled with ncols*len bytes of data + * corresponding to the *row* in the data matrix. + * + * \pre Segment_flush() needs to be called beforehand in order to make + * all recently written values available. * - * Buf will be filled with ncols*len bytes of data - * corresponding to the row in the data matrix. + * \pre *buf* points to an allocated array of length ncols*len + * where *len* is size of one stored value (cell). * * \param[in] seg segment * \param[in,out] buf diff --git a/lib/segment/open.c b/lib/segment/open.c index 5626ec082ca..7870d122574 100644 --- a/lib/segment/open.c +++ b/lib/segment/open.c @@ -20,10 +20,28 @@ /** * \brief Initialize segment structure and open segment file. * - * Initializes the seg structure and prepares a temporary file. - * This fn is a wrapper for Segment_format() and Segment_init() + * Initializes the *seg* structure and prepares a temporary file. * - * Note: The file with name fname will be created anew. + * This function is a wrapper for Segment_format_nofill(), + * Segment_init(), all-in-memory mode initialization, and temporary + * file handling. + * + * The values are not guaranteed to be initialized to zero or NULL. + * You need to initialize them if needed. Typically, initialization + * is done when loading values from existing raster map. + * + * The number of non-segmented rows and columns (*nrows* and *ncols*) + * is typically a computational region. + * + * The number of segments to keep in memory is automatically adjusted + * if it is larger than number of total segments required. + * + * In case of an error, a specific warning will be printed (using + * G_warning()) and a negative number will be returned. + * In case out of memory occurs in all-in-memory mode, + * G_fatal_error() is called. + * + * Note: The file with name *fname* will be created anew. * * \param[in,out] SEG segment * \param[in] fname file name @@ -57,6 +75,7 @@ int Segment_open(SEGMENT *SEG, char *fname, off_t nrows, off_t ncols, int srows, SEG->len = len; SEG->nseg = nseg; SEG->cache = G_calloc(sizeof(char) * SEG->nrows * SEG->ncols, SEG->len); + /* scb is used to decide if we are in the all-in-memory mode */ SEG->scb = NULL; SEG->open = 1; diff --git a/lib/segment/segmentlib.dox b/lib/segment/segmentlib.dox index 4ab6867d6d9..93f66f31672 100644 --- a/lib/segment/segmentlib.dox +++ b/lib/segment/segmentlib.dox @@ -2,7 +2,7 @@ \tableofcontents From f77f8e61e91c0053bf27267ab20554e5de882aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Fri, 21 Jun 2024 18:14:17 -0400 Subject: [PATCH 4/9] Apply suggestions from clang-format Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- doc/raster/r.example.segment/main.c | 8 ++++---- doc/raster/r.example.segmulti/main.c | 22 ++++++++++------------ lib/segment/get_row.c | 2 +- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/doc/raster/r.example.segment/main.c b/doc/raster/r.example.segment/main.c index a4edf7c7e46..9b8d085f556 100644 --- a/doc/raster/r.example.segment/main.c +++ b/doc/raster/r.example.segment/main.c @@ -23,7 +23,7 @@ #include /* function declaration */ -static void process(SEGMENT * raster_seg); +static void process(SEGMENT *raster_seg); /* main function driving the execution */ int main(int argc, char *argv[]) @@ -103,8 +103,8 @@ int main(int argc, char *argv[]) SEGMENT raster_seg; /* initialize the segment structures */ - if (Segment_open(&raster_seg, G_tempfile(), - nrows, ncols, srows, scols, cell_size, num_seg) != 1) + if (Segment_open(&raster_seg, G_tempfile(), nrows, ncols, srows, scols, + cell_size, num_seg) != 1) G_fatal_error("Unable to create temporary segment file"); /* load data into the segment structures */ @@ -144,7 +144,7 @@ int main(int argc, char *argv[]) /* This would be the main processing function. * Here we just hardcode a cell to modify. */ -static void process(SEGMENT * raster_seg) +static void process(SEGMENT *raster_seg) { /* variable we use to hold the value */ DCELL value; diff --git a/doc/raster/r.example.segmulti/main.c b/doc/raster/r.example.segmulti/main.c index ec8a57dba16..26340f4f521 100644 --- a/doc/raster/r.example.segmulti/main.c +++ b/doc/raster/r.example.segmulti/main.c @@ -20,10 +20,8 @@ #include #include - /* function declaration */ -static void process(SEGMENT * raster_seg, int ninputs); - +static void process(SEGMENT *raster_seg, int ninputs); /* main function driving the execution */ int main(int argc, char *argv[]) @@ -72,7 +70,8 @@ int main(int argc, char *argv[]) output_name = opt_output->answer; /* count input rasters */ - for (input = 0; opt_inputs->answers[input] != NULL; input++) ; + for (input = 0; opt_inputs->answers[input] != NULL; input++) + ; ninputs = input; nrows = Rast_window_rows(); @@ -96,9 +95,8 @@ int main(int argc, char *argv[]) SEGMENT raster_seg; /* initialize the segment structures */ - if (Segment_open(&raster_seg, G_tempfile(), - nrows, ncols, srows, scols, segment_cell_size, - nsegs) != 1) + if (Segment_open(&raster_seg, G_tempfile(), nrows, ncols, srows, scols, + segment_cell_size, nsegs) != 1) G_fatal_error(_("Unable to create temporary segment file")); /* array to store file descriptors */ @@ -119,8 +117,8 @@ int main(int argc, char *argv[]) for (input = 0; input < ninputs; input++) { Rast_get_d_row(input_fds[input], row_buffer, row); for (col = 0; col < ncols; col++) { - seg_buffer[col * ninputs + input] = row_buffer[col]; - } + seg_buffer[col * ninputs + input] = row_buffer[col]; + } } if (Segment_put_row(&raster_seg, seg_buffer, row) < 1) G_fatal_error(_("Unable to write temporary segment file")); @@ -135,11 +133,11 @@ int main(int argc, char *argv[]) for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { - row_buffer[col] = 0; + row_buffer[col] = 0; } Segment_get_row(&raster_seg, seg_buffer, row); for (input = 0; input < ninputs; input++) { - for (col = 0; col < ncols; col++) { + for (col = 0; col < ncols; col++) { row_buffer[col] += seg_buffer[col * ninputs + input]; } } @@ -168,7 +166,7 @@ int main(int argc, char *argv[]) /* This would be the main processing function. * Here we just hardcode a cell to modify. */ -static void process(SEGMENT * raster_seg, int ninputs) +static void process(SEGMENT *raster_seg, int ninputs) { /* buffer we use to hold the values */ DCELL *values = G_malloc(ninputs * sizeof(DCELL *)); diff --git a/lib/segment/get_row.c b/lib/segment/get_row.c index 7ebba5cfe6f..03f915f7b71 100644 --- a/lib/segment/get_row.c +++ b/lib/segment/get_row.c @@ -27,7 +27,7 @@ * Transfers data from a segment file, row by row, into memory * (which can then be written to a regular matrix file, typically raster * map). *SEG* is the - * segment structure that was configured from a call to + * segment structure that was configured from a call to * Segment_init() or Segment_open(). * * *buf* will be filled with ncols*len bytes of data From 9e6fe11e095875c7c2bca7b02a46df1b164c9e91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Fri, 20 Dec 2024 19:22:31 -0500 Subject: [PATCH 5/9] Add language in markdown fenced code blocks --- doc/raster/r.example.segment/README.md | 4 ++-- doc/raster/r.example.segmulti/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/raster/r.example.segment/README.md b/doc/raster/r.example.segment/README.md index d098a21d308..72b5700a285 100644 --- a/doc/raster/r.example.segment/README.md +++ b/doc/raster/r.example.segment/README.md @@ -1,13 +1,13 @@ To compile the example simply use `make` (in this directory): -``` +```shell make ``` To run (the asterisks will match your operating system and version specific directory and file): -``` +```shell ../../../bin.*/grass* --tmp-location XY --exec bash < Date: Sat, 21 Dec 2024 17:50:31 -0500 Subject: [PATCH 6/9] Update README.md --- doc/raster/r.example.segmulti/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/raster/r.example.segmulti/README.md b/doc/raster/r.example.segmulti/README.md index a59f870df09..ddee9993d73 100644 --- a/doc/raster/r.example.segmulti/README.md +++ b/doc/raster/r.example.segmulti/README.md @@ -1,6 +1,6 @@ To compile the example simply use `make` (in this directory): -``` +```shell make ``` From 3f785fa36c6f93a83cf085a53cf484e08158288c Mon Sep 17 00:00:00 2001 From: Abhimanyu Gupta Date: Wed, 4 Feb 2026 08:06:30 +0530 Subject: [PATCH 7/9] doc: convert example modules documentation to Markdown --- .../r.example.segment/r.example.segment.html | 35 ------------------- .../r.example.segment/r.example.segment.md | 32 +++++++++++++++++ ...le.segmulti.html => r.example.segmulti.md} | 35 +++++++++---------- lib/segment/segmentlib.dox | 2 +- 4 files changed, 49 insertions(+), 55 deletions(-) delete mode 100644 doc/raster/r.example.segment/r.example.segment.html create mode 100644 doc/raster/r.example.segment/r.example.segment.md rename doc/raster/r.example.segmulti/{r.example.segmulti.html => r.example.segmulti.md} (53%) diff --git a/doc/raster/r.example.segment/r.example.segment.html b/doc/raster/r.example.segment/r.example.segment.html deleted file mode 100644 index 09cc8a5b01d..00000000000 --- a/doc/raster/r.example.segment/r.example.segment.html +++ /dev/null @@ -1,35 +0,0 @@ -

DESCRIPTION

- -r.example.segment changes one cell value in hardcoded location. -It is meant to demonstrate how to use the Segment Library together with -GRASS GIS raster maps. - -

EXAMPLE

- -Create a modified version of the raster map "elevation" -(North Carolina sample dataset): - -
-g.region raster=elevation
-r.example.segment input=elevation output=modified_elevation
-r.univar raster_map_1
-r.univar raster_map_2
-
- -

SEE ALSO

- - -r.example -r.example.segmulti -v.example - - - -GRASS Programmer's Manual - - -

AUTHORS

- -Vaclav Petras - -

Last changed: $Date$ diff --git a/doc/raster/r.example.segment/r.example.segment.md b/doc/raster/r.example.segment/r.example.segment.md new file mode 100644 index 00000000000..a0602a6a69e --- /dev/null +++ b/doc/raster/r.example.segment/r.example.segment.md @@ -0,0 +1,32 @@ +# r.example.segment + +## DESCRIPTION + +*r.example.segment* changes one cell value in hardcoded location. +It is meant to demonstrate how to use the Segment Library together with +GRASS GIS raster maps. + +## EXAMPLE + +Create a modified version of the raster map "elevation" +(North Carolina sample dataset): + +```bash +g.region raster=elevation +r.example.segment input=elevation output=modified_elevation +r.univar raster_map_1 +r.univar raster_map_2 +``` + +## SEE ALSO + +* [r.example](r.example.html) +* [r.example.segmulti](r.example.segmulti.html) +* [v.example](v.example.html) + +* [GRASS Programmer's Manual](https://grass.osgeo.org/programming7/) + +## AUTHORS + +Vaclav Petras + diff --git a/doc/raster/r.example.segmulti/r.example.segmulti.html b/doc/raster/r.example.segmulti/r.example.segmulti.md similarity index 53% rename from doc/raster/r.example.segmulti/r.example.segmulti.html rename to doc/raster/r.example.segmulti/r.example.segmulti.md index 601c7ff8d43..e2c916fd81b 100644 --- a/doc/raster/r.example.segmulti/r.example.segmulti.html +++ b/doc/raster/r.example.segmulti/r.example.segmulti.md @@ -1,44 +1,41 @@ -

DESCRIPTION

+# r.example.segmulti -r.example.segmulti changes one cell value in hardcoded location +## DESCRIPTION + +*r.example.segmulti* changes one cell value in hardcoded location and sums input rasters together. It is meant to demonstrate how to use the Segment Library together with GRASS GIS raster maps. Specifically is focuses on case when multiple rasters are always accessed together (e.g. image bands) and when their values can be stored as a same type (here double). -

EXAMPLE

+## EXAMPLE Set computational region and generate synthetic data: -
+```bash
 g.region cols=100 rows=50 -p
 r.mapcalc -s expression='raster_1 = row()'
 r.mapcalc -s expression='raster_2 = 10 * col()'
 r.mapcalc -s expression='raster_3 = 1000'
-
+``` Test the module: -
+```bash
 r.example.segmulti input=raster_1,raster_2,raster_3 output=raster_out
-
+``` -

SEE ALSO

+## SEE ALSO - -r.example -r.example.segment -v.example - +* [r.example](r.example.html) +* [r.example.segment](r.example.segment.html) +* [v.example](v.example.html) - -GRASS Programmer's Manual - +* [GRASS Programmer's Manual](https://grass.osgeo.org/programming7/) -

AUTHORS

+## AUTHORS Vaclav Petras, -NCSU Center for Geospatial Analytics +[NCSU Center for Geospatial Analytics](http://geospatial.ncsu.edu) -

Last changed: $Date$ diff --git a/lib/segment/segmentlib.dox b/lib/segment/segmentlib.dox index 93f66f31672..b6047fe6e21 100644 --- a/lib/segment/segmentlib.dox +++ b/lib/segment/segmentlib.dox @@ -90,7 +90,7 @@ DEPENDENCIES = ... $(SEGMENTDEP) \endcode

-See \ref Compiling_and_Installing_GRASS_Modules for a complete +See \ref Compiling_and_Installing_GRASS_Modules for a complete discussion of Makefiles. \section How_to_Use_the_Library How to Use the Library for Raster Maps From d4f4f31e26ae7ff1065a324a874868e44c94f473 Mon Sep 17 00:00:00 2001 From: Abhimanyu Gupta Date: Wed, 4 Feb 2026 09:30:14 +0530 Subject: [PATCH 8/9] doc: fix end of files and trailing whitespace --- doc/raster/r.example.segment/r.example.segment.md | 1 - doc/raster/r.example.segmulti/r.example.segmulti.md | 1 - 2 files changed, 2 deletions(-) diff --git a/doc/raster/r.example.segment/r.example.segment.md b/doc/raster/r.example.segment/r.example.segment.md index a0602a6a69e..38ea3b166db 100644 --- a/doc/raster/r.example.segment/r.example.segment.md +++ b/doc/raster/r.example.segment/r.example.segment.md @@ -29,4 +29,3 @@ r.univar raster_map_2 ## AUTHORS Vaclav Petras - diff --git a/doc/raster/r.example.segmulti/r.example.segmulti.md b/doc/raster/r.example.segmulti/r.example.segmulti.md index e2c916fd81b..a11e43c6533 100644 --- a/doc/raster/r.example.segmulti/r.example.segmulti.md +++ b/doc/raster/r.example.segmulti/r.example.segmulti.md @@ -38,4 +38,3 @@ r.example.segmulti input=raster_1,raster_2,raster_3 output=raster_out Vaclav Petras, [NCSU Center for Geospatial Analytics](http://geospatial.ncsu.edu) - From b1d9cfa99bf91cb9ce14e52ceebc5884a08e6e87 Mon Sep 17 00:00:00 2001 From: Abhimanyu Gupta Date: Thu, 5 Feb 2026 02:01:55 +0530 Subject: [PATCH 9/9] doc: add cmake build for segment examples and fix linting --- doc/CMakeLists.txt | 3 +++ doc/raster/CMakeLists.txt | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 doc/raster/CMakeLists.txt diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 1607a619213..10858b0871d 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -2,6 +2,9 @@ set(doc_files grass_database projectionintro) +add_subdirectory(raster) + + set(img_files create_new_project_gui.png gi_3dview.jpg diff --git a/doc/raster/CMakeLists.txt b/doc/raster/CMakeLists.txt new file mode 100644 index 00000000000..f986f50db35 --- /dev/null +++ b/doc/raster/CMakeLists.txt @@ -0,0 +1,2 @@ +build_program_in_subdir(r.example.segment DEPENDS grass_gis grass_raster grass_segment) +build_program_in_subdir(r.example.segmulti DEPENDS grass_gis grass_raster grass_segment)