1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
|
//
// animation.c - Demonstrates the use of the plplot canvas widget with gtk.
//
// Copyright (C) 2004, 2005 Thomas J. Duck
// All rights reserved.
//
// Thomas J. Duck <tom.duck@dal.ca>
// Department of Physics and Atmospheric Science,
// Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
//
// $Author: airwin $
// $Revision: 11289 $
// $Date: 2010-10-29 13:44:17 -0700 (Fri, 29 Oct 2010) $
// $Name$
//
//
// NOTICE
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301 USA
//
//
// DESCRIPTION
//
// This program demonstrates the use of the plplot canvas widget with gtk.
// Two graphs are draw in a window. When the Execute button is pressed,
// two different waves progress through the graph in real time. Plotting
// to the two graphs is handled in two different threads.
//
//
#include <glib.h>
#include <gtk/gtk.h>
#include <plplotcanvas.h>
#include <math.h>
// The number of time steps
#define STEPS 300
// The number of points and period for the first wave
#define NPTS 100
#define PERIOD 30
// The width and height for each plot widget
#define WIDTH 800
#define HEIGHT 300
// Run the plots in different threads
GThread* thread0 = NULL;
GThread* thread1 = NULL;
typedef struct
{
PlplotCanvas* canvas;
char * title;
} ThreadData;
ThreadData data0, data1;
gint Nthreads = 0; // Count the number of threads
// Create two different canvases
PlplotCanvas *canvas0 = NULL;
PlplotCanvas *canvas1 = NULL;
// Create the x and y array
static PLFLT x[NPTS], y[NPTS];
// Lock on the gtkstate so that we don't try to plot after gtk_main_quit
#define GTKSTATE_CONTINUE ( TRUE )
#define GTKSTATE_QUIT (FALSE)
G_LOCK_DEFINE_STATIC( gtkstate );
static volatile int gtkstate = GTKSTATE_CONTINUE;
// setup_plot - preparation for plotting an animation to a canvas
void setup_plot( PlplotCanvas *canvas, char* title )
{
// Set up the viewport and window
plplot_canvas_vsta( canvas );
plplot_canvas_wind( canvas, x[0], x[NPTS - 1], -2., 2. );
// Set the pen width
plplot_canvas_wid( canvas, 2 );
// The axes should be persistent, so that they don't have to be
// replotted every time (which would slow down the animation)
//
plplot_canvas_use_persistence( canvas, TRUE );
// Draw the axes
plplot_canvas_col0( canvas, 15 );
plplot_canvas_box( canvas, "bcnst", 0., 0, "bcnstv", 0., 0 );
plplot_canvas_lab( canvas, "(x)", "(y)", title );
// Prepare for plotting
plplot_canvas_col0( canvas, plplot_canvas_get_stream_number( canvas ) + 8 );
// The animated data should not be persistent
plplot_canvas_use_persistence( canvas, FALSE );
}
// plot - draws a plot on a canvas
void plot( PlplotCanvas *canvas, gdouble offset, char* title )
{
int i;
guint Nstream;
gdouble xmin, xmax, ymin, ymax;
// Get the stream number
Nstream = plplot_canvas_get_stream_number( canvas );
// Generate the sinusoid
for ( i = 0; i < NPTS; i++ )
y[i] = sin( 2. * 3.14 * ( x[i] + offset * ( Nstream + 1 ) ) / PERIOD / (PLFLT) ( Nstream + 1 ) );
// Draw the line
plplot_canvas_line( canvas, NPTS, x, y );
// Advance the page to finalize the plot
plplot_canvas_adv( canvas, 0 );
}
// Delete event callback
gint delete_event_local( GtkWidget *widget, GdkEvent *event, gpointer data )
{
return FALSE;
}
// Destroy event calback
void destroy_local( GtkWidget *widget, gpointer data )
{
G_LOCK( gtkstate );
gtkstate = GTKSTATE_QUIT;
G_UNLOCK( gtkstate );
gtk_main_quit();
}
GThreadFunc plot_thread( ThreadData* data )
{
int i;
Nthreads++;
// Draw STEPS plots in succession
for ( i = 0; i < STEPS; i++ )
{
gdk_threads_enter();
// Lock the current gtk state
G_LOCK( gtkstate );
// Check to make sure gtk hasn't quit
if ( gtkstate == GTKSTATE_QUIT )
{
G_UNLOCK( gtkstate );
gdk_threads_leave();
g_thread_exit( NULL );
}
// Draw the plot
plot( data->canvas, i, data->title );
// Release the lock
G_UNLOCK( gtkstate );
gdk_threads_leave();
}
Nthreads--;
g_thread_exit( NULL );
}
// Start threads callback from execute button
void start_threads( GtkWidget *widget, gpointer data )
{
GError **gerror;
// Ignore call if threads are currently active
if ( Nthreads )
return;
// Create the two plotting threads
data0.canvas = canvas0;
data0.title = "A phase-progressing wave";
if ( ( thread0 = g_thread_create( (GThreadFunc) plot_thread, &data0, TRUE, gerror ) ) \
== NULL )
{
fprintf( stderr, "Could not create thread" );
return;
}
data1.canvas = canvas1;
data1.title = "Another phase-progressing wave";
if ( ( thread1 = g_thread_create( (GThreadFunc) plot_thread, &data1, TRUE, gerror ) ) \
== NULL )
{
fprintf( stderr, "Could not create thread" );
return;
}
}
int main( int argc, char *argv[] )
{
int i;
GtkWidget *window;
GtkWidget *table;
GtkFrame *canvas0frame;
GtkFrame *canvas1frame;
GtkButton * button;
GtkBox * buttonbox;
GtkBox * vbox;
// Parse the options
plparseopts( &argc, (const char **) argv, PL_PARSE_FULL );
// Initialize
g_thread_init( NULL );
gdk_threads_init();
gtk_init( &argc, &argv );
g_type_init();
// Initialize the x array
for ( i = 0; i < NPTS; i++ )
x[i] = (PLFLT) i;
// Create the first canvas, set its size, draw some axes on it, and
// place it in a frame
//
canvas0 = plplot_canvas_new( TRUE );
plplot_canvas_set_size( canvas0, WIDTH, HEIGHT );
plplot_canvas_adv( canvas0, 0 );
setup_plot( canvas0, "A phase-progressing wave" );
plplot_canvas_adv( canvas0, 0 ); // Advance the page to finalize the plot
canvas0frame = GTK_FRAME( gtk_frame_new( NULL ) );
gtk_frame_set_shadow_type( canvas0frame, GTK_SHADOW_ETCHED_OUT );
gtk_container_add( GTK_CONTAINER( canvas0frame ), GTK_WIDGET( canvas0 ) );
// Create the second canvas, set its size, draw some axes on it, and
// place it in a frame
//
canvas1 = plplot_canvas_new( TRUE );
plplot_canvas_set_size( canvas1, WIDTH, HEIGHT );
plplot_canvas_adv( canvas1, 0 );
setup_plot( canvas1, "Another phase-progressing wave" );
plplot_canvas_adv( canvas1, 0 ); // Advance the page to finalize the plot
canvas1frame = GTK_FRAME( gtk_frame_new( NULL ) );
gtk_frame_set_shadow_type( canvas1frame, GTK_SHADOW_ETCHED_OUT );
gtk_container_add( GTK_CONTAINER( canvas1frame ), GTK_WIDGET( canvas1 ) );
// Create a button and put it in a box
button = GTK_BUTTON( gtk_button_new_from_stock( GTK_STOCK_EXECUTE ) );
g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( start_threads ),
NULL );
gtk_container_set_border_width( GTK_CONTAINER( button ), 10 );
buttonbox = GTK_BOX( gtk_hbox_new( FALSE, 0 ) );
gtk_box_pack_start( buttonbox, GTK_WIDGET( button ), TRUE, FALSE, 0 );
// Create and fill the vbox with the widgets
vbox = GTK_BOX( gtk_vbox_new( FALSE, 0 ) );
gtk_box_pack_start( vbox, GTK_WIDGET( canvas0frame ), TRUE, FALSE, 0 );
gtk_box_pack_start( vbox, GTK_WIDGET( canvas1frame ), TRUE, FALSE, 10 );
gtk_box_pack_start( vbox, GTK_WIDGET( buttonbox ), TRUE, FALSE, 0 );
// Create a new window
window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
// Set the border width of the window
gtk_container_set_border_width( GTK_CONTAINER( window ), 10 );
// Connect the signal handlers to the window decorations
g_signal_connect( G_OBJECT( window ), "delete_event",
G_CALLBACK( delete_event_local ), NULL );
g_signal_connect( G_OBJECT( window ), "destroy", G_CALLBACK( destroy_local ), NULL );
// Put the vbox into the window
gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( vbox ) );
// Display everything
gtk_widget_show_all( window );
// Start the gtk main loop
gdk_threads_enter();
gtk_main();
gdk_threads_leave();
return 0;
}
|