From 36649d4e472172fe840444ac0268c7b6b4da94b4 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Thu, 14 Aug 2008 18:43:15 +0000 Subject: Merged changeset r9241:9289 from jblum/glwxgui into trunk. Adds OpenGL versions of fftsink, waterfallsink, and scopesink, and new constsink. See README.gl for use. (Josh Blum) git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9290 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-wxgui/src/python/plotter/waterfall_plotter.py | 282 +++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 gr-wxgui/src/python/plotter/waterfall_plotter.py (limited to 'gr-wxgui/src/python/plotter/waterfall_plotter.py') diff --git a/gr-wxgui/src/python/plotter/waterfall_plotter.py b/gr-wxgui/src/python/plotter/waterfall_plotter.py new file mode 100644 index 000000000..88e2b4dc1 --- /dev/null +++ b/gr-wxgui/src/python/plotter/waterfall_plotter.py @@ -0,0 +1,282 @@ +# +# Copyright 2008 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import wx +from plotter_base import grid_plotter_base +from OpenGL.GL import * +from gnuradio.wxgui import common +import numpy +import gltext +import math + +LEGEND_LEFT_PAD = 7 +LEGEND_NUM_BLOCKS = 256 +LEGEND_NUM_LABELS = 9 +LEGEND_WIDTH = 8 +LEGEND_FONT_SIZE = 8 +LEGEND_BORDER_COLOR_SPEC = (0, 0, 0) #black +PADDING = 35, 60, 40, 60 #top, right, bottom, left + +ceil_log2 = lambda x: 2**int(math.ceil(math.log(x)/math.log(2))) + +def _get_rbga(red_pts, green_pts, blue_pts, alpha_pts=[(0, 0), (1, 0)]): + """! + Get an array of 256 rgba values where each index maps to a color. + The scaling for red, green, blue, alpha are specified in piece-wise functions. + The piece-wise functions consist of a set of x, y coordinates. + The x and y values of the coordinates range from 0 to 1. + The coordinates must be specified so that x increases with the index value. + Resulting values are calculated along the line formed between 2 coordinates. + @param *_pts an array of x,y coordinates for each color element + @return array of rbga values (4 bytes) each + """ + def _fcn(x, pw): + for (x1, y1), (x2, y2) in zip(pw, pw[1:]): + #linear interpolation + if x <= x2: return float(y1 - y2)/(x1 - x2)*(x - x1) + y1 + raise Exception + return [numpy.array(map( + lambda pw: int(255*_fcn(i/255.0, pw)), + (red_pts, green_pts, blue_pts, alpha_pts), + ), numpy.uint8).tostring() for i in range(0, 256) + ] + +COLORS = { + 'rgb1': _get_rbga( #http://www.ks.uiuc.edu/Research/vmd/vmd-1.7.1/ug/img47.gif + red_pts = [(0, 0), (.5, 0), (1, 1)], + green_pts = [(0, 0), (.5, 1), (1, 0)], + blue_pts = [(0, 1), (.5, 0), (1, 0)], + ), + 'rgb2': _get_rbga( #http://xtide.ldeo.columbia.edu/~krahmann/coledit/screen.jpg + red_pts = [(0, 0), (3.0/8, 0), (5.0/8, 1), (7.0/8, 1), (1, .5)], + green_pts = [(0, 0), (1.0/8, 0), (3.0/8, 1), (5.0/8, 1), (7.0/8, 0), (1, 0)], + blue_pts = [(0, .5), (1.0/8, 1), (3.0/8, 1), (5.0/8, 0), (1, 0)], + ), + 'rgb3': _get_rbga( + red_pts = [(0, 0), (1.0/3.0, 0), (2.0/3.0, 0), (1, 1)], + green_pts = [(0, 0), (1.0/3.0, 0), (2.0/3.0, 1), (1, 0)], + blue_pts = [(0, 0), (1.0/3.0, 1), (2.0/3.0, 0), (1, 0)], + ), + 'gray': _get_rbga( + red_pts = [(0, 0), (1, 1)], + green_pts = [(0, 0), (1, 1)], + blue_pts = [(0, 0), (1, 1)], + ), +} + +################################################## +# Waterfall Plotter +################################################## +class waterfall_plotter(grid_plotter_base): + def __init__(self, parent): + """! + Create a new channel plotter. + """ + #init + grid_plotter_base.__init__(self, parent, PADDING) + self._resize_texture(False) + self._minimum = 0 + self._maximum = 0 + self._fft_size = 1 + self._buffer = list() + self._pointer = 0 + self._counter = 0 + self.set_num_lines(0) + self.set_color_mode(COLORS.keys()[0]) + + def _gl_init(self): + """! + Run gl initialization tasks. + """ + self._grid_compiled_list_id = glGenLists(1) + self._waterfall_texture = glGenTextures(1) + + def draw(self): + """! + Draw the grid and waveforms. + """ + self.lock() + #resize texture + self._resize_texture() + #store the grid drawing operations + if self.changed(): + glNewList(self._grid_compiled_list_id, GL_COMPILE) + self._draw_grid() + self._draw_legend() + glEndList() + self.changed(False) + self.clear() + #draw the grid + glCallList(self._grid_compiled_list_id) + self._draw_waterfall() + self._draw_point_label() + #swap buffer into display + self.SwapBuffers() + self.unlock() + + def _draw_waterfall(self): + """! + Draw the waterfall from the texture. + The texture is circularly filled and will wrap around. + Use matrix modeling to shift and scale the texture onto the coordinate plane. + """ + #setup texture + glBindTexture(GL_TEXTURE_2D, self._waterfall_texture) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE) + #write the buffer to the texture + while self._buffer: + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, self._pointer, self._fft_size, 1, GL_RGBA, GL_UNSIGNED_BYTE, self._buffer.pop(0)) + self._pointer = (self._pointer + 1)%self._num_lines + #begin drawing + glEnable(GL_TEXTURE_2D) + glPushMatrix() + #matrix scaling + glTranslatef(self.padding_left+1, self.padding_top, 0) + glScalef( + float(self.width-self.padding_left-self.padding_right-1), + float(self.height-self.padding_top-self.padding_bottom-1), + 1.0, + ) + #draw texture with wrapping + glBegin(GL_QUADS) + prop_y = float(self._pointer)/(self._num_lines-1) + prop_x = float(self._fft_size)/ceil_log2(self._fft_size) + off = 1.0/(self._num_lines-1) + glTexCoord2f(0, prop_y+1-off) + glVertex2f(0, 1) + glTexCoord2f(prop_x, prop_y+1-off) + glVertex2f(1, 1) + glTexCoord2f(prop_x, prop_y) + glVertex2f(1, 0) + glTexCoord2f(0, prop_y) + glVertex2f(0, 0) + glEnd() + glPopMatrix() + glDisable(GL_TEXTURE_2D) + + def _populate_point_label(self, x_val, y_val): + """! + Get the text the will populate the point label. + Give the X value for the current point. + @param x_val the current x value + @param y_val the current y value + @return a value string with units + """ + return '%s: %s %s'%(self.x_label, common.label_format(x_val), self.x_units) + + def _draw_legend(self): + """! + Draw the color scale legend. + """ + if not self._color_mode: return + legend_height = self.height-self.padding_top-self.padding_bottom + #draw each legend block + block_height = float(legend_height)/LEGEND_NUM_BLOCKS + x = self.width - self.padding_right + LEGEND_LEFT_PAD + for i in range(LEGEND_NUM_BLOCKS): + color = COLORS[self._color_mode][int(255*i/float(LEGEND_NUM_BLOCKS-1))] + glColor4f(*map(lambda c: ord(c)/255.0, color)) + y = self.height - (i+1)*block_height - self.padding_bottom + self._draw_rect(x, y, LEGEND_WIDTH, block_height) + #draw rectangle around color scale border + glColor3f(*LEGEND_BORDER_COLOR_SPEC) + self._draw_rect(x, self.padding_top, LEGEND_WIDTH, legend_height, fill=False) + #draw each legend label + label_spacing = float(legend_height)/(LEGEND_NUM_LABELS-1) + x = self.width - (self.padding_right - LEGEND_LEFT_PAD - LEGEND_WIDTH)/2 + for i in range(LEGEND_NUM_LABELS): + proportion = i/float(LEGEND_NUM_LABELS-1) + dB = proportion*(self._maximum - self._minimum) + self._minimum + y = self.height - i*label_spacing - self.padding_bottom + txt = gltext.Text('%ddB'%int(dB), font_size=LEGEND_FONT_SIZE, centered=True) + txt.draw_text(wx.Point(x, y)) + + def _resize_texture(self, flag=None): + """! + Create the texture to fit the fft_size X num_lines. + @param flag the set/unset or update flag + """ + if flag is not None: + self._resize_texture_flag = flag + return + if not self._resize_texture_flag: return + self._buffer = list() + self._pointer = 0 + if self._num_lines and self._fft_size: + glBindTexture(GL_TEXTURE_2D, self._waterfall_texture) + data = numpy.zeros(self._num_lines*self._fft_size*4, numpy.uint8).tostring() + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ceil_log2(self._fft_size), self._num_lines, 0, GL_RGBA, GL_UNSIGNED_BYTE, data) + self._resize_texture_flag = False + + def set_color_mode(self, color_mode): + """! + Set the color mode. + New samples will be converted to the new color mode. + Old samples will not be recolorized. + @param color_mode the new color mode string + """ + self.lock() + if color_mode in COLORS.keys(): + self._color_mode = color_mode + self.changed(True) + self.update() + self.unlock() + + def set_num_lines(self, num_lines): + """! + Set number of lines. + Powers of two only. + @param num_lines the new number of lines + """ + self.lock() + self._num_lines = num_lines + self._resize_texture(True) + self.update() + self.unlock() + + def set_samples(self, samples, minimum, maximum): + """! + Set the samples to the waterfall. + Convert the samples to color data. + @param samples the array of floats + @param minimum the minimum value to scale + @param maximum the maximum value to scale + """ + self.lock() + #set the min, max values + if self._minimum != minimum or self._maximum != maximum: + self._minimum = minimum + self._maximum = maximum + self.changed(True) + if self._fft_size != len(samples): + self._fft_size = len(samples) + self._resize_texture(True) + #normalize the samples to min/max + samples = (samples - minimum)*float(255/(maximum-minimum)) + samples = numpy.clip(samples, 0, 255) #clip + samples = numpy.array(samples, numpy.uint8) + #convert the samples to RGBA data + data = numpy.choose(samples, COLORS[self._color_mode]).tostring() + self._buffer.append(data) + self.unlock() -- cgit From ec6d18c95d58707ad89f14e094bf592047048227 Mon Sep 17 00:00:00 2001 From: jblum Date: Tue, 2 Sep 2008 07:24:19 +0000 Subject: replaced semaphore with primitive lock, adjusted drawing bounds git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9482 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-wxgui/src/python/plotter/waterfall_plotter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'gr-wxgui/src/python/plotter/waterfall_plotter.py') diff --git a/gr-wxgui/src/python/plotter/waterfall_plotter.py b/gr-wxgui/src/python/plotter/waterfall_plotter.py index 88e2b4dc1..42c17da86 100644 --- a/gr-wxgui/src/python/plotter/waterfall_plotter.py +++ b/gr-wxgui/src/python/plotter/waterfall_plotter.py @@ -152,10 +152,10 @@ class waterfall_plotter(grid_plotter_base): glEnable(GL_TEXTURE_2D) glPushMatrix() #matrix scaling - glTranslatef(self.padding_left+1, self.padding_top, 0) + glTranslatef(self.padding_left, self.padding_top, 0) glScalef( - float(self.width-self.padding_left-self.padding_right-1), - float(self.height-self.padding_top-self.padding_bottom-1), + float(self.width-self.padding_left-self.padding_right), + float(self.height-self.padding_top-self.padding_bottom), 1.0, ) #draw texture with wrapping -- cgit From 924831afcdb187b3de670be6fd1f6147d62be5cf Mon Sep 17 00:00:00 2001 From: jblum Date: Wed, 10 Sep 2008 01:23:21 +0000 Subject: Replaced """! with """. Exclamation mark showed in doxygen docs. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9549 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-wxgui/src/python/plotter/waterfall_plotter.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'gr-wxgui/src/python/plotter/waterfall_plotter.py') diff --git a/gr-wxgui/src/python/plotter/waterfall_plotter.py b/gr-wxgui/src/python/plotter/waterfall_plotter.py index 42c17da86..4dc19f672 100644 --- a/gr-wxgui/src/python/plotter/waterfall_plotter.py +++ b/gr-wxgui/src/python/plotter/waterfall_plotter.py @@ -38,7 +38,7 @@ PADDING = 35, 60, 40, 60 #top, right, bottom, left ceil_log2 = lambda x: 2**int(math.ceil(math.log(x)/math.log(2))) def _get_rbga(red_pts, green_pts, blue_pts, alpha_pts=[(0, 0), (1, 0)]): - """! + """ Get an array of 256 rgba values where each index maps to a color. The scaling for red, green, blue, alpha are specified in piece-wise functions. The piece-wise functions consist of a set of x, y coordinates. @@ -87,7 +87,7 @@ COLORS = { ################################################## class waterfall_plotter(grid_plotter_base): def __init__(self, parent): - """! + """ Create a new channel plotter. """ #init @@ -103,14 +103,14 @@ class waterfall_plotter(grid_plotter_base): self.set_color_mode(COLORS.keys()[0]) def _gl_init(self): - """! + """ Run gl initialization tasks. """ self._grid_compiled_list_id = glGenLists(1) self._waterfall_texture = glGenTextures(1) def draw(self): - """! + """ Draw the grid and waveforms. """ self.lock() @@ -133,7 +133,7 @@ class waterfall_plotter(grid_plotter_base): self.unlock() def _draw_waterfall(self): - """! + """ Draw the waterfall from the texture. The texture is circularly filled and will wrap around. Use matrix modeling to shift and scale the texture onto the coordinate plane. @@ -176,7 +176,7 @@ class waterfall_plotter(grid_plotter_base): glDisable(GL_TEXTURE_2D) def _populate_point_label(self, x_val, y_val): - """! + """ Get the text the will populate the point label. Give the X value for the current point. @param x_val the current x value @@ -186,7 +186,7 @@ class waterfall_plotter(grid_plotter_base): return '%s: %s %s'%(self.x_label, common.label_format(x_val), self.x_units) def _draw_legend(self): - """! + """ Draw the color scale legend. """ if not self._color_mode: return @@ -213,7 +213,7 @@ class waterfall_plotter(grid_plotter_base): txt.draw_text(wx.Point(x, y)) def _resize_texture(self, flag=None): - """! + """ Create the texture to fit the fft_size X num_lines. @param flag the set/unset or update flag """ @@ -230,7 +230,7 @@ class waterfall_plotter(grid_plotter_base): self._resize_texture_flag = False def set_color_mode(self, color_mode): - """! + """ Set the color mode. New samples will be converted to the new color mode. Old samples will not be recolorized. @@ -244,7 +244,7 @@ class waterfall_plotter(grid_plotter_base): self.unlock() def set_num_lines(self, num_lines): - """! + """ Set number of lines. Powers of two only. @param num_lines the new number of lines @@ -256,7 +256,7 @@ class waterfall_plotter(grid_plotter_base): self.unlock() def set_samples(self, samples, minimum, maximum): - """! + """ Set the samples to the waterfall. Convert the samples to color data. @param samples the array of floats -- cgit From d9744799b7df6c09180778540bf55eb9dc84281b Mon Sep 17 00:00:00 2001 From: jcorgan Date: Fri, 20 Mar 2009 02:16:20 +0000 Subject: Merged r10463:10658 from jblum/gui_guts into trunk. Trunk passes distcheck. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10660 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-wxgui/src/python/plotter/waterfall_plotter.py | 107 ++++++++++------------- 1 file changed, 46 insertions(+), 61 deletions(-) (limited to 'gr-wxgui/src/python/plotter/waterfall_plotter.py') diff --git a/gr-wxgui/src/python/plotter/waterfall_plotter.py b/gr-wxgui/src/python/plotter/waterfall_plotter.py index 4dc19f672..2e0669961 100644 --- a/gr-wxgui/src/python/plotter/waterfall_plotter.py +++ b/gr-wxgui/src/python/plotter/waterfall_plotter.py @@ -1,5 +1,5 @@ # -# Copyright 2008 Free Software Foundation, Inc. +# Copyright 2008, 2009 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -20,9 +20,9 @@ # import wx -from plotter_base import grid_plotter_base -from OpenGL.GL import * -from gnuradio.wxgui import common +from grid_plotter_base import grid_plotter_base +from OpenGL import GL +import common import numpy import gltext import math @@ -33,7 +33,7 @@ LEGEND_NUM_LABELS = 9 LEGEND_WIDTH = 8 LEGEND_FONT_SIZE = 8 LEGEND_BORDER_COLOR_SPEC = (0, 0, 0) #black -PADDING = 35, 60, 40, 60 #top, right, bottom, left +MIN_PADDING = 0, 60, 0, 0 #top, right, bottom, left ceil_log2 = lambda x: 2**int(math.ceil(math.log(x)/math.log(2))) @@ -91,7 +91,13 @@ class waterfall_plotter(grid_plotter_base): Create a new channel plotter. """ #init - grid_plotter_base.__init__(self, parent, PADDING) + grid_plotter_base.__init__(self, parent, MIN_PADDING) + #setup legend cache + self._legend_cache = self.new_gl_cache(self._draw_legend) + #setup waterfall cache + self._waterfall_cache = self.new_gl_cache(self._draw_waterfall, 50) + #setup waterfall plotter + self.register_init(self._init_waterfall) self._resize_texture(False) self._minimum = 0 self._maximum = 0 @@ -102,35 +108,11 @@ class waterfall_plotter(grid_plotter_base): self.set_num_lines(0) self.set_color_mode(COLORS.keys()[0]) - def _gl_init(self): + def _init_waterfall(self): """ Run gl initialization tasks. """ - self._grid_compiled_list_id = glGenLists(1) - self._waterfall_texture = glGenTextures(1) - - def draw(self): - """ - Draw the grid and waveforms. - """ - self.lock() - #resize texture - self._resize_texture() - #store the grid drawing operations - if self.changed(): - glNewList(self._grid_compiled_list_id, GL_COMPILE) - self._draw_grid() - self._draw_legend() - glEndList() - self.changed(False) - self.clear() - #draw the grid - glCallList(self._grid_compiled_list_id) - self._draw_waterfall() - self._draw_point_label() - #swap buffer into display - self.SwapBuffers() - self.unlock() + self._waterfall_texture = GL.glGenTextures(1) def _draw_waterfall(self): """ @@ -138,42 +120,44 @@ class waterfall_plotter(grid_plotter_base): The texture is circularly filled and will wrap around. Use matrix modeling to shift and scale the texture onto the coordinate plane. """ + #resize texture + self._resize_texture() #setup texture - glBindTexture(GL_TEXTURE_2D, self._waterfall_texture) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE) + GL.glBindTexture(GL.GL_TEXTURE_2D, self._waterfall_texture) + GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR) + GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR) + GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT) + GL.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE) #write the buffer to the texture while self._buffer: - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, self._pointer, self._fft_size, 1, GL_RGBA, GL_UNSIGNED_BYTE, self._buffer.pop(0)) + GL.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, self._pointer, self._fft_size, 1, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, self._buffer.pop(0)) self._pointer = (self._pointer + 1)%self._num_lines #begin drawing - glEnable(GL_TEXTURE_2D) - glPushMatrix() + GL.glEnable(GL.GL_TEXTURE_2D) + GL.glPushMatrix() #matrix scaling - glTranslatef(self.padding_left, self.padding_top, 0) - glScalef( + GL.glTranslatef(self.padding_left, self.padding_top, 0) + GL.glScalef( float(self.width-self.padding_left-self.padding_right), float(self.height-self.padding_top-self.padding_bottom), 1.0, ) #draw texture with wrapping - glBegin(GL_QUADS) + GL.glBegin(GL.GL_QUADS) prop_y = float(self._pointer)/(self._num_lines-1) prop_x = float(self._fft_size)/ceil_log2(self._fft_size) off = 1.0/(self._num_lines-1) - glTexCoord2f(0, prop_y+1-off) - glVertex2f(0, 1) - glTexCoord2f(prop_x, prop_y+1-off) - glVertex2f(1, 1) - glTexCoord2f(prop_x, prop_y) - glVertex2f(1, 0) - glTexCoord2f(0, prop_y) - glVertex2f(0, 0) - glEnd() - glPopMatrix() - glDisable(GL_TEXTURE_2D) + GL.glTexCoord2f(0, prop_y+1-off) + GL.glVertex2f(0, 1) + GL.glTexCoord2f(prop_x, prop_y+1-off) + GL.glVertex2f(1, 1) + GL.glTexCoord2f(prop_x, prop_y) + GL.glVertex2f(1, 0) + GL.glTexCoord2f(0, prop_y) + GL.glVertex2f(0, 0) + GL.glEnd() + GL.glPopMatrix() + GL.glDisable(GL.GL_TEXTURE_2D) def _populate_point_label(self, x_val, y_val): """ @@ -183,7 +167,7 @@ class waterfall_plotter(grid_plotter_base): @param y_val the current y value @return a value string with units """ - return '%s: %s %s'%(self.x_label, common.label_format(x_val), self.x_units) + return '%s: %s'%(self.x_label, common.eng_format(x_val, self.x_units)) def _draw_legend(self): """ @@ -196,11 +180,11 @@ class waterfall_plotter(grid_plotter_base): x = self.width - self.padding_right + LEGEND_LEFT_PAD for i in range(LEGEND_NUM_BLOCKS): color = COLORS[self._color_mode][int(255*i/float(LEGEND_NUM_BLOCKS-1))] - glColor4f(*map(lambda c: ord(c)/255.0, color)) + GL.glColor4f(*map(lambda c: ord(c)/255.0, color)) y = self.height - (i+1)*block_height - self.padding_bottom self._draw_rect(x, y, LEGEND_WIDTH, block_height) #draw rectangle around color scale border - glColor3f(*LEGEND_BORDER_COLOR_SPEC) + GL.glColor3f(*LEGEND_BORDER_COLOR_SPEC) self._draw_rect(x, self.padding_top, LEGEND_WIDTH, legend_height, fill=False) #draw each legend label label_spacing = float(legend_height)/(LEGEND_NUM_LABELS-1) @@ -224,9 +208,9 @@ class waterfall_plotter(grid_plotter_base): self._buffer = list() self._pointer = 0 if self._num_lines and self._fft_size: - glBindTexture(GL_TEXTURE_2D, self._waterfall_texture) + GL.glBindTexture(GL.GL_TEXTURE_2D, self._waterfall_texture) data = numpy.zeros(self._num_lines*self._fft_size*4, numpy.uint8).tostring() - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ceil_log2(self._fft_size), self._num_lines, 0, GL_RGBA, GL_UNSIGNED_BYTE, data) + GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, ceil_log2(self._fft_size), self._num_lines, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, data) self._resize_texture_flag = False def set_color_mode(self, color_mode): @@ -239,7 +223,7 @@ class waterfall_plotter(grid_plotter_base): self.lock() if color_mode in COLORS.keys(): self._color_mode = color_mode - self.changed(True) + self._legend_cache.changed(True) self.update() self.unlock() @@ -268,7 +252,7 @@ class waterfall_plotter(grid_plotter_base): if self._minimum != minimum or self._maximum != maximum: self._minimum = minimum self._maximum = maximum - self.changed(True) + self._legend_cache.changed(True) if self._fft_size != len(samples): self._fft_size = len(samples) self._resize_texture(True) @@ -279,4 +263,5 @@ class waterfall_plotter(grid_plotter_base): #convert the samples to RGBA data data = numpy.choose(samples, COLORS[self._color_mode]).tostring() self._buffer.append(data) + self._waterfall_cache.changed(True) self.unlock() -- cgit From eb1d1b5cfb474b087d41337356efc0cdb7342f28 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 2 Sep 2009 14:06:34 -0700 Subject: Fix so that the waterfall texture is initialized with a buffer of the same size. If the fft size was a non power of two, the buffer would be a different size. This would cause a segfault. Particularly because fft_window was throwing out a bin. --- gr-wxgui/src/python/plotter/waterfall_plotter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-wxgui/src/python/plotter/waterfall_plotter.py') diff --git a/gr-wxgui/src/python/plotter/waterfall_plotter.py b/gr-wxgui/src/python/plotter/waterfall_plotter.py index 2e0669961..d32b0ca0a 100644 --- a/gr-wxgui/src/python/plotter/waterfall_plotter.py +++ b/gr-wxgui/src/python/plotter/waterfall_plotter.py @@ -209,7 +209,7 @@ class waterfall_plotter(grid_plotter_base): self._pointer = 0 if self._num_lines and self._fft_size: GL.glBindTexture(GL.GL_TEXTURE_2D, self._waterfall_texture) - data = numpy.zeros(self._num_lines*self._fft_size*4, numpy.uint8).tostring() + data = numpy.zeros(self._num_lines*ceil_log2(self._fft_size)*4, numpy.uint8).tostring() GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, ceil_log2(self._fft_size), self._num_lines, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, data) self._resize_texture_flag = False -- cgit From f6a770799b8725546044a59067f1ab9937ee3af1 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 26 Dec 2009 22:43:29 -0500 Subject: bug fix for waterfall plotter, it seems that numpy choose changed --- gr-wxgui/src/python/plotter/waterfall_plotter.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'gr-wxgui/src/python/plotter/waterfall_plotter.py') diff --git a/gr-wxgui/src/python/plotter/waterfall_plotter.py b/gr-wxgui/src/python/plotter/waterfall_plotter.py index d32b0ca0a..f83e27e72 100644 --- a/gr-wxgui/src/python/plotter/waterfall_plotter.py +++ b/gr-wxgui/src/python/plotter/waterfall_plotter.py @@ -26,6 +26,7 @@ import common import numpy import gltext import math +import struct LEGEND_LEFT_PAD = 7 LEGEND_NUM_BLOCKS = 256 @@ -37,6 +38,9 @@ MIN_PADDING = 0, 60, 0, 0 #top, right, bottom, left ceil_log2 = lambda x: 2**int(math.ceil(math.log(x)/math.log(2))) +pack_color = lambda x: struct.pack('BBBB', *x) +unpack_color = lambda s: struct.unpack('BBBB', s) + def _get_rbga(red_pts, green_pts, blue_pts, alpha_pts=[(0, 0), (1, 0)]): """ Get an array of 256 rgba values where each index maps to a color. @@ -53,10 +57,10 @@ def _get_rbga(red_pts, green_pts, blue_pts, alpha_pts=[(0, 0), (1, 0)]): #linear interpolation if x <= x2: return float(y1 - y2)/(x1 - x2)*(x - x1) + y1 raise Exception - return [numpy.array(map( + return [pack_color(map( lambda pw: int(255*_fcn(i/255.0, pw)), (red_pts, green_pts, blue_pts, alpha_pts), - ), numpy.uint8).tostring() for i in range(0, 256) + )) for i in range(0, 256) ] COLORS = { @@ -179,8 +183,8 @@ class waterfall_plotter(grid_plotter_base): block_height = float(legend_height)/LEGEND_NUM_BLOCKS x = self.width - self.padding_right + LEGEND_LEFT_PAD for i in range(LEGEND_NUM_BLOCKS): - color = COLORS[self._color_mode][int(255*i/float(LEGEND_NUM_BLOCKS-1))] - GL.glColor4f(*map(lambda c: ord(c)/255.0, color)) + color = unpack_color(COLORS[self._color_mode][int(255*i/float(LEGEND_NUM_BLOCKS-1))]) + GL.glColor4f(*numpy.array(color)/255.0) y = self.height - (i+1)*block_height - self.padding_bottom self._draw_rect(x, y, LEGEND_WIDTH, block_height) #draw rectangle around color scale border @@ -261,7 +265,7 @@ class waterfall_plotter(grid_plotter_base): samples = numpy.clip(samples, 0, 255) #clip samples = numpy.array(samples, numpy.uint8) #convert the samples to RGBA data - data = numpy.choose(samples, COLORS[self._color_mode]).tostring() + data = ''.join([COLORS[self._color_mode][sample] for sample in samples]) self._buffer.append(data) self._waterfall_cache.changed(True) self.unlock() -- cgit From bd18b8192c78bb7af4a9c3d3a6c367cde3527311 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 6 Jan 2010 22:08:27 -0800 Subject: Use numpy to do color table lookup. You can index a numpy array with another numpy array to get an array of looked-up values. I did not know that numpy could do that! --- gr-wxgui/src/python/plotter/waterfall_plotter.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'gr-wxgui/src/python/plotter/waterfall_plotter.py') diff --git a/gr-wxgui/src/python/plotter/waterfall_plotter.py b/gr-wxgui/src/python/plotter/waterfall_plotter.py index f83e27e72..0af64b826 100644 --- a/gr-wxgui/src/python/plotter/waterfall_plotter.py +++ b/gr-wxgui/src/python/plotter/waterfall_plotter.py @@ -1,5 +1,5 @@ # -# Copyright 2008, 2009 Free Software Foundation, Inc. +# Copyright 2008, 2009, 2010 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -38,8 +38,8 @@ MIN_PADDING = 0, 60, 0, 0 #top, right, bottom, left ceil_log2 = lambda x: 2**int(math.ceil(math.log(x)/math.log(2))) -pack_color = lambda x: struct.pack('BBBB', *x) -unpack_color = lambda s: struct.unpack('BBBB', s) +pack_color = lambda x: struct.unpack('I', struct.pack('BBBB', *x))[0] +unpack_color = lambda x: struct.unpack('BBBB', struct.pack('I', int(x))) def _get_rbga(red_pts, green_pts, blue_pts, alpha_pts=[(0, 0), (1, 0)]): """ @@ -57,11 +57,10 @@ def _get_rbga(red_pts, green_pts, blue_pts, alpha_pts=[(0, 0), (1, 0)]): #linear interpolation if x <= x2: return float(y1 - y2)/(x1 - x2)*(x - x1) + y1 raise Exception - return [pack_color(map( - lambda pw: int(255*_fcn(i/255.0, pw)), - (red_pts, green_pts, blue_pts, alpha_pts), - )) for i in range(0, 256) - ] + return numpy.array([pack_color(map( + lambda pw: int(255*_fcn(i/255.0, pw)), + (red_pts, green_pts, blue_pts, alpha_pts), + )) for i in range(0, 256)], numpy.uint32) COLORS = { 'rgb1': _get_rbga( #http://www.ks.uiuc.edu/Research/vmd/vmd-1.7.1/ug/img47.gif @@ -265,7 +264,7 @@ class waterfall_plotter(grid_plotter_base): samples = numpy.clip(samples, 0, 255) #clip samples = numpy.array(samples, numpy.uint8) #convert the samples to RGBA data - data = ''.join([COLORS[self._color_mode][sample] for sample in samples]) + data = COLORS[self._color_mode][samples].tostring() self._buffer.append(data) self._waterfall_cache.changed(True) self.unlock() -- cgit From f919f9dcbb54a08e6e26d6c229ce92fb784fa1b2 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 13 Apr 2012 18:36:53 -0400 Subject: Removed whitespace and added dtools/bin/remove-whitespace as a tool to do this in the future. The sed script was provided by Moritz Fischer. --- gr-wxgui/src/python/plotter/waterfall_plotter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-wxgui/src/python/plotter/waterfall_plotter.py') diff --git a/gr-wxgui/src/python/plotter/waterfall_plotter.py b/gr-wxgui/src/python/plotter/waterfall_plotter.py index 0af64b826..f2456241c 100644 --- a/gr-wxgui/src/python/plotter/waterfall_plotter.py +++ b/gr-wxgui/src/python/plotter/waterfall_plotter.py @@ -204,7 +204,7 @@ class waterfall_plotter(grid_plotter_base): Create the texture to fit the fft_size X num_lines. @param flag the set/unset or update flag """ - if flag is not None: + if flag is not None: self._resize_texture_flag = flag return if not self._resize_texture_flag: return -- cgit From ed838eb9be22d769247a9c63f23423c8c2f81f72 Mon Sep 17 00:00:00 2001 From: Marcus Leech Date: Mon, 21 May 2012 14:35:33 -0400 Subject: wxgui: allows LEFT click to set a flow-graph variable to the adjusted X value on either the FFT or waterfall display. --- gr-wxgui/src/python/plotter/waterfall_plotter.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gr-wxgui/src/python/plotter/waterfall_plotter.py') diff --git a/gr-wxgui/src/python/plotter/waterfall_plotter.py b/gr-wxgui/src/python/plotter/waterfall_plotter.py index f2456241c..6a6bf6330 100644 --- a/gr-wxgui/src/python/plotter/waterfall_plotter.py +++ b/gr-wxgui/src/python/plotter/waterfall_plotter.py @@ -110,6 +110,7 @@ class waterfall_plotter(grid_plotter_base): self._counter = 0 self.set_num_lines(0) self.set_color_mode(COLORS.keys()[0]) + self.callback = None def _init_waterfall(self): """ @@ -172,6 +173,13 @@ class waterfall_plotter(grid_plotter_base): """ return '%s: %s'%(self.x_label, common.eng_format(x_val, self.x_units)) + def _call_callback(self, x_val, y_val): + if self.callback != None: + self.callback(x_val,y_val) + + def set_callback(self,callback): + self.callback = callback + def _draw_legend(self): """ Draw the color scale legend. -- cgit