]> Pileus Git - aweather/blobdiff - src/plugins/level2.c
Pass objects to grits_viewer_remove instead of refs
[aweather] / src / plugins / level2.c
index 180aea33bad9e23eb22cda902799f6c6eaefbb5c..66eb172a4c4431743c4b7fc265dd6764f5adee49 100644 (file)
 #include <math.h>
 #include <GL/gl.h>
 #include <glib/gstdio.h>
-#include <gis.h>
+#include <grits.h>
 #include <rsl.h>
 
 #include "level2.h"
 
+#define ISO_MIN 30
+#define ISO_MAX 80
 
 /**************************
  * Data loading functions *
@@ -46,18 +48,22 @@ static void _bscan_sweep(Sweep *sweep, AWeatherColormap *colormap,
        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) {
+                       float  value = ray->h.f(ray->range[bi]);
+
+                       /* Check for bad values */
+                       if (value == BADVAL     || value == RFVAL      || value == APFLAG ||
+                           value == NOTFOUND_H || value == NOTFOUND_V || value == NOECHO) {
                                buf[buf_i+3] = 0x00; // transparent
+                               continue;
                        }
+
+                       /* Copy color to buffer */
+                       guint8 *data = colormap_get(colormap, value);
+                       buf[buf_i+0] = data[0];
+                       buf[buf_i+1] = data[1];
+                       buf[buf_i+2] = data[2];
+                       buf[buf_i+3] = data[3]*0.75; // TESTING
                }
        }
 
@@ -68,19 +74,29 @@ static void _bscan_sweep(Sweep *sweep, AWeatherColormap *colormap,
 }
 
 /* Load a sweep into an OpenGL texture */
-static void _load_sweep_gl(Sweep *sweep, AWeatherColormap *colormap, guint *tex)
+static void _load_sweep_gl(AWeatherLevel2 *level2)
 {
        g_debug("AWeatherLevel2: _load_sweep_gl");
-       int height, width;
        guint8 *data;
-       _bscan_sweep(sweep, colormap, &data, &width, &height);
-       glBindTexture(GL_TEXTURE_2D, *tex);
+       gint width, height;
+       _bscan_sweep(level2->sweep, level2->sweep_colors, &data, &width, &height);
+       gint tex_width  = pow(2, ceil(log(width )/log(2)));
+       gint tex_height = pow(2, ceil(log(height)/log(2)));
+       level2->sweep_coords[0] = (double)width  / tex_width;
+       level2->sweep_coords[1] = (double)height / tex_height;
+
+       if (!level2->sweep_tex)
+                glGenTextures(1, &level2->sweep_tex);
+       glBindTexture(GL_TEXTURE_2D, level2->sweep_tex);
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_width, tex_height, 0,
+                       GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+       glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, width,height,
+                       GL_RGBA, GL_UNSIGNED_BYTE, data);
        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);
 }
 
@@ -116,24 +132,85 @@ static gboolean _decompress_radar(const gchar *file, const gchar *raw)
        return TRUE;
 }
 
