From c0e52fc233205fb646326a0efd86e4359f51d96c Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Sun, 7 Feb 2010 17:33:47 +0000 Subject: [PATCH] Move RSL file handling to level2 object This lets us add multiple radars. It also makes things cleaner and will hopefully make threading easier. However, it's still buggy and crashes all the time. --- src/Makefile.am | 4 +- .../radar-colormap.c => aweather-colormap.c} | 31 +- src/aweather-colormap.h | 32 ++ src/plugins/Makefile.am | 6 +- src/plugins/level2.c | 285 +++++++++++ src/plugins/level2.h | 58 +++ src/plugins/radar.c | 445 ++++-------------- src/plugins/radar.h | 43 +- 8 files changed, 529 insertions(+), 375 deletions(-) rename src/{plugins/radar-colormap.c => aweather-colormap.c} (96%) create mode 100644 src/aweather-colormap.h create mode 100644 src/plugins/level2.c create mode 100644 src/plugins/level2.h diff --git a/src/Makefile.am b/src/Makefile.am index b0ea82c..47856d0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,7 +6,9 @@ bin_PROGRAMS = aweather wsr88ddec aweather_SOURCES = main.c \ aweather-gui.c aweather-gui.h \ aweather-location.c aweather-location.h -aweather_CPPFLAGS = -DPKGDATADIR="\"$(pkgdatadir)\"" -DPLUGINSDIR="\"$(pkglibdir)\"" +aweather_CPPFLAGS = \ + -DPKGDATADIR="\"$(pkgdatadir)\"" \ + -DPLUGINSDIR="\"$(pkglibdir)\"" aweather_CFLAGS = $(GIS_CFLAGS) $(AM_CFLAGS) aweather_LDADD = $(GIS_LIBS) diff --git a/src/plugins/radar-colormap.c b/src/aweather-colormap.c similarity index 96% rename from src/plugins/radar-colormap.c rename to src/aweather-colormap.c index 03b2f32..0fb289a 100644 --- a/src/plugins/radar-colormap.c +++ b/src/aweather-colormap.c @@ -1,5 +1,22 @@ -#include -#include "radar.h" +/* + * Copyright (C) 2009-2010 Andy Spencer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "aweather-colormap.h" //{0xcc,0xff,0xff,0xff},{0xcc,0xff,0xff,0xff}, {0xcc,0xff,0xff,0xff}, //{0xcc,0x99,0xcc,0xff},{0xcc,0x99,0xcc,0xff}, {0xcc,0x99,0xcc,0xff}, @@ -7,8 +24,8 @@ //{0x66,0x33,0x66,0xff},{0x66,0x33,0x66,0xff}, {0x66,0x33,0x66,0xff}, //{0xcc,0xcc,0x99,0xff},{0xcc,0xcc,0x99,0xff}, {0xcc,0xcc,0x99,0xff}, //{0x99,0x99,0x66,0xff},{0x99,0x99,0x66,0xff}, {0x99,0x99,0x66,0xff}, -colormap_t colormaps[] = { - {"Reflectivity", +AWeatherColormap colormaps[] = { + {DZ_INDEX, "Reflectivity", {{0x00,0x00,0x00,0x00}, // 0 dBZ {0x00,0x00,0x00,0x00}, // 1 dBZ {0x00,0x00,0x00,0x00}, // 2 dBZ @@ -265,7 +282,7 @@ colormap_t colormaps[] = { {0x00,0x00,0x00,0x00}, {0x00,0x00,0x00,0x00}, {0x00,0x00,0x00,0x00}}}, - {"Velocity", + {VR_INDEX, "Velocity", { {0x88,0x88,0x88,0x00}, // 0 {0x98,0x77,0x77,0xff}, // 1 @@ -524,7 +541,7 @@ colormap_t colormaps[] = { {0x7c,0x97,0x7b,0xff}, // -2 {0x7c,0x97,0x7b,0xff}, // -1 }}, - {"Spectrum width", + {SW_INDEX, "Spectrum width", {{0x00,0x00,0x00,0x00}, {0x00,0x00,0xa0,0xff}, {0x00,0x00,0xd0,0xff}, @@ -781,5 +798,5 @@ colormap_t colormaps[] = { {0x00,0x00,0x00,0xff}, {0x00,0x00,0x00,0xff}, {0x00,0x00,0x00,0xff}}}, - {NULL, {{}}}, + {0, NULL, {{}}}, }; diff --git a/src/aweather-colormap.h b/src/aweather-colormap.h new file mode 100644 index 0000000..e92dffc --- /dev/null +++ b/src/aweather-colormap.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2009-2010 Andy Spencer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __AWEATHER_COLORMAP_H__ +#define __AWEATHER_COLORMAP_H__ + +#include +#include + +typedef struct { + int type; + const char *name; + guint8 data[256][4]; +} AWeatherColormap; + +extern AWeatherColormap colormaps[]; + +#endif diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index cf4029a..5dca79d 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -9,8 +9,10 @@ plugins_LTLIBRARIES = if HAVE_RSL plugins_LTLIBRARIES += radar.la -radar_la_SOURCES = radar.c radar.h \ - radar-colormap.c \ +radar_la_SOURCES = \ + radar.c radar.h \ + level2.c level2.h \ + ../aweather-colormap.c \ ../aweather-location.c radar_la_LDFLAGS = $(AM_LDFLAGS) $(RSL_LIBS) endif diff --git a/src/plugins/level2.c b/src/plugins/level2.c new file mode 100644 index 0000000..3fa7d4e --- /dev/null +++ b/src/plugins/level2.c @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2009-2010 Andy Spencer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "level2.h" + + +/************************** + * Data loading functions * + **************************/ +/* Convert a sweep to an 2d array of data points */ +static void _bscan_sweep(Sweep *sweep, AWeatherColormap *colormap, + guint8 **data, int *width, int *height) +{ + g_debug("AWeatherLevel2: _bscan_sweep - %p, %p, %p", + sweep, colormap, data); + /* Calculate max number of bins */ + int max_bins = 0; + for (int i = 0; i < sweep->h.nrays; i++) + max_bins = MAX(max_bins, sweep->ray[i]->h.nbins); + + /* Allocate buffer using max number of bins for each ray */ + guint8 *buf = g_malloc0(sweep->h.nrays * max_bins * 4); + + /* Fill the data */ + for (int ri = 0; ri < sweep->h.nrays; ri++) { + Ray *ray = sweep->ray[ri]; + for (int bi = 0; bi < ray->h.nbins; bi++) { + /* copy RGBA into buffer */ + //guint val = dz_f(ray->range[bi]); + guint8 val = (guint8)ray->h.f(ray->range[bi]); + guint buf_i = (ri*max_bins+bi)*4; + buf[buf_i+0] = colormap->data[val][0]; + buf[buf_i+1] = colormap->data[val][1]; + buf[buf_i+2] = colormap->data[val][2]; + buf[buf_i+3] = colormap->data[val][3]*0.75; // TESTING + if (val == BADVAL || val == RFVAL || val == APFLAG || + val == NOTFOUND_H || val == NOTFOUND_V || val == NOECHO) { + buf[buf_i+3] = 0x00; // transparent + } + } + } + + /* set output */ + *width = max_bins; + *height = sweep->h.nrays; + *data = buf; +} + +/* Load a sweep into an OpenGL texture */ +static void _load_sweep_gl(Sweep *sweep, AWeatherColormap *colormap, guint *tex) +{ + g_debug("AWeatherLevel2: _load_sweep_gl"); + int height, width; + guint8 *data; + _bscan_sweep(sweep, colormap, &data, &width, &height); + glGenTextures(1, tex); + glBindTexture(GL_TEXTURE_2D, *tex); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, data); + g_free(data); +} + +/* Decompress a radar file using wsr88dec */ +static gboolean _decompress_radar(const gchar *file, const gchar *raw) +{ + g_debug("AWeatherLevel2: _decompress_radar - \n\t%s\n\t%s", file, raw); + char *argv[] = {"wsr88ddec", (gchar*)file, (gchar*)raw, NULL}; + gint status; + GError *error = NULL; + g_spawn_sync( + NULL, // const gchar *working_directory + argv, // gchar **argv + NULL, // gchar **envp + G_SPAWN_SEARCH_PATH, // GSpawnFlags flags + NULL, // GSpawnChildSetupFunc child_setup + NULL, // gpointer user_data + NULL, // gchar *standard_output + NULL, // gchar *standard_output + &status, // gint *exit_status + &error); // GError **error + if (error) { + g_warning("AWeatherLevel2: _decompress_radar - %s", error->message); + g_error_free(error); + return FALSE; + } + if (status != 0) { + gchar *msg = g_strdup_printf("wsr88ddec exited with status %d", status); + g_warning("AWeatherLevel2: _decompress_radar - %s", msg); + g_free(msg); + return FALSE; + } + return TRUE; +} + + +/********************* + * Drawing functions * + *********************/ +static gpointer _draw_radar(GisCallback *_self, gpointer _viewer) +{ + AWeatherLevel2 *self = AWEATHER_LEVEL2(_self); + if (!self->sweep || !self->sweep_tex) + return NULL; + + /* Draw wsr88d */ + Sweep *sweep = self->sweep; + Radar_header *h = &self->radar->h; + gdouble lat = (double)h->latd + (double)h->latm/60 + (double)h->lats/(60*60); + gdouble lon = (double)h->lond + (double)h->lonm/60 + (double)h->lons/(60*60); + gdouble elev = h->height; + gis_viewer_center_position(self->viewer, lat, lon, elev); + + glDisable(GL_ALPHA_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_LIGHTING); + glEnable(GL_TEXTURE_2D); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.0, -2.0); + glColor4f(1,1,1,1); + + /* Draw the rays */ + glBindTexture(GL_TEXTURE_2D, self->sweep_tex); + g_message("Tex = %d", self->sweep_tex); + glBegin(GL_TRIANGLE_STRIP); + for (int ri = 0; ri <= sweep->h.nrays; ri++) { + Ray *ray = NULL; + double angle = 0; + if (ri < sweep->h.nrays) { + ray = sweep->ray[ri]; + angle = deg2rad(ray->h.azimuth - ((double)ray->h.beam_width/2.)); + } else { + /* Do the right side of the last sweep */ + ray = sweep->ray[ri-1]; + angle = deg2rad(ray->h.azimuth + ((double)ray->h.beam_width/2.)); + } + + double lx = sin(angle); + double ly = cos(angle); + + double near_dist = ray->h.range_bin1; + double far_dist = ray->h.nbins*ray->h.gate_size + ray->h.range_bin1; + + /* (find middle of bin) / scale for opengl */ + // near left + glTexCoord2f(0.0, (double)ri/sweep->h.nrays-0.01); + glVertex3f(lx*near_dist, ly*near_dist, 2.0); + + // far left + // todo: correct range-height function + double height = sin(deg2rad(ray->h.elev)) * far_dist; + glTexCoord2f(1.0, (double)ri/sweep->h.nrays-0.01); + glVertex3f(lx*far_dist, ly*far_dist, height); + } + glEnd(); + //g_print("ri=%d, nr=%d, bw=%f\n", _ri, sweep->h.nrays, sweep->h.beam_width); + + /* Texture debug */ + //glBegin(GL_QUADS); + //glTexCoord2d( 0., 0.); glVertex3f(-500., 0., 0.); // bot left + //glTexCoord2d( 0., 1.); glVertex3f(-500., 500., 0.); // top left + //glTexCoord2d( 1., 1.); glVertex3f( 0., 500., 3.); // top right + //glTexCoord2d( 1., 0.); glVertex3f( 0., 0., 3.); // bot right + //glEnd(); + + return NULL; +} + + +/*********** + * Methods * + ***********/ +static gboolean _set_sweep_cb(gpointer _self) +{ + g_debug("AWeatherLevel2: _set_sweep_cb"); + AWeatherLevel2 *self = _self; + if (self->sweep_tex) + glDeleteTextures(1, &self->sweep_tex); + _load_sweep_gl(self->sweep, self->sweep_colors, &self->sweep_tex); + gtk_widget_queue_draw(GTK_WIDGET(self->viewer)); + return FALSE; +} +void aweather_level2_set_sweep(AWeatherLevel2 *self, + int type, float elev) +{ + g_debug("AWeatherLevel2: set_sweep - %d %f", type, elev); + + /* Find sweep */ + Volume *volume = RSL_get_volume(self->radar, type); + if (!volume) return; + self->sweep = RSL_get_closest_sweep(volume, elev, 90); + if (!self->sweep) return; + + /* Find colormap */ + self->sweep_colors = NULL; + for (int i = 0; self->colormap[i].name; i++) + if (self->colormap[i].type == type) + self->sweep_colors = &self->colormap[i]; + if (!self->sweep_colors) return; + + /* Load data */ + g_idle_add(_set_sweep_cb, self); +} + +AWeatherLevel2 *aweather_level2_new(GisViewer *viewer, + AWeatherColormap *colormap, Radar *radar) +{ + g_debug("AWeatherLevel2: new"); + AWeatherLevel2 *self = g_object_new(AWEATHER_TYPE_LEVEL2, NULL); + self->viewer = viewer; + self->radar = radar; + self->colormap = colormap; + aweather_level2_set_sweep(self, DZ_INDEX, 0); + return self; +} + +AWeatherLevel2 *aweather_level2_new_from_file(GisViewer *viewer, + AWeatherColormap *colormap, + const gchar *file, const gchar *site) +{ + g_debug("AWeatherLevel2: new_from_file %s %s", site, file); + + /* Decompress radar */ + gchar *raw = g_strconcat(file, ".raw", NULL); + if (g_file_test(raw, G_FILE_TEST_EXISTS)) { + struct stat files, raws; + g_stat(file, &files); + g_stat(raw, &raws); + if (files.st_mtime < raws.st_mtime) + if (!_decompress_radar(file, raw)) + return NULL; + } else { + if (!_decompress_radar(file, raw)) + return NULL; + } + + /* Load the radar file */ + RSL_read_these_sweeps("all", NULL); + Radar *radar = RSL_wsr88d_to_radar(raw, (gchar*)site); + g_free(raw); + if (!radar) + return NULL; + + return aweather_level2_new(viewer, colormaps, radar); +} + + +/**************** + * GObject code * + ****************/ +G_DEFINE_TYPE(AWeatherLevel2, aweather_level2, GIS_TYPE_CALLBACK); +static void aweather_level2_init(AWeatherLevel2 *self) +{ + GIS_CALLBACK(self)->callback = _draw_radar; + GIS_CALLBACK(self)->user_data = self; +} + +static void aweather_level2_class_init(AWeatherLevel2Class *klass) +{ +} + diff --git a/src/plugins/level2.h b/src/plugins/level2.h new file mode 100644 index 0000000..3577ed5 --- /dev/null +++ b/src/plugins/level2.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2009-2010 Andy Spencer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __AWEATHER_LEVEL2_H__ +#define __AWEATHER_LEVEL2_H__ + +#include +#include "aweather-colormap.h" + +/* Level2 */ +#define AWEATHER_TYPE_LEVEL2 (aweather_level2_get_type()) + +GOBJECT_HEAD( + AWEATHER, LEVEL2, + AWeather, Level2, + aweather, level2); + +struct _AWeatherLevel2 { + GisCallback parent; + GisViewer *viewer; + Radar *radar; + AWeatherColormap *colormap; + + /* Private */ + Sweep *sweep; + AWeatherColormap *sweep_colors; + guint sweep_tex; +}; + +struct _AWeatherLevel2Class { + GisCallbackClass parent_class; +}; + +AWeatherLevel2 *aweather_level2_new(GisViewer *viewer, + AWeatherColormap *colormap, Radar *radar); + +AWeatherLevel2 *aweather_level2_new_from_file(GisViewer *viewer, + AWeatherColormap *colormap, + const gchar *file, const gchar *site); + +void aweather_level2_set_sweep(AWeatherLevel2 *level2, + int type, float elev); + +#endif diff --git a/src/plugins/radar.c b/src/plugins/radar.c index 28de17c..7a1bf45 100644 --- a/src/plugins/radar.c +++ b/src/plugins/radar.c @@ -27,100 +27,58 @@ #include #include "radar.h" +#include "level2.h" #include "../aweather-location.h" - -/************************** - * Data loading functions * - **************************/ -/* Convert a sweep to an 2d array of data points */ -static void _bscan_sweep(GisPluginRadar *self, Sweep *sweep, colormap_t *colormap, - guint8 **data, int *width, int *height) +/* Drawing functions */ +static gpointer _draw_hud(GisCallback *callback, gpointer _self) { - g_debug("GisPluginRadar: _bscan_sweep - %p, %p, %p", - sweep, colormap, data); - /* Calculate max number of bins */ - int max_bins = 0; - for (int i = 0; i < sweep->h.nrays; i++) - max_bins = MAX(max_bins, sweep->ray[i]->h.nbins); - - /* Allocate buffer using max number of bins for each ray */ - guint8 *buf = g_malloc0(sweep->h.nrays * max_bins * 4); - - /* Fill the data */ - for (int ri = 0; ri < sweep->h.nrays; ri++) { - Ray *ray = sweep->ray[ri]; - for (int bi = 0; bi < ray->h.nbins; bi++) { - /* copy RGBA into buffer */ - //guint val = dz_f(ray->range[bi]); - guint8 val = (guint8)ray->h.f(ray->range[bi]); - guint buf_i = (ri*max_bins+bi)*4; - buf[buf_i+0] = colormap->data[val][0]; - buf[buf_i+1] = colormap->data[val][1]; - buf[buf_i+2] = colormap->data[val][2]; - buf[buf_i+3] = colormap->data[val][3]*0.75; // TESTING - if (val == BADVAL || val == RFVAL || val == APFLAG || - val == NOTFOUND_H || val == NOTFOUND_V || val == NOECHO) { - buf[buf_i+3] = 0x00; // transparent - } - } - } - - /* set output */ - *width = max_bins; - *height = sweep->h.nrays; - *data = buf; -} + GisPluginRadar *self = GIS_PLUGIN_RADAR(_self); + if (!self->colormap) + return NULL; -/* Load a sweep as the active texture */ -static gboolean _load_sweep(gpointer _self) -{ - GisPluginRadar *self = _self; - if (!self->cur_sweep) - return FALSE; - g_debug("GisPluginRadar: _load_sweep - %p", self->cur_sweep); - int height, width; - guint8 *data; - _bscan_sweep(self, self->cur_sweep, self->cur_colormap, &data, &width, &height); - glDeleteTextures(1, &self->cur_sweep_tex); - glGenTextures(1, &self->cur_sweep_tex); - glBindTexture(GL_TEXTURE_2D, self->cur_sweep_tex); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, data); - g_free(data); - gtk_widget_queue_draw(GTK_WIDGET(self->viewer)); - return FALSE; -} + g_debug("GisPluginRadar: _draw_hud"); + /* Print the color table */ + glMatrixMode(GL_MODELVIEW ); glLoadIdentity(); + glMatrixMode(GL_PROJECTION); glLoadIdentity(); + glDisable(GL_TEXTURE_2D); + glDisable(GL_ALPHA_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_LIGHTING); + glEnable(GL_COLOR_MATERIAL); + glBegin(GL_QUADS); + int i; + for (i = 0; i < 256; i++) { + glColor4ubv(self->colormap->data[i]); + glVertex3f(-1.0, (float)((i ) - 256/2)/(256/2), 0.0); // bot left + glVertex3f(-1.0, (float)((i+1) - 256/2)/(256/2), 0.0); // top left + glVertex3f(-0.9, (float)((i+1) - 256/2)/(256/2), 0.0); // top right + glVertex3f(-0.9, (float)((i ) - 256/2)/(256/2), 0.0); // bot right + } + glEnd(); -/* Load the colormap for a sweep */ -static void _load_colormap(GisPluginRadar *self, gchar *table) -{ - g_debug("GisPluginRadar: _load_colormap - %s", table); - /* Set colormap so we can draw it on expose */ - for (int i = 0; colormaps[i].name; i++) - if (g_str_equal(colormaps[i].name, table)) - self->cur_colormap = &colormaps[i]; + return NULL; } /*************** * GUI loading * ***************/ +/* Clear the config area */ +static void _load_gui_clear(GisPluginRadar *self) +{ + GtkWidget *child = gtk_bin_get_child(GTK_BIN(self->config_body)); + if (child) + gtk_widget_destroy(child); +} + /* Setup a loading screen in the tab */ static void _load_gui_pre(GisPluginRadar *self) { g_debug("GisPluginRadar: _load_gui_pre"); - gdk_threads_enter(); /* Set up progress bar */ - GtkWidget *child = gtk_bin_get_child(GTK_BIN(self->config_body)); - if (child) - gtk_widget_destroy(child); - + _load_gui_clear(self); GtkWidget *vbox = gtk_vbox_new(FALSE, 10); gtk_container_set_border_width(GTK_CONTAINER(vbox), 10); self->progress_bar = gtk_progress_bar_new(); @@ -129,14 +87,6 @@ static void _load_gui_pre(GisPluginRadar *self) gtk_box_pack_start(GTK_BOX(vbox), self->progress_label, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(self->config_body), vbox); gtk_widget_show_all(self->config_body); - - /* Clear radar */ - if (self->cur_radar) - RSL_free_radar(self->cur_radar); - self->cur_radar = NULL; - self->cur_sweep = NULL; - gtk_widget_queue_draw(GTK_WIDGET(self->viewer)); - gdk_threads_leave(); } /* Update pogress bar of loading screen */ @@ -148,13 +98,11 @@ static void _load_gui_update(char *path, goffset cur, goffset total, gpointer _s //g_debug("GisPluginRadar: cache_chunk_cb - %lld/%lld = %.2f%%", // cur, total, percent*100); - gdk_threads_enter(); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(self->progress_bar), MIN(percent, 1.0)); gchar *msg = g_strdup_printf("Loading radar... %5.1f%% (%.2f/%.2f MB)", percent*100, (double)cur/1000000, (double)total/1000000); gtk_label_set_text(GTK_LABEL(self->progress_label), msg); - gdk_threads_leave(); g_free(msg); } @@ -164,26 +112,20 @@ static void _load_gui_error(GisPluginRadar *self, gchar *error) gchar *msg = g_strdup_printf( "GisPluginRadar: error loading radar - %s", error); g_warning("%s", msg); - gdk_threads_enter(); - GtkWidget *child = gtk_bin_get_child(GTK_BIN(self->config_body)); - if (child) - gtk_widget_destroy(child); + _load_gui_clear(self); gtk_container_add(GTK_CONTAINER(self->config_body), gtk_label_new(msg)); gtk_widget_show_all(self->config_body); - gdk_threads_leave(); g_free(msg); } /* Clear loading screen and add sweep selectors */ static void _on_sweep_clicked(GtkRadioButton *button, gpointer _self); -static void _load_gui_success(GisPluginRadar *self, Radar *radar) +static void _load_gui_success(GisPluginRadar *self, AWeatherLevel2 *level2) { + Radar *radar = level2->radar; g_debug("GisPluginRadar: _load_gui_success - %p", radar); /* Clear existing items */ - gdk_threads_enter(); - GtkWidget *child = gtk_bin_get_child(GTK_BIN(self->config_body)); - if (child) - gtk_widget_destroy(child); + _load_gui_clear(self); gdouble elev; guint rows = 1, cols = 1, cur_cols; @@ -238,21 +180,16 @@ static void _load_gui_success(GisPluginRadar *self, Radar *radar) g_object_set(button, "draw-indicator", FALSE, NULL); gtk_box_pack_end(GTK_BOX(elev_box), button, TRUE, TRUE, 0); - g_object_set_data(G_OBJECT(button), "type", vol->h.type_str); - g_object_set_data(G_OBJECT(button), "sweep", sweep); + g_object_set_data(G_OBJECT(button), "level2", (gpointer)level2); + g_object_set_data(G_OBJECT(button), "type", (gpointer)vi); + g_object_set_data(G_OBJECT(button), "elev", (gpointer)(int)(elev*100)); g_signal_connect(button, "clicked", G_CALLBACK(_on_sweep_clicked), self); } } gtk_container_add(GTK_CONTAINER(self->config_body), table); gtk_widget_show_all(table); - gdk_threads_leave(); } - -/***************** - * Radar caching * - *****************/ -/* Download a compressed radar file from the remote server */ static gchar *_download_radar(GisPluginRadar *self, const gchar *site, const gchar *time) { g_debug("GisPluginRadar: _download_radar - %s, %s", site, time); @@ -262,157 +199,86 @@ static gchar *_download_radar(GisPluginRadar *self, const gchar *site, const gch gchar *local = g_strdup_printf("%s/%s_%s", site, site, time); gchar *uri = g_strconcat(base, "/", local, NULL); GisCacheType mode = gis_viewer_get_offline(self->viewer) ? GIS_LOCAL : GIS_UPDATE; - return gis_http_fetch(self->http, uri, local, mode, _load_gui_update, self); + gchar *file = gis_http_fetch(self->http, uri, local, mode, _load_gui_update, self); + g_free(base); + g_free(local); + g_free(uri); + return file; } -/* Decompress a radar file using wsr88dec */ -static gchar *_decompress_radar(GisPluginRadar *self, char *compressed) -{ - char *decompressed = g_strconcat(compressed, ".raw", NULL); - if (g_file_test(decompressed, G_FILE_TEST_EXISTS)) { - struct stat comp, dec; - g_stat(compressed, &comp); - g_stat(decompressed, &dec); - if (dec.st_mtime >= comp.st_mtime) - return decompressed; - } - g_debug("GisPluginRadar: _decompress_radar - %s", decompressed); - char *argv[] = {"wsr88ddec", compressed, decompressed, NULL}; - gint status; - GError *error = NULL; - g_spawn_sync( - NULL, // const gchar *working_directory - argv, // gchar **argv - NULL, // gchar **envp - G_SPAWN_SEARCH_PATH, // GSpawnFlags flags - NULL, // GSpawnChildSetupFunc child_setup - NULL, // gpointer user_data - NULL, // gchar *standard_output - NULL, // gchar *standard_output - &status, // gint *exit_status - &error); // GError **error - if (error) { - g_warning("GisPluginRadar: _decompress_radar - %s", error->message); - g_error_free(error); - return NULL; - } - if (status != 0) { - gchar *msg = g_strdup_printf("wsr88ddec exited with status %d", status); - g_warning("GisPluginRadar: _decompress_radar - %s", msg); - g_free(msg); - return NULL; - } - return decompressed; -} - - -/**************** - * Misc helpers * - ****************/ -/* Set the radar file based on cur_site andcur_time - * This should be run in a separatet hread */ -static gboolean _set_radar_cb(GisPluginRadar *self) +struct SetRadarData { + GisPluginRadar *self; + gchar *site; + gchar *time; +}; +static gpointer _set_radar_cb(gpointer _data) { g_debug("GisPluginRadar: _set_radar_cb"); + struct SetRadarData *data = _data; + GisPluginRadar *self = data->self; + gdk_threads_enter(); _load_gui_pre(self); - - /* Download and decompress the radar */ - gchar *compressed = _download_radar(self, - self->cur_site, self->cur_time); - if (!compressed) { - _load_gui_error(self, "Download failed"); - goto fail; - } - - /* Decompress radar */ - gchar *decompressed = _decompress_radar(self, compressed); - g_free(compressed); - if (!decompressed) { - _load_gui_error(self, "Decompression failed"); - goto fail; - } - - /* Load the radar file */ - g_debug("GisPluginRadar: _set_radar_cb - loading %s", decompressed); - RSL_read_these_sweeps("all", NULL); - self->cur_radar = RSL_wsr88d_to_radar(decompressed, self->cur_site); - g_free(decompressed); - if (!self->cur_radar) { - _load_gui_error(self, "Loading failed"); - goto fail; + if (self->radar) { + gis_viewer_remove(self->viewer, self->radar); + self->radar = NULL; } - - /* Load the first sweep by default */ - Radar *radar = self->cur_radar; - Sweep *sweep = NULL; - gchar *type_str = NULL; - for (int vi = 0; vi < radar->h.nvolumes; vi++) { - if (radar->v[vi] == NULL) - continue; - for (int si = 0; si < radar->v[vi]->h.nsweeps; si++) { - if (radar->v[vi]->sweep[si] == NULL) - continue; - sweep = radar->v[vi]->sweep[si]; - type_str = radar->v[vi]->h.type_str; - break; - } - break; + gchar *file = _download_radar(self, data->site, data->time); + if (!file) { + _load_gui_error(self, "Download failed"); + goto out; } - if (!type_str) { - _load_gui_error(self, "No sweeps found"); - goto fail; + AWeatherLevel2 *level2 = aweather_level2_new_from_file( + self->viewer, colormaps, file, data->site); + if (!level2) { + _load_gui_error(self, "Loading radar failed"); + //g_remove(file); + goto out; } + self->colormap = level2->sweep_colors; + self->radar = gis_viewer_add(self->viewer, GIS_OBJECT(level2), GIS_LEVEL_WORLD, TRUE); + _load_gui_success(self, level2); - /* Load weep */ - g_debug("GisPluginRadar: _set_radar_cb - setting sweep"); - self->cur_sweep = sweep; - _load_colormap(self, type_str); - g_idle_add(_load_sweep, self); - _load_gui_success(self, radar); - - /* Let other threads go */ - g_mutex_unlock(self->load_mutex); - return TRUE; - -fail: - g_mutex_unlock(self->load_mutex); - return TRUE; +out: + gdk_threads_leave(); + g_free(file); + g_free(data->site); + g_free(data->time); + g_free(data); + return NULL; } - -static void _set_radar(GisPluginRadar *self, - gchar *site, gchar *time) +static void _set_radar(GisPluginRadar *self, const gchar *site, const gchar *time) { - if (site) self->cur_site = site; - if (time) self->cur_time = time; - if (!self->cur_site || !self->cur_time) + if (!site || !time) return; - - /* Abort any current downloads */ - soup_session_abort(self->http->soup); - - g_mutex_lock(self->load_mutex); - - g_thread_create((GThreadFunc)_set_radar_cb, self, FALSE, NULL); + //soup_session_abort(self->http->soup); + //g_mutex_lock(self->load_mutex); + struct SetRadarData *data = g_new(struct SetRadarData, 1); + data->self = self; + data->site = g_strdup(site); + data->time = g_strdup(time); + g_thread_create(_set_radar_cb, data, FALSE, NULL); } - /************* * Callbacks * *************/ static void _on_sweep_clicked(GtkRadioButton *button, gpointer _self) { - GisPluginRadar *self = GIS_PLUGIN_RADAR(_self); - _load_colormap(self, g_object_get_data(G_OBJECT(button), "type")); - self->cur_sweep = g_object_get_data(G_OBJECT(button), "sweep"); - _load_sweep(self); + GisPluginRadar *self = GIS_PLUGIN_RADAR(_self); + AWeatherLevel2 *level2 = g_object_get_data(G_OBJECT(button), "level2"); + gint type = (gint)g_object_get_data(G_OBJECT(button), "type"); + gint elev = (gint)g_object_get_data(G_OBJECT(button), "elev"); + aweather_level2_set_sweep(level2, type, (float)elev/100); + self->colormap = level2->sweep_colors; } static void _on_time_changed(GisViewer *viewer, const char *time, gpointer _self) { g_debug("GisPluginRadar: _on_time_changed"); GisPluginRadar *self = GIS_PLUGIN_RADAR(_self); - _set_radar(self, self->cur_site, g_strdup(time)); + self->cur_time = g_strdup(time); + _set_radar(self, self->cur_site, self->cur_time); } static void _on_location_changed(GisViewer *viewer, @@ -439,110 +305,11 @@ static void _on_location_changed(GisViewer *viewer, } } static city_t *last_city = NULL; - if (min_city && min_city != last_city) - _set_radar(self, min_city->code, self->cur_time); - last_city = min_city; -} - -static gpointer _draw_radar(GisCallback *callback, gpointer _self) -{ - GisPluginRadar *self = GIS_PLUGIN_RADAR(_self); - - /* Draw wsr88d */ - if (self->cur_sweep == NULL) - return NULL; - g_debug("GisPluginRadar: _draw_radar"); - Sweep *sweep = self->cur_sweep; - - g_debug("GisPluginRadar: _draw_radar - setting camera"); - Radar_header *h = &self->cur_radar->h; - gdouble lat = (double)h->latd + (double)h->latm/60 + (double)h->lats/(60*60); - gdouble lon = (double)h->lond + (double)h->lonm/60 + (double)h->lons/(60*60); - gdouble elev = h->height; - gis_viewer_center_position(self->viewer, lat, lon, elev); - - glDisable(GL_ALPHA_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_LIGHTING); - glEnable(GL_TEXTURE_2D); - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(1.0, -2.0); - glColor4f(1,1,1,1); - - /* Draw the rays */ - glBindTexture(GL_TEXTURE_2D, self->cur_sweep_tex); - g_message("Tex = %d", self->cur_sweep_tex); - glBegin(GL_TRIANGLE_STRIP); - for (int ri = 0; ri <= sweep->h.nrays; ri++) { - Ray *ray = NULL; - double angle = 0; - if (ri < sweep->h.nrays) { - ray = sweep->ray[ri]; - angle = deg2rad(ray->h.azimuth - ((double)ray->h.beam_width/2.)); - } else { - /* Do the right side of the last sweep */ - ray = sweep->ray[ri-1]; - angle = deg2rad(ray->h.azimuth + ((double)ray->h.beam_width/2.)); - } - - double lx = sin(angle); - double ly = cos(angle); - - double near_dist = ray->h.range_bin1; - double far_dist = ray->h.nbins*ray->h.gate_size + ray->h.range_bin1; - - /* (find middle of bin) / scale for opengl */ - // near left - glTexCoord2f(0.0, (double)ri/sweep->h.nrays-0.01); - glVertex3f(lx*near_dist, ly*near_dist, 2.0); - - // far left - // todo: correct range-height function - double height = sin(deg2rad(ray->h.elev)) * far_dist; - glTexCoord2f(1.0, (double)ri/sweep->h.nrays-0.01); - glVertex3f(lx*far_dist, ly*far_dist, height); + if (min_city && min_city != last_city){ + self->cur_site = min_city->code; + _set_radar(self, self->cur_site, self->cur_time); } - glEnd(); - //g_print("ri=%d, nr=%d, bw=%f\n", _ri, sweep->h.nrays, sweep->h.beam_width); - - /* Texture debug */ - //glBegin(GL_QUADS); - //glTexCoord2d( 0., 0.); glVertex3f(-500., 0., 0.); // bot left - //glTexCoord2d( 0., 1.); glVertex3f(-500., 500., 0.); // top left - //glTexCoord2d( 1., 1.); glVertex3f( 0., 500., 3.); // top right - //glTexCoord2d( 1., 0.); glVertex3f( 0., 0., 3.); // bot right - //glEnd(); - - return NULL; -} - -static gpointer _draw_hud(GisCallback *callback, gpointer _self) -{ - GisPluginRadar *self = GIS_PLUGIN_RADAR(_self); - if (self->cur_sweep == NULL) - return NULL; - g_debug("GisPluginRadar: _draw_hud"); - - /* Print the color table */ - glMatrixMode(GL_MODELVIEW ); glLoadIdentity(); - glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glDisable(GL_TEXTURE_2D); - glDisable(GL_ALPHA_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_LIGHTING); - glEnable(GL_COLOR_MATERIAL); - glBegin(GL_QUADS); - int i; - for (i = 0; i < 256; i++) { - glColor4ubv(self->cur_colormap->data[i]); - glVertex3f(-1.0, (float)((i ) - 256/2)/(256/2), 0.0); // bot left - glVertex3f(-1.0, (float)((i+1) - 256/2)/(256/2), 0.0); // top left - glVertex3f(-0.9, (float)((i+1) - 256/2)/(256/2), 0.0); // top right - glVertex3f(-0.9, (float)((i ) - 256/2)/(256/2), 0.0); // bot right - } - glEnd(); - - return NULL; + last_city = min_city; } @@ -572,12 +339,8 @@ GisPluginRadar *gis_plugin_radar_new(GisViewer *viewer, GisPrefs *prefs) gis_viewer_add(self->viewer, GIS_OBJECT(marker), GIS_LEVEL_OVERLAY, FALSE); } - /* Add renderers */ - GisCallback *radar_cb = gis_callback_new(_draw_radar, self); - GisCallback *hud_cb = gis_callback_new(_draw_hud, self); - - gis_viewer_add(viewer, GIS_OBJECT(radar_cb), GIS_LEVEL_WORLD, TRUE); - gis_viewer_add(viewer, GIS_OBJECT(hud_cb), GIS_LEVEL_HUD, FALSE); + GisCallback *hud_cb = gis_callback_new(_draw_hud, self); + gis_viewer_add(viewer, GIS_OBJECT(hud_cb), GIS_LEVEL_HUD, FALSE); return self; } @@ -610,7 +373,7 @@ static void gis_plugin_radar_init(GisPluginRadar *self) /* Set defaults */ self->http = gis_http_new("/nexrad/level2/"); self->config_body = gtk_alignment_new(0, 0, 1, 1); - self->load_mutex = g_mutex_new(); + //self->load_mutex = g_mutex_new(); gtk_container_set_border_width(GTK_CONTAINER(self->config_body), 5); gtk_container_add(GTK_CONTAINER(self->config_body), gtk_label_new("No radar loaded")); } @@ -628,7 +391,7 @@ static void gis_plugin_radar_finalize(GObject *gobject) GisPluginRadar *self = GIS_PLUGIN_RADAR(gobject); /* Free data */ gis_http_free(self->http); - g_mutex_free(self->load_mutex); + //g_mutex_free(self->load_mutex); G_OBJECT_CLASS(gis_plugin_radar_parent_class)->finalize(gobject); } diff --git a/src/plugins/radar.h b/src/plugins/radar.h index b45ce1e..b61854a 100644 --- a/src/plugins/radar.h +++ b/src/plugins/radar.h @@ -22,13 +22,7 @@ #include #include - -/* TODO: convert */ -typedef struct { - char *name; - guint8 data[256][4]; -} colormap_t; -extern colormap_t colormaps[]; +#include "level2.h" #define GIS_TYPE_PLUGIN_RADAR (gis_plugin_radar_get_type ()) #define GIS_PLUGIN_RADAR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GIS_TYPE_PLUGIN_RADAR, GisPluginRadar)) @@ -44,23 +38,24 @@ struct _GisPluginRadar { GObject parent_instance; /* instance members */ - GisViewer *viewer; - GisPrefs *prefs; - GisHttp *http; - GtkWidget *config_body; - GtkWidget *progress_bar; - GtkWidget *progress_label; - guint time_changed_id; - guint location_changed_id; - - /* Private data for loading radars */ - GMutex *load_mutex; - char *cur_site; - char *cur_time; - Radar *cur_radar; - Sweep *cur_sweep; - colormap_t *cur_colormap; - guint cur_sweep_tex; + GisViewer *viewer; + GisPrefs *prefs; + GisHttp *http; + + /* Signals */ + guint time_changed_id; + guint location_changed_id; + + /* Tab area */ + GtkWidget *config_body; + GtkWidget *progress_bar; + GtkWidget *progress_label; + + /* Radar lists */ + AWeatherColormap *colormap; + gpointer radar; + gchar *cur_site; + gchar *cur_time; }; struct _GisPluginRadarClass { -- 2.43.2