]> Pileus Git - grits/blobdiff - src/plugin-radar.c
Adding some (commented out) support for generating iso surfaces.
[grits] / src / plugin-radar.c
index 7f4efa39950440725638d13b184b0b5d89a9837f..23b6d3ab774fdf1976e6c22bba71503ce413e4a8 100644 (file)
 #include <config.h>
 #include <gtk/gtk.h>
 #include <gtk/gtkgl.h>
+#include <gio/gio.h>
 #include <GL/gl.h>
 #include <math.h>
 #include <rsl.h>
 
+#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 *
  ****************/
+/* Plugin init */
 static void aweather_radar_plugin_init(AWeatherPluginInterface *iface);
 static void _aweather_radar_expose(AWeatherPlugin *_radar);
 G_DEFINE_TYPE_WITH_CODE(AWeatherRadar, aweather_radar, G_TYPE_OBJECT,
                G_IMPLEMENT_INTERFACE(AWEATHER_TYPE_PLUGIN,
                        aweather_radar_plugin_init));
-static void aweather_radar_class_init(AWeatherRadarClass *klass)
-{
-       GObjectClass *object_class = (GObjectClass*)klass;
-}
 static void aweather_radar_plugin_init(AWeatherPluginInterface *iface)
 {
+       g_debug("AWeatherRadar: plugin_init");
        /* Add methods to the interface */
        iface->expose = _aweather_radar_expose;
 }
+/* Class/Object init */
 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)