+/* Load the radar into a Grits Volume */
+static void _cart_to_sphere(VolCoord *out, VolCoord *in)
+{
+       gdouble angle = in->x;
+       gdouble dist  = in->y;
+       gdouble tilt  = in->z;
+       gdouble lx    = sin(angle);
+       gdouble ly    = cos(angle);
+       gdouble lz    = sin(tilt);
+       //out->x = (ly*dist)/20000;
+       //out->y = (lz*dist)/10000-0.5;
+       //out->z = (lx*dist)/20000-1.5;
+       out->x = (lx*dist);
+       out->y = (ly*dist);
+       out->z = (lz*dist);
+}
+
+static VolGrid *_load_grid(Volume *vol)
+{
+       g_debug("AWeatherLevel2: _load_grid");
+
+       Sweep *sweep   = vol->sweep[0];
+       Ray   *ray     = sweep->ray[0];
+       gint nsweeps   = vol->h.nsweeps;
+       gint nrays     = sweep->h.nrays/(1/sweep->h.beam_width)+1;
+       gint nbins     = ray->h.nbins  /(1000/ray->h.gate_size);
+       nbins = MIN(nbins, 150);
+
+       VolGrid  *grid = vol_grid_new(nrays, nbins, nsweeps);
+
+       gint rs, bs, val;
+       gint si=0, ri=0, bi=0;
+       for (si = 0; si < nsweeps; si++) {
+               sweep = vol->sweep[si];
+               rs    = 1.0/sweep->h.beam_width;
+       for (ri = 0; ri < nrays; ri++) {
+               /* TODO: missing rays, pick ri based on azmith */
+               ray   = sweep->ray[(ri*rs) % sweep->h.nrays];
+               bs    = 1000/ray->h.gate_size;
+       for (bi = 0; bi < nbins; bi++) {
+               if (bi*bs >= ray->h.nbins)
+                       break;
+               val   = ray->h.f(ray->range[bi*bs]);
+               if (val == BADVAL     || val == RFVAL      ||
+                   val == APFLAG     || val == NOECHO     ||
+                   val == NOTFOUND_H || val == NOTFOUND_V ||
+                   val > 80)
+                       val = 0;
+               VolPoint *point = vol_grid_get(grid, ri, bi, si);
+               point->value = val;
+               point->c.x = deg2rad(ray->h.azimuth);
+               point->c.y = bi*bs*ray->h.gate_size + ray->h.range_bin1;
+               point->c.z = deg2rad(ray->h.elev);
+       } } }
+
+       for (si = 0; si < nsweeps; si++)
+       for (ri = 0; ri < nrays; ri++)
+       for (bi = 0; bi < nbins; bi++) {
+               VolPoint *point = vol_grid_get(grid, ri, bi, si);
+               if (point->c.y == 0)
+                       point->value = nan("");
+               else
+                       _cart_to_sphere(&point->c, &point->c);
+       }
+       return grid;
+}
+
 
 /*********************
  * Drawing functions *
  *********************/
-static void _draw_radar(GisCallback *_self, gpointer _viewer)
+void aweather_level2_draw(GritsObject *_level2, GritsOpenGL *opengl)
 {
-       AWeatherLevel2 *self = AWEATHER_LEVEL2(_self);
-       if (!self->sweep || !self->sweep_tex)
+       AWeatherLevel2 *level2 = AWEATHER_LEVEL2(_level2);
+       if (!level2->sweep || !level2->sweep_tex)
                return;
 
        /* 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);
-
+       Sweep *sweep = level2->sweep;
        glDisable(GL_ALPHA_TEST);
        glDisable(GL_CULL_FACE);
        glDisable(GL_LIGHTING);
@@ -143,7 +220,9 @@ static void _draw_radar(GisCallback *_self, gpointer _viewer)
        glColor4f(1,1,1,1);
 
        /* Draw the rays */
-       glBindTexture(GL_TEXTURE_2D, self->sweep_tex);
+       gdouble xscale = level2->sweep_coords[0];
+       gdouble yscale = level2->sweep_coords[1];
+       glBindTexture(GL_TEXTURE_2D, level2->sweep_tex);
        glBegin(GL_TRIANGLE_STRIP);
        for (int ri = 0; ri <= sweep->h.nrays; ri++) {
                Ray  *ray = NULL;
@@ -160,18 +239,18 @@ static void _draw_radar(GisCallback *_self, gpointer _viewer)
                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;
+               double near_dist = ray->h.range_bin1 - ((double)ray->h.gate_size/2.);
+               double far_dist  = near_dist + (double)ray->h.nbins*ray->h.gate_size;
 
                /* (find middle of bin) / scale for opengl */
                // near left
-               glTexCoord2f(0.0, (double)ri/sweep->h.nrays-0.01);
+               glTexCoord2f(0.0, ((double)ri/sweep->h.nrays)*yscale);
                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);
+               glTexCoord2f(xscale, ((double)ri/sweep->h.nrays)*yscale);
                glVertex3f(lx*far_dist,  ly*far_dist, height);
        }
        glEnd();
