X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=src%2Fplugin-radar.c;h=23b6d3ab774fdf1976e6c22bba71503ce413e4a8;hb=aba05890085cec97c631b5b8a25fd04c960ec203;hp=e5e56b68f288b7e4eae1a2ea27ad530df9b7b2fa;hpb=1cf8b4ecd92f49dfbbe0472e02d4e5bc8841fe2f;p=aweather diff --git a/src/plugin-radar.c b/src/plugin-radar.c index e5e56b6..23b6d3a 100644 --- a/src/plugin-radar.c +++ b/src/plugin-radar.c @@ -23,9 +23,13 @@ #include #include +#include "misc.h" #include "aweather-gui.h" #include "plugin-radar.h" #include "data.h" +#include "marching.h" + +static char *nexrad_base = "http://mesonet.agron.iastate.edu/data/"; /**************** * GObject code * @@ -47,7 +51,10 @@ static void aweather_radar_init(AWeatherRadar *radar) { g_debug("AWeatherRadar: class_init"); /* Set defaults */ - radar->gui = NULL; + radar->gui = NULL; + radar->soup = NULL; + radar->cur_triangles = NULL; + radar->cur_num_triangles = 0; } static void aweather_radar_dispose(GObject *gobject) { @@ -80,18 +87,17 @@ static void bscan_sweep(AWeatherRadar *self, Sweep *sweep, colormap_t *colormap, guint8 **data, int *width, int *height) { /* Calculate max number of bins */ - int i, max_bins = 0; - for (i = 0; i < sweep->h.nrays; i++) + 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 */ - int ri, bi; - for (ri = 0; ri < sweep->h.nrays; ri++) { + for (int ri = 0; ri < sweep->h.nrays; ri++) { Ray *ray = sweep->ray[ri]; - for (bi = 0; bi < ray->h.nbins; bi++) { + 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]); @@ -99,7 +105,7 @@ static void bscan_sweep(AWeatherRadar *self, Sweep *sweep, colormap_t *colormap, 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]; + buf[buf_i+3] = colormap->data[val][3]; // TESTING if (val == BADVAL || val == RFVAL || val == APFLAG || val == NOTFOUND_H || val == NOTFOUND_V || val == NOECHO) { buf[buf_i+3] = 0x00; // transparent @@ -184,7 +190,7 @@ static void load_radar_gui(AWeatherRadar *self, Radar *radar) g_snprintf(col_label_str, 64, "%.2f°", elev); col_label = gtk_label_new(col_label_str); gtk_label_set_use_markup(GTK_LABEL(col_label), TRUE); - gtk_widget_set_size_request(col_label, 40, -1); + gtk_widget_set_size_request(col_label, 70, -1); gtk_table_attach(GTK_TABLE(table), col_label, cols-1,cols, 0,1, GTK_FILL,GTK_FILL, 0,0); } @@ -214,6 +220,37 @@ static void load_radar_gui(AWeatherRadar *self, Radar *radar) gtk_widget_show_all(table); } +static void _aweather_radar_grid_set(GRIDCELL *grid, int gi, Ray *ray, int bi) +{ + Range range = ray->range[bi]; + + double angle = d2r(ray->h.azimuth); + double tilt = d2r(ray->h.elev); + + double lx = sin(angle); + double ly = cos(angle); + double lz = sin(tilt); + + double dist = bi*ray->h.gate_size + ray->h.range_bin1; + + grid->p[gi].x = lx*dist; + grid->p[gi].y = ly*dist; + grid->p[gi].z = lz*dist; + + guint8 val = (guint8)ray->h.f(ray->range[bi]); + if (val == BADVAL || val == RFVAL || val == APFLAG || + val == NOTFOUND_H || val == NOTFOUND_V || val == NOECHO || + val > 80) + val = 0; + grid->val[gi] = (float)val; + //g_debug("(%.2f,%.2f,%.2f) - (%.0f,%.0f,%.0f) = %d", + // angle, tilt, dist, + // grid->p[gi].x, + // grid->p[gi].y, + // grid->p[gi].z, + // val); +} + /* Load a radar from a decompressed file */ static void load_radar(AWeatherRadar *self, gchar *radar_file) { @@ -230,6 +267,81 @@ static void load_radar(AWeatherRadar *self, gchar *radar_file) } g_free(site); +#ifdef MARCHING + /* Load the surface */ + if (self->cur_triangles) { + g_free(self->cur_triangles); + self->cur_triangles = NULL; + } + self->cur_num_triangles = 0; + int x = 1; + for (guint vi = 0; vi < radar->h.nvolumes; vi++) { + if (radar->v[vi] == NULL) continue; + + for (guint si = 0; si+1 < radar->v[vi]->h.nsweeps; si++) { + Sweep *sweep0 = radar->v[vi]->sweep[si+0]; + Sweep *sweep1 = radar->v[vi]->sweep[si+1]; + + //g_debug("_aweather_radar_expose: sweep[%3d-%3d] -- nrays = %d, %d", + // si, si+1,sweep0->h.nrays, sweep1->h.nrays); + + /* Skip super->regular resolution switch for now */ + if (sweep0 == NULL || sweep0->h.elev == 0 || + sweep1 == NULL || sweep1->h.elev == 0 || + sweep0->h.nrays != sweep1->h.nrays) + continue; + + /* We repack the arrays so that raysX[0] is always north, etc */ + Ray **rays0 = g_malloc0(sizeof(Ray*)*sweep0->h.nrays); + Ray **rays1 = g_malloc0(sizeof(Ray*)*sweep1->h.nrays); + + for (guint ri = 0; ri < sweep0->h.nrays; ri++) + rays0[(guint)(sweep0->ray[ri]->h.azimuth * sweep0->h.nrays / 360)] = + sweep0->ray[ri]; + for (guint ri = 0; ri < sweep1->h.nrays; ri++) + rays1[(guint)(sweep1->ray[ri]->h.azimuth * sweep1->h.nrays / 360)] = + sweep1->ray[ri]; + + for (guint ri = 0; ri+x < sweep0->h.nrays; ri+=x) { + //g_debug("_aweather_radar_expose: ray[%3d-%3d] -- nbins = %d, %d, %d, %d", + // ri, ri+x, + // rays0[ri ]->h.nbins, + // rays0[ri+1]->h.nbins, + // rays1[ri ]->h.nbins, + // rays1[ri+1]->h.nbins); + + for (guint bi = 0; bi+x < rays1[ri]->h.nbins; bi+=x) { + GRIDCELL grid = {}; + _aweather_radar_grid_set(&grid, 7, rays0[(ri )%sweep0->h.nrays], bi+x); + _aweather_radar_grid_set(&grid, 6, rays0[(ri+x)%sweep0->h.nrays], bi+x); + _aweather_radar_grid_set(&grid, 5, rays0[(ri+x)%sweep0->h.nrays], bi ); + _aweather_radar_grid_set(&grid, 4, rays0[(ri )%sweep0->h.nrays], bi ); + _aweather_radar_grid_set(&grid, 3, rays1[(ri )%sweep0->h.nrays], bi+x); + _aweather_radar_grid_set(&grid, 2, rays1[(ri+x)%sweep0->h.nrays], bi+x); + _aweather_radar_grid_set(&grid, 1, rays1[(ri+x)%sweep0->h.nrays], bi ); + _aweather_radar_grid_set(&grid, 0, rays1[(ri )%sweep0->h.nrays], bi ); + + TRIANGLE tris[10]; + int n = march_one_cube(grid, 40, tris); + + self->cur_triangles = g_realloc(self->cur_triangles, + (self->cur_num_triangles+n)*sizeof(TRIANGLE)); + for (int i = 0; i < n; i++) { + //g_debug("triangle: "); + //g_debug("\t(%f,%f,%f)", tris[i].p[0].x, tris[i].p[0].y, tris[i].p[0].z); + //g_debug("\t(%f,%f,%f)", tris[i].p[1].x, tris[i].p[1].y, tris[i].p[1].z); + //g_debug("\t(%f,%f,%f)", tris[i].p[2].x, tris[i].p[2].y, tris[i].p[2].z); + self->cur_triangles[self->cur_num_triangles+i] = tris[i]; + } + self->cur_num_triangles += n; + //g_debug(" "); + } + } + } + break; // Exit after first volume (reflectivity) + } +#endif + /* Load the first sweep by default */ if (radar->h.nvolumes < 1 || radar->v[0]->h.nsweeps < 1) { g_warning("No sweeps found\n"); @@ -250,46 +362,10 @@ static void load_radar(AWeatherRadar *self, gchar *radar_file) load_radar_gui(self, radar); } -static void update_times(AWeatherRadar *self, AWeatherView *view, char *site, char **last_time) +/* TODO: These update times functions are getting ugly... */ +static void update_times_gtk(AWeatherRadar *self, GList *times) { - GList *times = NULL; - if (aweather_view_get_offline(view)) { - gchar *path = g_build_filename(g_get_user_cache_dir(), PACKAGE, "nexrd2", "raw", site, NULL); - GDir *dir = g_dir_open(path, 0, NULL); - if (dir) { - const gchar *name; - while ((name = g_dir_read_name(dir))) { - times = g_list_prepend(times, g_strdup(name)); - } - g_dir_close(dir); - } - g_free(path); - } else { - gchar *data; - gsize length; - GError *error = NULL; - - char *list_uri = g_strdup_printf("http://mesonet.agron.iastate.edu/data/nexrd2/raw/%s/dir.list", site); - GFile *list = g_file_new_for_uri(list_uri); - g_file_load_contents(list, NULL, &data, &length, NULL, &error); - if (error) { - g_warning("Error loading list for %s: %s", site, error->message); - g_error_free(error); - } else { - gchar **lines = g_strsplit(data, "\n", -1); - for (int i = 0; lines[i] && lines[i][0]; i++) { - char **parts = g_strsplit(lines[i], " ", 2); - times = g_list_prepend(times, parts[1]); - g_strfreev(parts); - } - g_strfreev(lines); - g_free(data); - } - - g_free(list_uri); - g_object_unref(list); - } - + gchar *last_time = NULL; GRegex *regex = g_regex_new("^[A-Z]{4}_([0-9]{8}_[0-9]{4})$", 0, 0, NULL); // KLSX_20090622_2113 GMatchInfo *info; @@ -305,15 +381,55 @@ static void update_times(AWeatherRadar *self, AWeatherView *view, char *site, ch g_message("adding time %s", (gchar*)cur->data); gtk_list_store_insert(lstore, &iter, 0); gtk_list_store_set(lstore, &iter, 0, time, -1); - if (last_time) - *last_time = time; + last_time = time; } } + AWeatherView *view = aweather_gui_get_view(self->gui); + aweather_view_set_time(view, last_time); + g_regex_unref(regex); g_list_foreach(times, (GFunc)g_free, NULL); g_list_free(times); } +static void update_times_online_cb(char *path, gboolean updated, gpointer _self) +{ + GList *times = NULL; + gchar *data; + gsize length; + g_file_get_contents(path, &data, &length, NULL); + gchar **lines = g_strsplit(data, "\n", -1); + for (int i = 0; lines[i] && lines[i][0]; i++) { + char **parts = g_strsplit(lines[i], " ", 2); + times = g_list_prepend(times, g_strdup(parts[1])); + g_strfreev(parts); + } + g_strfreev(lines); + g_free(data); + + update_times_gtk(_self, times); +} +static void update_times(AWeatherRadar *self, AWeatherView *view, char *site) +{ + if (aweather_view_get_offline(view)) { + GList *times = NULL; + gchar *path = g_build_filename(g_get_user_cache_dir(), PACKAGE, "nexrd2", "raw", site, NULL); + GDir *dir = g_dir_open(path, 0, NULL); + if (dir) { + const gchar *name; + while ((name = g_dir_read_name(dir))) { + times = g_list_prepend(times, g_strdup(name)); + } + g_dir_close(dir); + } + g_free(path); + update_times_gtk(self, times); + } else { + gchar *path = g_strdup_printf("nexrd2/raw/%s/dir.list", site); + cache_file(nexrad_base, path, AWEATHER_REFRESH, NULL, update_times_online_cb, self); + /* update_times_gtk from update_times_online_cb */ + } +} /***************** * ASync helpers * @@ -336,7 +452,23 @@ static void decompressed_cb(GPid pid, gint status, gpointer _udata) g_free(udata); } -static void cached_cb(char *path, gboolean updated, gpointer _self) +static void cache_chunk_cb(char *path, goffset cur, goffset total, gpointer _self) +{ + AWeatherRadar *self = AWEATHER_RADAR(_self); + double percent = (double)cur/total; + + g_message("AWeatherRadar: cache_chunk_cb - %lld/%lld = %.2f%%", + cur, total, percent*100); + + 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); + g_free(msg); +} + +static void cache_done_cb(char *path, gboolean updated, gpointer _self) { AWeatherRadar *self = AWEATHER_RADAR(_self); char *decompressed = g_strconcat(path, ".raw", NULL); @@ -348,7 +480,7 @@ static void cached_cb(char *path, gboolean updated, gpointer _self) decompressed_t *udata = g_malloc(sizeof(decompressed_t)); udata->self = self; udata->radar_file = decompressed; - g_debug("AWeatherRadar: cached_cb - File updated, decompressing.."); + g_debug("AWeatherRadar: cache_done_cb - File updated, decompressing.."); char *argv[] = {"wsr88ddec", path, decompressed, NULL}; GPid pid; GError *error = NULL; @@ -369,6 +501,7 @@ static void cached_cb(char *path, gboolean updated, gpointer _self) g_error_free(error); } g_child_watch_add(pid, decompressed_cb, udata); + self->soup = NULL; } /************* @@ -387,16 +520,22 @@ static void on_time_changed(AWeatherView *view, const char *time, gpointer _self g_debug("AWeatherRadar: on_time_changed - setting time=%s", time); // format: http://mesonet.agron.iastate.edu/data/nexrd2/raw/KABR/KABR_20090510_0323 char *site = aweather_view_get_site(view); - char *base = "http://mesonet.agron.iastate.edu/data/"; char *path = g_strdup_printf("nexrd2/raw/%s/%s_%s", site, site, time); - /* Clear out children */ + /* Set up progress bar */ GtkWidget *child = gtk_bin_get_child(GTK_BIN(self->config_body)); - if (child) - gtk_widget_destroy(child); - gtk_container_add(GTK_CONTAINER(self->config_body), - gtk_label_new("Loading radar...")); + if (child) gtk_widget_destroy(child); + + GtkWidget *vbox = gtk_vbox_new(FALSE, 10); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 10); + self->progress_bar = gtk_progress_bar_new(); + self->progress_label = gtk_label_new("Loading radar..."); + gtk_box_pack_start(GTK_BOX(vbox), self->progress_bar, FALSE, FALSE, 0); + 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; @@ -404,10 +543,16 @@ static void on_time_changed(AWeatherView *view, const char *time, gpointer _self aweather_gui_gl_redraw(self->gui); /* Start loading the new radar */ + if (self->soup) { + soup_session_abort(self->soup); + self->soup = NULL; + } if (aweather_view_get_offline(view)) - cache_file(base, path, AWEATHER_ONCE, cached_cb, self); + self->soup = cache_file(nexrad_base, path, AWEATHER_ONCE, + cache_chunk_cb, cache_done_cb, self); else - cache_file(base, path, AWEATHER_UPDATE, cached_cb, self); + self->soup = cache_file(nexrad_base, path, AWEATHER_UPDATE, + cache_chunk_cb, cache_done_cb, self); g_free(path); } @@ -415,21 +560,14 @@ static void on_site_changed(AWeatherView *view, char *site, gpointer _self) { AWeatherRadar *self = AWEATHER_RADAR(_self); g_debug("AWeatherRadar: on_site_changed - Loading wsr88d list for %s", site); - char *time = NULL; - update_times(self, view, site, &time); - aweather_view_set_time(view, time); - - g_free(time); + update_times(self, view, site), &time; } static void on_refresh(AWeatherView *view, gpointer _self) { AWeatherRadar *self = AWEATHER_RADAR(_self); char *site = aweather_view_get_site(view); - char *time = NULL; - update_times(self, view, site, &time); - aweather_view_set_time(view, time); - g_free(time); + update_times(self, view, site); } /*********** @@ -466,8 +604,39 @@ static void _aweather_radar_expose(AWeatherPlugin *_self) return; Sweep *sweep = self->cur_sweep; - /* Draw the rays */ +#ifdef MARCHING + /* Draw the surface */ + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glDisable(GL_TEXTURE_2D); + float light_ambient[] = {0.1f, 0.1f, 0.0f}; + float light_diffuse[] = {0.9f, 0.9f, 0.9f}; + float light_position[] = {-300000.0f, 500000.0f, 400000.0f, 1.0f}; + glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); + glLightfv(GL_LIGHT0, GL_POSITION, light_position); + glEnable(GL_LIGHT0); + glEnable(GL_LIGHTING); + glEnable(GL_COLOR_MATERIAL); + glColor4f(1,1,1,0.75); + g_debug("ntri=%d", self->cur_num_triangles); + glBegin(GL_TRIANGLES); + for (int i = 0; i < self->cur_num_triangles; i++) { + TRIANGLE t = self->cur_triangles[i]; + do_normal(t.p[0].x, t.p[0].y, t.p[0].z, + t.p[1].x, t.p[1].y, t.p[1].z, + t.p[2].x, t.p[2].y, t.p[2].z); + glVertex3f(t.p[0].x, t.p[0].y, t.p[0].z); + glVertex3f(t.p[1].x, t.p[1].y, t.p[1].z); + glVertex3f(t.p[2].x, t.p[2].y, t.p[2].z); + } + glEnd(); + glPopMatrix(); +#endif + /* Draw the rays */ + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glBindTexture(GL_TEXTURE_2D, self->cur_sweep_tex); @@ -480,11 +649,11 @@ static void _aweather_radar_expose(AWeatherPlugin *_self) double angle = 0; if (ri < sweep->h.nrays) { ray = sweep->ray[ri]; - angle = ((ray->h.azimuth - ((double)ray->h.beam_width/2.))*M_PI)/180.0; + angle = d2r(ray->h.azimuth - ((double)ray->h.beam_width/2.)); } else { /* Do the right side of the last sweep */ ray = sweep->ray[ri-1]; - angle = ((ray->h.azimuth + ((double)ray->h.beam_width/2.))*M_PI)/180.0; + angle = d2r(ray->h.azimuth + ((double)ray->h.beam_width/2.)); } double lx = sin(angle); @@ -499,8 +668,10 @@ static void _aweather_radar_expose(AWeatherPlugin *_self) glVertex3f(lx*near_dist, ly*near_dist, 2.0); // far left + // todo: correct range-height function + double height = sin(d2r(ray->h.elev)) * far_dist; glTexCoord2f(1.0, (double)ri/sweep->h.nrays-0.01); - glVertex3f(lx*far_dist, ly*far_dist, 2.0); + glVertex3f(lx*far_dist, ly*far_dist, height); } //g_print("ri=%d, nr=%d, bw=%f\n", _ri, sweep->h.nrays, sweep->h.beam_width); glEnd();