+{
+       g_debug("AWeatherRadar: dispose");
+       AWeatherRadar *self = AWEATHER_RADAR(gobject);
+       /* Drop references */
+       G_OBJECT_CLASS(aweather_radar_parent_class)->dispose(gobject);
+}
+static void aweather_radar_finalize(GObject *gobject)
+{
+       g_debug("AWeatherRadar: finalize");
+       AWeatherRadar *self = AWEATHER_RADAR(gobject);
+       /* Free data */
+       G_OBJECT_CLASS(aweather_radar_parent_class)->finalize(gobject);
+
+}
+static void aweather_radar_class_init(AWeatherRadarClass *klass)
+{
+       g_debug("AWeatherRadar: class_init");
+       GObjectClass *gobject_class = (GObjectClass*)klass;
+       gobject_class->dispose  = aweather_radar_dispose;
+       gobject_class->finalize = aweather_radar_finalize;
 }
 
 /**************************
@@ -57,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]);
@@ -76,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
@@ -132,7 +161,7 @@ static void load_radar_gui(AWeatherRadar *self, Radar *radar)
        gdouble elev;
        guint rows = 1, cols = 1, cur_cols;
        gchar row_label_str[64], col_label_str[64], button_str[64];
-       GtkWidget *row_label, *col_label, *button = NULL, *elev_box;
+       GtkWidget *row_label, *col_label, *button = NULL, *elev_box = NULL;
        GtkWidget *table = gtk_table_new(rows, cols, FALSE);
 
        for (guint vi = 0; vi < radar->h.nvolumes; vi++) {
@@ -161,7 +190,7 @@ static void load_radar_gui(AWeatherRadar *self, Radar *radar)
                                        g_snprintf(col_label_str, 64, "<b>%.2f°</b>", 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);
                                }
@@ -191,18 +220,45 @@ 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)
 {
        char *dir  = g_path_get_dirname(radar_file);
        char *site = g_path_get_basename(dir);
        g_free(dir);
-       RSL_read_these_sweeps("all", NULL);
-       if (self->cur_radar) {
-               g_debug("AWeatherRadar: load_radar - Freeing old radar");
-               RSL_free_radar(self->cur_radar);
-       }
        g_debug("AWeatherRadar: load_radar - Loading new radar");
+       RSL_read_these_sweeps("all", NULL);
        Radar *radar = self->cur_radar = RSL_wsr88d_to_radar(radar_file, site);
        if (radar == NULL) {
                g_warning("fail to load radar: path=%s, site=%s", radar_file, site);
@@ -211,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");
@@ -231,44 +362,73 @@ static void load_radar(AWeatherRadar *self, gchar *radar_file)
        load_radar_gui(self, radar);
 }
 
-static void update_times(AWeatherRadar *self, char *site, char **last_time)
+/* TODO: These update times functions are getting ugly... */
+static void update_times_gtk(AWeatherRadar *self, GList *times)
 {
-       char *list_uri = g_strdup_printf(
-                       "http://mesonet.agron.iastate.edu/data/nexrd2/raw/K%s/dir.list",
-                       site);
-       GFile *list    = g_file_new_for_uri(list_uri);
-       g_free(list_uri);
+       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;
 
-       gchar *data;
-       gsize length;
-       GError *error = NULL;
-       g_file_load_contents(list, NULL, &data, &length, NULL, &error);
-       g_object_unref(list);
-       if (error) {
-               g_warning("Error loading list for %s: %s", site, error->message);
-               g_error_free(error);
-               return;
-       }
-       gchar **lines = g_strsplit(data, "\n", -1);
        GtkTreeView  *tview  = GTK_TREE_VIEW(aweather_gui_get_widget(self->gui, "time"));
        GtkListStore *lstore = GTK_LIST_STORE(gtk_tree_view_get_model(tview));
        gtk_list_store_clear(lstore);
        GtkTreeIter iter;
+       times = g_list_reverse(times);
+       for (GList *cur = times; cur; cur = cur->next) {
+               g_message("trying time %s", (gchar*)cur->data);
+               if (g_regex_match(regex, cur->data, 0, &info)) {
+                       gchar *time = g_match_info_fetch(info, 1);
+                       g_message("adding time %s", (gchar*)cur->data);
+                       gtk_list_store_insert(lstore, &iter, 0);
+                       gtk_list_store_set(lstore, &iter, 0, time, -1);
+                       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++) {
-               // format: `841907 KABR_20090510_0159'
-               //g_message("\tadding %p [%s]", lines[i], lines[i]);
                char **parts = g_strsplit(lines[i], " ", 2);
-               char *time = parts[1]+5;
-               gtk_list_store_insert(lstore, &iter, 0);
-               gtk_list_store_set(lstore, &iter, 0, time, -1);
+               times = g_list_prepend(times, g_strdup(parts[1]));
                g_strfreev(parts);
        }
-
-       if (last_time)
-               gtk_tree_model_get(GTK_TREE_MODEL(lstore), &iter, 0, last_time, -1);
-
-       g_free(data);
        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 */
+       }
 }
 
 /*****************
@@ -279,19 +439,36 @@ typedef struct {
        gchar *radar_file;
 } decompressed_t;
 
-static void decompressed_cb(GPid pid, gint status, gpointer _self)
+static void decompressed_cb(GPid pid, gint status, gpointer _udata)
 {
-       decompressed_t *udata = _self;
+       decompressed_t *udata = _udata;
        if (status != 0) {
                g_warning("wsr88ddec exited with status %d", status);
                return;
        }
        load_radar(udata->self, udata->radar_file);
+       g_spawn_close_pid(pid);
        g_free(udata->radar_file);
        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);
@@ -303,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;
@@ -324,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;
 }
 
 /*************
@@ -336,28 +514,45 @@ static void on_sweep_clicked(GtkRadioButton *button, gpointer _self)
        load_sweep   (self, g_object_get_data(G_OBJECT(button), "sweep"));
 }
 
-static void on_time_changed(AWeatherView *view, char *time, gpointer _self)
+static void on_time_changed(AWeatherView *view, const char *time, gpointer _self)
 {
        AWeatherRadar *self = AWEATHER_RADAR(_self);
-       g_debug("AWeatherRadar: on_time_changed - setting time");
+       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/K%s/K%s_%s", site, site, time);
+       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;
-       self->cur_sweep = NULL; // Clear radar
+       self->cur_sweep = NULL;
        aweather_gui_gl_redraw(self->gui);
 
        /* Start loading the new radar */
-       cache_file(base, path, AWEATHER_AUTOMATIC, cached_cb, self);
+       if (self->soup) {
+               soup_session_abort(self->soup);
+               self->soup = NULL;
+       }
+       if (aweather_view_get_offline(view)) 
+               self->soup = cache_file(nexrad_base, path, AWEATHER_ONCE,
+                               cache_chunk_cb, cache_done_cb, self);
+       else 
+               self->soup = cache_file(nexrad_base, path, AWEATHER_UPDATE,
+                               cache_chunk_cb, cache_done_cb, self);
        g_free(path);
 }
 
@@ -365,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, site, &time);
-       aweather_view_set_time(view, time);
-
-       g_free(time);
+       update_times(self, view, site), &time;
 }
 
-static void on_refresh(AWeatherView *view, gpointer user_data, gpointer _self)
+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, site, &time);
-       aweather_view_set_time(view, time);
-       g_free(time);
+       update_times(self, view, site);
 }
 
 /***********
@@ -416,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);
@@ -430,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);
@@ -449,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();