1 /***************************************************************************
2     qgis.d.rast.c
3     ---------------------
4     begin                : February 2010
5     copyright            : (C) 2010 by Radim Blazek
6     email                : radim dot blazek at gmail dot com
7  ***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 /****************************************************************************
16  *
17  * MODULE:       qgis.d.rast
18  * AUTHOR(S):    Radim Blazek <radim.blazek gmail.com>
19  *               using d.rast from GRASS
20  * PURPOSE:      display raster maps in active graphics display
21  * COPYRIGHT:    (C) 2010 by Radim Blazek
22  *
23  *               This program is free software under the GNU General Public
24  *               License (>=v2).
25  *
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <math.h>
31 #include <assert.h>
32 #include <limits.h>
33 #ifdef WIN32
34 #include <fcntl.h>
35 #include <io.h>
36 #endif
37 #include <grass/version.h>
38 #include <grass/gis.h>
39 #include <grass/raster.h>
40 #include <grass/display.h>
41 
42 #if defined(_MSC_VER) && _MSC_VER < 1900
43 #include <float.h>
44 #define INFINITY (DBL_MAX+DBL_MAX)
45 #define NAN (INFINITY-INFINITY)
46 #endif
47 
48 int display( char *name, char *mapset, RASTER_MAP_TYPE data_type, char *format );
49 
main(int argc,char ** argv)50 int main( int argc, char **argv )
51 {
52   char *mapset = 0;
53   char *name = 0;
54   struct GModule *module;
55   struct Option *map;
56   struct Option *win;
57   struct Option *format;
58   struct Cell_head window;
59   RASTER_MAP_TYPE raster_type;
60 
61   /* Initialize the GIS calls */
62   G_gisinit( argv[0] );
63 
64   module = G_define_module();
65   module->description = ( "Output raster map layers in a format suitable for display in QGIS" );
66 
67   map = G_define_standard_option( G_OPT_R_MAP );
68   map->description = ( "Raster map to be displayed" );
69 
70   format = G_define_option();
71   format->key = "format";
72   format->type = TYPE_STRING;
73   format->description = "format";
74   format->options = "color,value";
75 
76   win = G_define_option();
77   win->key = "window";
78   win->type = TYPE_DOUBLE;
79   win->multiple = YES;
80   win->description = "xmin,ymin,xmax,ymax,ncols,nrows";
81 
82   if ( G_parser( argc, argv ) )
83     exit( EXIT_FAILURE );
84 
85   name = map->answer;
86   mapset = "";
87 
88   /* It can happen that GRASS data set is 'corrupted' and zone differs in WIND and
89    * cellhd, and Rast_open_old fails, so it is better to read window from map */
90   /* G_get_window( &window ); */
91   Rast_get_cellhd( name, mapset, &window );
92   window.west = atof( win->answers[0] );
93   window.south = atof( win->answers[1] );
94   window.east = atof( win->answers[2] );
95   window.north = atof( win->answers[3] );
96   window.cols = atoi( win->answers[4] );
97   window.rows = atoi( win->answers[5] );
98   G_adjust_Cell_head( &window, 1, 1 );
99   G_set_window( &window );
100 
101   Rast_suppress_masking(); // must be after G_set_window()
102 
103   raster_type = Rast_map_type( name, "" );
104 
105   display( name, mapset, raster_type, format->answer );
106 
107   exit( EXIT_SUCCESS );
108 }
109 
110 static int cell_draw( char *, char *, struct Colors *, RASTER_MAP_TYPE, char *format );
111 
display(char * name,char * mapset,RASTER_MAP_TYPE data_type,char * format)112 int display( char *name,
113              char *mapset,
114              RASTER_MAP_TYPE data_type,
115              char *format )
116 {
117   struct Colors colors;
118 
119   if ( Rast_read_colors( name, mapset, &colors ) == -1 )
120     G_fatal_error( ( "Color file for <%s> not available" ), name );
121 
122   //G_set_null_value_color(r, g, b, &colors);
123 
124   /* Go draw the raster map */
125   cell_draw( name, mapset, &colors, data_type, format );
126 
127   /* release the colors now */
128   Rast_free_colors( &colors );
129 
130   return 0;
131 }
132 
cell_draw(char * name,char * mapset,struct Colors * colors,RASTER_MAP_TYPE data_type,char * format)133 static int cell_draw( char *name,
134                       char *mapset,
135                       struct Colors *colors,
136                       RASTER_MAP_TYPE data_type,
137                       char *format )
138 {
139   int cellfile;
140   void *xarray = 0;
141   int row;
142   int ncols, nrows;
143   static unsigned char *red, *grn, *blu, *set;
144   int i;
145   void *ptr = 0;
146   int big_endian;
147   long one = 1;
148   FILE *fo = 0;
149   size_t raster_size;
150 #ifdef NAN
151   double dnul = NAN;
152   float fnul = ( float )( NAN );
153 #else
154   double dnul = strtod( "NAN", 0 );
155   float fnul = strtof( "NAN", 0 );
156   // another possibility would be nan()/nanf() - C99
157   // and 0./0. if all fails
158 #endif
159 
160   assert( dnul != dnul );
161   assert( fnul != fnul );
162 
163   big_endian = !( *( ( char * )( &one ) ) );
164 
165   ncols = Rast_window_cols();
166   nrows = Rast_window_rows();
167 
168   /* Make sure map is available */
169   if ( ( cellfile = Rast_open_old( name, mapset ) ) == -1 )
170     G_fatal_error( ( "Unable to open raster map <%s>" ), name );
171 
172   /* Allocate space for cell buffer */
173   xarray = Rast_allocate_buf( data_type );
174   red = G_malloc( ncols );
175   grn = G_malloc( ncols );
176   blu = G_malloc( ncols );
177   set = G_malloc( ncols );
178 
179   /* some buggy C libraries require BOTH setmode() and fdopen(bin) */
180   // Do not use Q_OS_WIN, we are in C file, no Qt headers
181 #ifdef WIN32
182   if ( _setmode( _fileno( stdout ), _O_BINARY ) == -1 )
183     G_fatal_error( "Cannot set stdout mode" );
184 #endif
185   // Unfortunately this is not sufficient on Windows to switch stdout to binary mode
186   fo = fdopen( fileno( stdout ), "wb" );
187 
188   raster_size = Rast_cell_size( data_type );
189   //fprintf( fo, "%d %d", data_type, raster_size );
190   //exit(0);
191   /* loop for array rows */
192   for ( row = 0; row < nrows; row++ )
193   {
194     Rast_get_row( cellfile, xarray, row, data_type );
195     ptr = xarray;
196 
197     Rast_lookup_colors( xarray, red, grn, blu, set, ncols, colors,
198                         data_type );
199 
200     for ( i = 0; i < ncols; i++ )
201     {
202       unsigned char alpha = 255;
203       //G_debug ( 0, "row = %d col = %d", row, i );
204       if ( Rast_is_null_value( ptr, data_type ) )
205       {
206         alpha = 0;
207       }
208 
209       if ( strcmp( format, "color" ) == 0 )
210       {
211         // We need data suitable for QImage 32-bpp
212         // the data are stored in QImage as QRgb which is unsigned int.
213         // Because it depends on byte order of the platform we have to
214         // consider byte order (well, middle endian ignored)
215         if ( big_endian )
216         {
217           // I have never tested this
218           fprintf( fo, "%c%c%c%c", alpha, red[i], grn[i], blu[i] );
219         }
220         else
221         {
222           fprintf( fo, "%c%c%c%c", blu[i], grn[i], red[i], alpha );
223         }
224       }
225       else
226       {
227         if ( data_type == CELL_TYPE )
228         {
229           //G_debug ( 0, "valx = %d", *((CELL *) ptr));
230         }
231         if ( Rast_is_null_value( ptr, data_type ) )
232         {
233           // see comments in QgsGrassRasterProvider::noDataValue()
234           if ( data_type == CELL_TYPE )
235           {
236             //int nul = -2000000000;
237             int nul = INT_MIN;
238             fwrite( &nul, 4, 1, fo );
239           }
240           else if ( data_type == DCELL_TYPE )
241           {
242             //double nul = -1e+300;
243             fwrite( &dnul, 8, 1, fo );
244           }
245           else if ( data_type == FCELL_TYPE )
246           {
247             //double nul = -1e+30;
248             fwrite( &fnul, 4, 1, fo );
249           }
250         }
251         else
252         {
253           fwrite( ptr, raster_size, 1, fo );
254         }
255       }
256       ptr = G_incr_void_ptr( ptr, raster_size );
257     }
258   }
259 
260   Rast_close( cellfile );
261   fclose( fo );
262 
263   return ( 0 );
264 }
265