@@ -186,59 +265,101 @@ static void _draw_radar(GisCallback *_self, gpointer _viewer)
        //glEnd();
 }
 
+void aweather_level2_hide(GritsObject *_level2, gboolean hidden)
+{
+       AWeatherLevel2 *level2 = AWEATHER_LEVEL2(_level2);
+       if (level2->volume)
+               grits_object_hide(GRITS_OBJECT(level2->volume), hidden);
+}
+
 
 /***********
  * Methods *
  ***********/
-static gboolean _set_sweep_cb(gpointer _self)
+static gboolean _set_sweep_cb(gpointer _level2)
 {
        g_debug("AWeatherLevel2: _set_sweep_cb");
-       AWeatherLevel2 *self = _self;
-       if (!self->sweep_tex)
-                glGenTextures(1, &self->sweep_tex);
-       _load_sweep_gl(self->sweep, self->sweep_colors, &self->sweep_tex);
-       gtk_widget_queue_draw(GTK_WIDGET(self->viewer));
-       g_object_unref(self);
+       AWeatherLevel2 *level2 = _level2;
+       _load_sweep_gl(level2);
+       grits_object_queue_draw(_level2);
+       g_object_unref(level2);
        return FALSE;
 }
-void aweather_level2_set_sweep(AWeatherLevel2 *self,
+void aweather_level2_set_sweep(AWeatherLevel2 *level2,
                int type, float elev)
 {
        g_debug("AWeatherLevel2: set_sweep - %d %f", type, elev);
 
        /* Find sweep */
-       Volume *volume = RSL_get_volume(self->radar, type);
+       Volume *volume = RSL_get_volume(level2->radar, type);
        if (!volume) return;
-       self->sweep = RSL_get_closest_sweep(volume, elev, 90);
-       if (!self->sweep) return;
+       level2->sweep = RSL_get_closest_sweep(volume, elev, 90);
+       if (!level2->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;
+       level2->sweep_colors = NULL;
+       for (int i = 0; level2->colormap[i].file; i++)
+               if (level2->colormap[i].type == type)
+                       level2->sweep_colors = &level2->colormap[i];
+       if (!level2->sweep_colors) {
+               g_warning("AWeatherLevel2: set_sweep - missing colormap[%d]", type);
+               level2->sweep_colors = &level2->colormap[0];
+       }
 
        /* Load data */
-       g_object_ref(self);
-       g_idle_add(_set_sweep_cb, self);
+       g_object_ref(level2);
+       g_idle_add(_set_sweep_cb, level2);
+}
+
+void aweather_level2_set_iso(AWeatherLevel2 *level2, gfloat level)
+{
+       g_debug("AWeatherLevel2: set_iso - %f", level);
+
+       if (!level2->volume) {
+               g_debug("AWeatherLevel2: set_iso - creating new volume");
+               Volume      *rvol = RSL_get_volume(level2->radar, DZ_INDEX);
+               VolGrid     *grid = _load_grid(rvol);
+               GritsVolume *vol  = grits_volume_new(grid);
+               vol->proj = GRITS_VOLUME_CARTESIAN;
+               vol->disp = GRITS_VOLUME_SURFACE;
+               GRITS_OBJECT(vol)->center = GRITS_OBJECT(level2)->center;
+               grits_viewer_add(GRITS_OBJECT(level2)->viewer,
+                               GRITS_OBJECT(vol), GRITS_LEVEL_WORLD, TRUE);
+               level2->volume = vol;
+       }
+       if (ISO_MIN < level && level < ISO_MAX) {
+               guint8 *data = colormap_get(&level2->colormap[0], level);
+               level2->volume->color[0] = data[0];
+               level2->volume->color[1] = data[1];
+               level2->volume->color[2] = data[2];
+               level2->volume->color[3] = data[3];
+               grits_volume_set_level(level2->volume, level);
+               grits_object_hide(GRITS_OBJECT(level2->volume), FALSE);
+       } else {
+               grits_object_hide(GRITS_OBJECT(level2->volume), TRUE);
+       }
 }
 
-AWeatherLevel2 *aweather_level2_new(GisViewer *viewer,
-               AWeatherColormap *colormap, Radar *radar)
+AWeatherLevel2 *aweather_level2_new(Radar *radar, AWeatherColormap *colormap)
 {
        g_debug("AWeatherLevel2: new - %s", radar->h.radar_name);
-       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;
+       RSL_sort_radar(radar);
+       AWeatherLevel2 *level2 = g_object_new(AWEATHER_TYPE_LEVEL2, NULL);
+       level2->radar    = radar;
+       level2->colormap = colormap;
+       aweather_level2_set_sweep(level2, DZ_INDEX, 0);
+
+       GritsPoint center;
+       Radar_header *h = &radar->h;
+       center.lat  = (double)h->latd + (double)h->latm/60 + (double)h->lats/(60*60);
+       center.lon  = (double)h->lond + (double)h->lonm/60 + (double)h->lons/(60*60);
+       center.elev = h->height;
+       GRITS_OBJECT(level2)->center = center;
+       return level2;
 }
 
-AWeatherLevel2 *aweather_level2_new_from_file(GisViewer *viewer,
-               AWeatherColormap *colormap,
-               const gchar *file, const gchar *site)
+AWeatherLevel2 *aweather_level2_new_from_file(const gchar *file, const gchar *site,
+               AWeatherColormap *colormap)
 {
        g_debug("AWeatherLevel2: new_from_file %s %s", site, file);
 
@@ -265,16 +386,25 @@ AWeatherLevel2 *aweather_level2_new_from_file(GisViewer *viewer,
        if (!radar)
                return NULL;
 
-       return aweather_level2_new(viewer, colormaps, radar);
+       return aweather_level2_new(radar, colormaps);
 }
 
 static void _on_sweep_clicked(GtkRadioButton *button, gpointer _level2)
 {
        AWeatherLevel2 *level2 = _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;
+       if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) {
+               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);
+               //level2->colormap = level2->sweep_colors;
+       }
+}
+
+static void _on_iso_changed(GtkRange *range, gpointer _level2)
+{
+       AWeatherLevel2 *level2 = _level2;
+       gfloat level = gtk_range_get_value(range);
+       aweather_level2_set_iso(level2, level);
 }
 
 GtkWidget *aweather_level2_get_config(AWeatherLevel2 *level2)
@@ -282,7 +412,7 @@ GtkWidget *aweather_level2_get_config(AWeatherLevel2 *level2)
        Radar *radar = level2->radar;
        g_debug("AWeatherLevel2: get_config - %p, %p", level2, radar);
        /* Clear existing items */
-       gdouble elev;
+       gfloat 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 = NULL;
@@ -298,6 +428,7 @@ GtkWidget *aweather_level2_get_config(AWeatherLevel2 *level2)
                        0,1, 0,1, GTK_FILL,GTK_FILL, 5,0);
        g_free(date_str);
 
