]> Pileus Git - aweather/blob - src/plugins/level2.c
Move RSL file handling to level2 object
[aweather] / src / plugins / level2.c
1 /*
2  * Copyright (C) 2009-2010 Andy Spencer <andy753421@gmail.com>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <config.h>
19 #include <math.h>
20 #include <GL/gl.h>
21 #include <glib/gstdio.h>
22 #include <gis.h>
23 #include <rsl.h>
24
25 #include "level2.h"
26
27
28 /**************************
29  * Data loading functions *
30  **************************/
31 /* Convert a sweep to an 2d array of data points */
32 static void _bscan_sweep(Sweep *sweep, AWeatherColormap *colormap,
33                 guint8 **data, int *width, int *height)
34 {
35         g_debug("AWeatherLevel2: _bscan_sweep - %p, %p, %p",
36                         sweep, colormap, data);
37         /* Calculate max number of bins */
38         int max_bins = 0;
39         for (int i = 0; i < sweep->h.nrays; i++)
40                 max_bins = MAX(max_bins, sweep->ray[i]->h.nbins);
41
42         /* Allocate buffer using max number of bins for each ray */
43         guint8 *buf = g_malloc0(sweep->h.nrays * max_bins * 4);
44
45         /* Fill the data */
46         for (int ri = 0; ri < sweep->h.nrays; ri++) {
47                 Ray *ray  = sweep->ray[ri];
48                 for (int bi = 0; bi < ray->h.nbins; bi++) {
49                         /* copy RGBA into buffer */
50                         //guint val   = dz_f(ray->range[bi]);
51                         guint8 val   = (guint8)ray->h.f(ray->range[bi]);
52                         guint  buf_i = (ri*max_bins+bi)*4;
53                         buf[buf_i+0] = colormap->data[val][0];
54                         buf[buf_i+1] = colormap->data[val][1];
55                         buf[buf_i+2] = colormap->data[val][2];
56                         buf[buf_i+3] = colormap->data[val][3]*0.75; // TESTING
57                         if (val == BADVAL     || val == RFVAL      || val == APFLAG ||
58                             val == NOTFOUND_H || val == NOTFOUND_V || val == NOECHO) {
59                                 buf[buf_i+3] = 0x00; // transparent
60                         }
61                 }
62         }
63
64         /* set output */
65         *width  = max_bins;
66         *height = sweep->h.nrays;
67         *data   = buf;
68 }
69
70 /* Load a sweep into an OpenGL texture */
71 static void _load_sweep_gl(Sweep *sweep, AWeatherColormap *colormap, guint *tex)
72 {
73         g_debug("AWeatherLevel2: _load_sweep_gl");
74         int height, width;
75         guint8 *data;
76         _bscan_sweep(sweep, colormap, &data, &width, &height);
77         glGenTextures(1, tex);
78         glBindTexture(GL_TEXTURE_2D, *tex);
79         glPixelStorei(GL_PACK_ALIGNMENT, 1);
80         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
81         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
82         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
83         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
84                         GL_RGBA, GL_UNSIGNED_BYTE, data);
85         g_free(data);
86 }
87
88 /* Decompress a radar file using wsr88dec */
89 static gboolean _decompress_radar(const gchar *file, const gchar *raw)
90 {
91         g_debug("AWeatherLevel2: _decompress_radar - \n\t%s\n\t%s", file, raw);
92         char *argv[] = {"wsr88ddec", (gchar*)file, (gchar*)raw, NULL};
93         gint status;
94         GError *error = NULL;
95         g_spawn_sync(
96                 NULL,    // const gchar *working_directory
97                 argv,    // gchar **argv
98                 NULL,    // gchar **envp
99                 G_SPAWN_SEARCH_PATH, // GSpawnFlags flags
100                 NULL,    // GSpawnChildSetupFunc child_setup
101                 NULL,    // gpointer user_data
102                 NULL,    // gchar *standard_output
103                 NULL,    // gchar *standard_output
104                 &status, // gint *exit_status
105                 &error); // GError **error
106         if (error) {
107                 g_warning("AWeatherLevel2: _decompress_radar - %s", error->message);
108                 g_error_free(error);
109                 return FALSE;
110         }
111         if (status != 0) {
112                 gchar *msg = g_strdup_printf("wsr88ddec exited with status %d", status);
113                 g_warning("AWeatherLevel2: _decompress_radar - %s", msg);
114                 g_free(msg);
115                 return FALSE;
116         }
117         return TRUE;
118 }
119
120
121 /*********************
122  * Drawing functions *
123  *********************/
124 static gpointer _draw_radar(GisCallback *_self, gpointer _viewer)
125 {
126         AWeatherLevel2 *self = AWEATHER_LEVEL2(_self);
127         if (!self->sweep || !self->sweep_tex)
128                 return NULL;
129
130         /* Draw wsr88d */
131         Sweep *sweep = self->sweep;
132         Radar_header *h = &self->radar->h;
133         gdouble lat  = (double)h->latd + (double)h->latm/60 + (double)h->lats/(60*60);
134         gdouble lon  = (double)h->lond + (double)h->lonm/60 + (double)h->lons/(60*60);
135         gdouble elev = h->height;
136         gis_viewer_center_position(self->viewer, lat, lon, elev);
137
138         glDisable(GL_ALPHA_TEST);
139         glDisable(GL_CULL_FACE);
140         glDisable(GL_LIGHTING);
141         glEnable(GL_TEXTURE_2D);
142         glEnable(GL_POLYGON_OFFSET_FILL);
143         glPolygonOffset(1.0, -2.0);
144         glColor4f(1,1,1,1);
145
146         /* Draw the rays */
147         glBindTexture(GL_TEXTURE_2D, self->sweep_tex);
148         g_message("Tex = %d", self->sweep_tex);
149         glBegin(GL_TRIANGLE_STRIP);
150         for (int ri = 0; ri <= sweep->h.nrays; ri++) {
151                 Ray  *ray = NULL;
152                 double angle = 0;
153                 if (ri < sweep->h.nrays) {
154                         ray = sweep->ray[ri];
155                         angle = deg2rad(ray->h.azimuth - ((double)ray->h.beam_width/2.));
156                 } else {
157                         /* Do the right side of the last sweep */
158                         ray = sweep->ray[ri-1];
159                         angle = deg2rad(ray->h.azimuth + ((double)ray->h.beam_width/2.));
160                 }
161
162                 double lx = sin(angle);
163                 double ly = cos(angle);
164
165                 double near_dist = ray->h.range_bin1;
166                 double far_dist  = ray->h.nbins*ray->h.gate_size + ray->h.range_bin1;
167
168                 /* (find middle of bin) / scale for opengl */
169                 // near left
170                 glTexCoord2f(0.0, (double)ri/sweep->h.nrays-0.01);
171                 glVertex3f(lx*near_dist, ly*near_dist, 2.0);
172
173                 // far  left
174                 // todo: correct range-height function
175                 double height = sin(deg2rad(ray->h.elev)) * far_dist;
176                 glTexCoord2f(1.0, (double)ri/sweep->h.nrays-0.01);
177                 glVertex3f(lx*far_dist,  ly*far_dist, height);
178         }
179         glEnd();
180         //g_print("ri=%d, nr=%d, bw=%f\n", _ri, sweep->h.nrays, sweep->h.beam_width);
181
182         /* Texture debug */
183         //glBegin(GL_QUADS);
184         //glTexCoord2d( 0.,  0.); glVertex3f(-500.,   0., 0.); // bot left
185         //glTexCoord2d( 0.,  1.); glVertex3f(-500., 500., 0.); // top left
186         //glTexCoord2d( 1.,  1.); glVertex3f( 0.,   500., 3.); // top right
187         //glTexCoord2d( 1.,  0.); glVertex3f( 0.,     0., 3.); // bot right
188         //glEnd();
189
190         return NULL;
191 }
192
193
194 /***********
195  * Methods *
196  ***********/
197 static gboolean _set_sweep_cb(gpointer _self)
198 {
199         g_debug("AWeatherLevel2: _set_sweep_cb");
200         AWeatherLevel2 *self = _self;
201         if (self->sweep_tex)
202                 glDeleteTextures(1, &self->sweep_tex);
203         _load_sweep_gl(self->sweep, self->sweep_colors, &self->sweep_tex);
204         gtk_widget_queue_draw(GTK_WIDGET(self->viewer));
205         return FALSE;
206 }
207 void aweather_level2_set_sweep(AWeatherLevel2 *self,
208                 int type, float elev)
209 {
210         g_debug("AWeatherLevel2: set_sweep - %d %f", type, elev);
211
212         /* Find sweep */
213         Volume *volume = RSL_get_volume(self->radar, type);
214         if (!volume) return;
215         self->sweep = RSL_get_closest_sweep(volume, elev, 90);
216         if (!self->sweep) return;
217
218         /* Find colormap */
219         self->sweep_colors = NULL;
220         for (int i = 0; self->colormap[i].name; i++)
221                 if (self->colormap[i].type == type)
222                         self->sweep_colors = &self->colormap[i];
223         if (!self->sweep_colors) return;
224
225         /* Load data */
226         g_idle_add(_set_sweep_cb, self);
227 }
228
229 AWeatherLevel2 *aweather_level2_new(GisViewer *viewer,
230                 AWeatherColormap *colormap, Radar *radar)
231 {
232         g_debug("AWeatherLevel2: new");
233         AWeatherLevel2 *self = g_object_new(AWEATHER_TYPE_LEVEL2, NULL);
234         self->viewer   = viewer;
235         self->radar    = radar;
236         self->colormap = colormap;
237         aweather_level2_set_sweep(self, DZ_INDEX, 0);
238         return self;
239 }
240
241 AWeatherLevel2 *aweather_level2_new_from_file(GisViewer *viewer,
242                 AWeatherColormap *colormap,
243                 const gchar *file, const gchar *site)
244 {
245         g_debug("AWeatherLevel2: new_from_file %s %s", site, file);
246
247         /* Decompress radar */
248         gchar *raw = g_strconcat(file, ".raw", NULL);
249         if (g_file_test(raw, G_FILE_TEST_EXISTS)) {
250                 struct stat files, raws;
251                 g_stat(file, &files);
252                 g_stat(raw,  &raws);
253                 if (files.st_mtime < raws.st_mtime)
254                         if (!_decompress_radar(file, raw))
255                                 return NULL;
256         } else {
257                 if (!_decompress_radar(file, raw))
258                         return NULL;
259         }
260
261         /* Load the radar file */
262         RSL_read_these_sweeps("all", NULL);
263         Radar *radar = RSL_wsr88d_to_radar(raw, (gchar*)site);
264         g_free(raw);
265         if (!radar)
266                 return NULL;
267
268         return aweather_level2_new(viewer, colormaps, radar);
269 }
270
271
272 /****************
273  * GObject code *
274  ****************/
275 G_DEFINE_TYPE(AWeatherLevel2, aweather_level2, GIS_TYPE_CALLBACK);
276 static void aweather_level2_init(AWeatherLevel2 *self)
277 {
278         GIS_CALLBACK(self)->callback  = _draw_radar;
279         GIS_CALLBACK(self)->user_data = self;
280 }
281
282 static void aweather_level2_class_init(AWeatherLevel2Class *klass)
283 {
284 }
285