+       /* Add sweeps */
        for (guint vi = 0; vi < radar->h.nvolumes; vi++) {
                Volume *vol = radar->v[vi];
                if (vol == NULL) continue;
@@ -351,34 +482,59 @@ GtkWidget *aweather_level2_get_config(AWeatherLevel2 *level2)
                        g_signal_connect(button, "clicked", G_CALLBACK(_on_sweep_clicked), level2);
                }
        }
+
+       /* Add Iso-surface volume */
+       g_object_get(table, "n-columns", &cols, NULL);
+       row_label = gtk_label_new("<b>Isosurface:</b>");
+       gtk_label_set_use_markup(GTK_LABEL(row_label), TRUE);
+       gtk_misc_set_alignment(GTK_MISC(row_label), 1, 0.5);
+       gtk_table_attach(GTK_TABLE(table), row_label,
+                       0,1, rows,rows+1, GTK_FILL,GTK_FILL, 5,0);
+       GtkWidget *scale = gtk_hscale_new_with_range(ISO_MIN, ISO_MAX, 0.5);
+       gtk_widget_set_size_request(scale, -1, 26);
+       gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_LEFT);
+       gtk_range_set_inverted(GTK_RANGE(scale), TRUE);
+       gtk_range_set_value(GTK_RANGE(scale), ISO_MAX);
+       g_signal_connect(scale, "value-changed", G_CALLBACK(_on_iso_changed), level2);
+       gtk_table_attach(GTK_TABLE(table), scale,
+                       1,cols+1, rows,rows+1, GTK_FILL|GTK_EXPAND,GTK_FILL, 0,0);
+       /* Shove all the buttons to the left, but keep the slider expanded */
+       gtk_table_attach(GTK_TABLE(table), gtk_label_new(""),
+                       cols,cols+1, 0,1, GTK_FILL|GTK_EXPAND,GTK_FILL, 0,0);
        return table;
 }
 
 /****************
  * GObject code *
  ****************/
-G_DEFINE_TYPE(AWeatherLevel2, aweather_level2, GIS_TYPE_CALLBACK);
-static void aweather_level2_init(AWeatherLevel2 *self)
+G_DEFINE_TYPE(AWeatherLevel2, aweather_level2, GRITS_TYPE_OBJECT);
+static void aweather_level2_init(AWeatherLevel2 *level2)
 {
-       GIS_CALLBACK(self)->callback  = _draw_radar;
-       GIS_CALLBACK(self)->user_data = self;
 }
-static void aweather_level2_dispose(GObject *_self)
+static void aweather_level2_dispose(GObject *_level2)
 {
-       g_debug("AWeatherLevel2: dispose - %p", _self);
-       G_OBJECT_CLASS(aweather_level2_parent_class)->dispose(_self);
+       AWeatherLevel2 *level2 = AWEATHER_LEVEL2(_level2);
+       g_debug("AWeatherLevel2: dispose - %p", _level2);
+       if (level2->volume) {
+               grits_viewer_remove(GRITS_OBJECT(level2->volume)->viewer,
+                               GRITS_OBJECT(level2->volume));
+               level2->volume = NULL;
+       }
+       G_OBJECT_CLASS(aweather_level2_parent_class)->dispose(_level2);
 }
-static void aweather_level2_finalize(GObject *_self)
+static void aweather_level2_finalize(GObject *_level2)
 {
-       AWeatherLevel2 *self = AWEATHER_LEVEL2(_self);
-       g_debug("AWeatherLevel2: finalize - %p", _self);
-       RSL_free_radar(self->radar);
-       if (self->sweep_tex)
-               glDeleteTextures(1, &self->sweep_tex);
-       G_OBJECT_CLASS(aweather_level2_parent_class)->finalize(_self);
+       AWeatherLevel2 *level2 = AWEATHER_LEVEL2(_level2);
+       g_debug("AWeatherLevel2: finalize - %p", _level2);
+       RSL_free_radar(level2->radar);
+       if (level2->sweep_tex)
+               glDeleteTextures(1, &level2->sweep_tex);
+       G_OBJECT_CLASS(aweather_level2_parent_class)->finalize(_level2);
 }
 static void aweather_level2_class_init(AWeatherLevel2Class *klass)
 {
-       G_OBJECT_CLASS(klass)->finalize = aweather_level2_finalize;
        G_OBJECT_CLASS(klass)->dispose  = aweather_level2_dispose;
+       G_OBJECT_CLASS(klass)->finalize = aweather_level2_finalize;
+       GRITS_OBJECT_CLASS(klass)->draw = aweather_level2_draw;
+       GRITS_OBJECT_CLASS(klass)->hide = aweather_level2_hide;
 }