TSP: The Transport Sample Protocol



Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

plotwindow.c

00001 
00002 /* GTK - The GIMP Toolkit
00003  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public
00016  * License along with this library; if not, write to the
00017  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018  * Boston, MA 02111-1307, USA.
00019  */
00020 
00021 #include <gdk/gdk.h>
00022 #include <gtk/gtkvbox.h>
00023 
00024 #include <pthread.h>
00025 
00026 #include "plotwindow.h"
00027 
00028 #ifdef __OpenBSD__
00029 #include <sys/limits.h>
00030 #define MAXINT INT_MAX
00031 #endif /* __OpenBSD__ */
00032 
00033 #include <sys/time.h>
00034 #include <sys/types.h>
00035 #include <unistd.h>
00036 #include <stdlib.h>
00037 #include <fcntl.h>
00038 #include <stdio.h>
00039 #include <assert.h>
00040 #include <math.h>
00041 
00042 
00043 #define MARGIN 60
00044 
00045 #define XY_MODE_MAX_POINT 200
00046 #define MAX_SAMPLE_NUMBER 10000
00047 #define SCROLL_RATIO 0.10
00048 #define AUTOSCALE_RATIO 0.08
00049 
00050 #define WIDGET_INIT_SIZE_X 120
00051 #define WIDGET_INIT_SIZE_Y 100
00052 
00053 /* 0.5f is there to solve round problems */
00054 #define COORD_SAMP_TO_PIX(bias, scale, coord)    ((bias) + (double)(coord) * (scale) + 0.5f)
00055 #define COORD_SAMP_TO_PIX_X(pw, x) COORD_SAMP_TO_PIX((pw)->mapping.x_bias, (pw)->mapping.x_scale, x)
00056 #define COORD_SAMP_TO_PIX_Y(pw, y) COORD_SAMP_TO_PIX((pw)->mapping.y_bias, (pw)->mapping.y_scale, y)
00057 
00058 #define IS_SAME_PIXEL(pix1, pix2)  ( (pix1.x == pix2.x) && (pix1.y == pix2.y) )
00059 
00060 /* pixel coord boundaries inside plotting area */
00061 #define X_LEFT_MARGIN  (MARGIN*9/10) /* need area for Y axis */
00062 #define X_RIGHT_MARGIN (MARGIN-X_LEFT_MARGIN)
00063 #define X_LEFT_IN(pw)  X_LEFT_MARGIN /* need area for Y axisds */
00064 #define X_RIGHT_IN(pw) (pw->widget.allocation.width-X_RIGHT_MARGIN)
00065 #define Y_LOW_IN(pw)   (pw->widget.allocation.height-(MARGIN/2))
00066 #define Y_TOP_IN(pw)   (MARGIN/2)
00067 
00068 /* pixel coord boundaries outside plotting area */
00069 #define X_LEFT_OUT(pw)  (X_LEFT_IN(pw) - 1)
00070 #define X_RIGHT_OUT(pw) (X_RIGHT_IN(pw) + 1)
00071 #define Y_LOW_OUT(pw)   (Y_LOW_IN(pw) + 1)
00072 #define Y_TOP_OUT(pw)   (Y_TOP_IN(pw) - 1)
00073 
00074 
00075 
00076 
00077 
00078 static void plotwindow_class_init (PlotWindowClass *class);
00079 static void plotwindow_init (PlotWindow *pw);
00080 static void plotwindow_realize (GtkWidget *widget);
00081 static void plotwindow_map();
00082 static void plotwindow_draw(); 
00083 static void plotwindow_size_allocate(GtkWidget *widget, GtkAllocation *allocation);
00084 static gint plotwindow_expose(GtkWidget *widget, GdkEventExpose *event) ;
00085 static void render_now (PlotWindow *pw);
00086   
00087 gint paint_data (void *arg);
00088 void draw_grids(PlotWindow *pw, GdkDrawable *where, int partial);
00089 void *background_drawing (void *arg);
00090 gint generator( void *arg);
00091 
00092     
00093 static GtkWidgetClass *parent_class = NULL;
00094 
00095 struct GtkTypeInfo
00096 {
00097   gchar                 *type_name;
00098   guint                  object_size;
00099   guint                  class_size;
00100   GtkClassInitFunc       class_init_func;
00101   GtkObjectInitFunc      object_init_func;
00102   gpointer               reserved_1;
00103   gpointer               reserved_2;
00104   GtkClassInitFunc       base_class_init_func;
00105 };
00106 
00107 
00108 GtkType
00109 plotwindow_get_type () {
00110   static guint pw_type = 0;
00111   if (!pw_type) {
00112     GtkTypeInfo pw_info = {
00113       "PlotWindow",
00114       sizeof(PlotWindow),
00115       sizeof(PlotWindowClass),
00116       (GtkClassInitFunc) plotwindow_class_init,
00117       (GtkObjectInitFunc) plotwindow_init,
00118       NULL,
00119       NULL,
00120       (GtkClassInitFunc) NULL
00121     };
00122     pw_type = gtk_type_unique (gtk_widget_get_type(), &pw_info);
00123   }
00124   return pw_type;
00125 }
00126 
00127 /* Initializes the fields of the widget's class structure, and sets up any signals for the class */
00128 static void
00129 plotwindow_class_init (PlotWindowClass *class) {
00130   GtkObjectClass *object_class;
00131   GtkWidgetClass *widget_class;
00132 
00133   object_class = (GtkObjectClass*) class;
00134   widget_class = (GtkWidgetClass*) class;
00135     
00136   parent_class = gtk_type_class (gtk_widget_get_type ());
00137   widget_class->expose_event = plotwindow_expose;
00138   widget_class->realize = plotwindow_realize;
00139   widget_class->size_allocate = plotwindow_size_allocate;
00140   widget_class->size_allocate = plotwindow_size_allocate;
00141     
00142 }
00143 
00144 static void 
00145 plotwindow_size_allocate (GtkWidget *widget, GtkAllocation *allocation) {
00146   PlotWindow *pw;
00147     
00148   g_return_if_fail (widget != NULL);
00149   g_return_if_fail (IS_PLOTWINDOW (widget));
00150   g_return_if_fail (allocation != NULL);
00151 
00152   widget->allocation = *allocation;
00153   pw = PLOTWINDOW (widget);
00154     
00155   if (GTK_WIDGET_REALIZED (widget)) {
00156 
00157     pw->scale_dirty = TRUE;
00158 
00159     gdk_window_move_resize (widget->window,
00160                             allocation->x, allocation->y,
00161                             allocation->width, allocation->height);
00162   }
00163 }
00164   
00165 /*inline */gint RGB (gint r, gint g, gint b) {
00166   return (r&0xff) << 16 | (g&0xff) << 8 | (b&0xff);
00167 }
00168 
00169 
00170   
00171 #define MAX_DEF 1280
00172   
00173 /* Sets the fields of the structure to default values. */
00174 static void
00175 plotwindow_init (PlotWindow *pw) {
00176     
00177   pw->all_points_bbox.minX = pw->all_points_bbox.minY = MAXINT;
00178   pw->all_points_bbox.maxX = pw->all_points_bbox.maxY = -MAXINT;
00179 
00180   /* Horizontal scrolling */
00181   /* FIXME : for a X/Y widget, do filterY_on = FALSE */
00182 
00183   /*FIXME*/
00184   pw->time_mode = FALSE;
00185 
00186   pw->ready_buffer = NULL;
00187   pw->data_dirty = FALSE;
00188   pw->scale_dirty = TRUE;
00189   pw->scroll_duration = 0;
00190   pw->prev_pt_exists = FALSE;
00191   pw->title = "";
00192   pw->clear_gc = NULL;
00193   pw->point_gc = NULL;
00194   pw->scroll_gc = NULL;
00195   pw->axis_gc = NULL;
00196   pw->box_gc = NULL;
00197   pw->small_font = NULL;
00198   pw->big_font = NULL;
00199   pw->ready_buffer = NULL;
00200   pw->array_sample.nb_sample = 0;
00201   pw->array_sample.current = 0;
00202   pw->array_sample.first = 0;
00203   pw->array_sample.samples = NULL;
00204   pw->array_sample.max_nb_sample = MAX_SAMPLE_NUMBER;
00205   pw->points = NULL;
00206   gtk_widget_set_usize(GTK_WIDGET(pw),WIDGET_INIT_SIZE_X,WIDGET_INIT_SIZE_Y);
00207 }
00208   
00209 
00210 /* Creates and returns the new object */
00211 GtkWidget *
00212 plotwindow_new () {
00213   return GTK_WIDGET(gtk_type_new(plotwindow_get_type()));
00214 }
00215 
00216 /* Creates an X window for the widget if it has one */
00217 static void
00218 plotwindow_realize (GtkWidget *widget) {
00219   GdkWindowAttr attributes;
00220   PlotWindow *pw;
00221   gint attributes_mask;
00222 
00223   g_return_if_fail (widget != NULL);
00224   g_return_if_fail (IS_PLOTWINDOW (widget));
00225   
00226   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
00227 
00228   attributes.x = widget->allocation.x;
00229   attributes.y = widget->allocation.y;
00230   attributes.width = widget->allocation.width;
00231   attributes.height = widget->allocation.height;
00232   attributes.wclass = GDK_INPUT_OUTPUT;
00233   attributes.window_type = GDK_WINDOW_CHILD;
00234   attributes.event_mask = gtk_widget_get_events (widget) | 
00235     GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
00236     GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
00237     GDK_POINTER_MOTION_HINT_MASK;
00238   attributes.visual = gtk_widget_get_visual (widget);
00239   attributes.colormap = gtk_widget_get_colormap (widget);
00240     
00241   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
00242   widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
00243   widget->style = gtk_style_attach (widget->style, widget->window);
00244     
00245   gdk_window_set_user_data (widget->window, widget);
00246   gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
00247 
00248   pw = PLOTWINDOW(widget);
00249 }
00250   
00251 /* Makes sure the widget is actually drawn on the screen (mapped) */
00252 static void
00253 plotwindow_map () {
00254 }
00255 /* Calls the drawing functions to draw the widget on the screen */
00256 static void
00257 plotwindow_draw () {
00258 }
00259  
00260   
00261 gint paint_data (void *arg) 
00262 {
00263   PlotWindow *pw = (PlotWindow *)arg;
00264   /* If nothing was read, return */
00265   /*if (!pw->data_dirty) return TRUE;*/
00266   gtk_widget_draw (GTK_WIDGET(pw), NULL);
00267   /*pw->data_dirty = FALSE;*/
00268   return TRUE;
00269 }
00270 
00271 
00272 
00273 
00277 #define array_sample_index(p_array, i) ((p_array)->samples[(i + (p_array)->first) % (p_array)->nb_sample ])
00278 
00279 
00283 static void array_sample_add_sample(array_sample_t* array, DoublePoint* pt)
00284 {
00285   (array)->samples[(array)->current] = *pt;
00286   (array)->current = ((array)->current + 1 ) % (array)->max_nb_sample;
00287     
00288   if((array)->nb_sample != (array)->max_nb_sample)
00289     {
00290       (array)->nb_sample++;      
00291       (array)->first = 0;
00292     }
00293   else
00294     {
00295       (array)->first = (array)->current;
00296     }
00297 }
00298 
00302 static void calc_mapping(PlotWindow* pw)
00303 {
00304   pw->mapping.x_len = (pw->widget.allocation.width-MARGIN);
00305   pw->mapping.y_len = -(pw->widget.allocation.height-MARGIN);
00306   if ( (pw->all_points_bbox.maxX-pw->all_points_bbox.minX) != 0 )
00307     pw->mapping.x_scale = pw->mapping.x_len / (pw->all_points_bbox.maxX-pw->all_points_bbox.minX);
00308   else
00309     pw->mapping.x_scale = 1;
00310   if ( (pw->all_points_bbox.maxY-pw->all_points_bbox.minY) != 0 )
00311     pw->mapping.y_scale = pw->mapping.y_len / (pw->all_points_bbox.maxY-pw->all_points_bbox.minY);
00312   else
00313     pw->mapping.y_scale = 1;
00314   pw->mapping.x_bias = -(pw->all_points_bbox.minX*pw->mapping.x_scale)+(double)X_LEFT_IN(pw);
00315   pw->mapping.y_bias = -(pw->all_points_bbox.maxY*pw->mapping.y_scale)+(double)Y_TOP_IN(pw);
00316   pw->mapping.x_scroll_len = 
00317     pw->mapping.x_len * ( pw->scroll_duration / (pw->all_points_bbox.maxX-pw->all_points_bbox.minX ) ) + .5f;
00318 }
00319 
00323 static void add_point_to_pixel(PlotWindow* pw, DoublePoint* pt)
00324 {    
00325   /* FIXME : mechante optimisation a faire */
00326   int add_pixel = FALSE;
00327   PixelPoint pix;
00328   PixelPoint prev_pix;
00329 
00330   /* OPTIMIZE (seed end of file if optimisation needed) */
00331   add_pixel = TRUE;
00332 
00333   /* Now, must we add a pixel ? */
00334   if(add_pixel && pw->prev_pt_exists)
00335     {
00336       pix.x =      COORD_SAMP_TO_PIX_X(pw, pt->x);
00337       pix.y =      COORD_SAMP_TO_PIX_Y(pw, pt->y);
00338       prev_pix.x = COORD_SAMP_TO_PIX_X(pw, pw->prev_pt.x);
00339       prev_pix.y = COORD_SAMP_TO_PIX_Y(pw, pw->prev_pt.y);
00340       pw->data_dirty = TRUE;
00341 
00342       if( !IS_SAME_PIXEL(pix, prev_pix) )
00343         gdk_draw_line (pw->ready_buffer, pw->point_gc,
00344                        prev_pix.x, prev_pix.y,
00345                        pix.x, pix.y);
00346     }        
00347 
00348   pw->prev_pt = *pt;
00349   pw->prev_pt_exists = TRUE;
00350 }
00351   
00352 
00353 void time_mode_scroll(PlotWindow* pw)
00354 {
00355   gint width, height, xsrc, xdest, y;
00356 
00357   /* First scroll the bbox */
00358   pw->all_points_bbox.maxX += pw->scroll_duration;
00359   pw->all_points_bbox.minX += pw->scroll_duration;
00360 
00361   /* Update mapping with new bbox */
00362   calc_mapping(pw);
00363 
00364   /*Scroll*/
00365   width = pw->mapping.x_len - pw->mapping.x_scroll_len + 1;
00366   height = -pw->mapping.y_len + 1 ;
00367   xdest = X_LEFT_IN(pw);
00368   xsrc = xdest + pw->mapping.x_scroll_len;
00369   y = Y_TOP_IN(pw);
00370 
00371   /* scroll plots */
00372   gdk_draw_pixmap (pw->ready_buffer, pw->scroll_gc, pw->ready_buffer,
00373                    xsrc, y,
00374                    xdest, y,
00375                    width, height);
00376 
00377   /* Erase old part of plots */
00378   gdk_draw_rectangle(pw->ready_buffer, pw->clear_gc, TRUE,
00379                      xdest + width, y,
00380                      xsrc - xdest,  height);
00381 
00382   /* scroll axis 
00383   gdk_draw_pixmap (pw->ready_buffer, pw->scroll_gc, pw->ready_buffer,
00384                    xsrc, y+height+1,
00385                    xdest, y+height+1, 
00386                    width+X_RIGHT_MARGIN, MARGIN/2);
00387   
00388   /* Erase old part of axis 
00389   gdk_draw_rectangle(pw->ready_buffer, pw->scroll_gc, TRUE,
00390                      xdest+width+X_RIGHT_MARGIN-1, y+height+1,
00391                      xsrc-xdest, MARGIN/2);
00392 
00393 
00394                      /* Avoid truncadted figures on the left axis */
00395   gdk_draw_rectangle(pw->ready_buffer, pw->scroll_gc, TRUE,
00396                      X_RIGHT_MARGIN, y+height+1,
00397                      pw->widget.allocation.width-X_RIGHT_MARGIN, MARGIN/2);
00398 
00399   draw_grids(pw, pw->ready_buffer, 1);
00400 
00401 }
00402   
00403 
00408 void add_point(PlotWindow* pw,DoublePoint* pt)
00409 {
00410   array_sample_add_sample(&pw->array_sample, pt);
00411 
00412   /* If the scale is already dirty no need to work more,
00413      we will recompute everything at next display refresh */
00414   if( ! pw->scale_dirty ) 
00415     { 
00416       /* Check to see if the new point stay in the grid */
00417       if(pt->y <= pw->all_points_bbox.maxY && 
00418          pt->y >= pw->all_points_bbox.minY)
00419         {
00420           if (pt->x <= pw->all_points_bbox.maxX && 
00421               pt->x >= pw->all_points_bbox.minX)
00422             {
00423               /* yes. We add the point */
00424               add_point_to_pixel(pw, pt);
00425             }
00426           else
00427             {
00428               if(! pw->time_mode)
00429                 {
00430                   /* We must rescal everything */
00431                   pw->scale_dirty = TRUE;
00432                 }
00433               else
00434                 {
00435                   /* time mode. Scroll everything and plot*/
00436                   time_mode_scroll(pw);
00437                   add_point_to_pixel(pw, pt);               
00438                 }
00439             }
00440         }
00441       else
00442         {
00443           /* We must rescal everything */
00444           pw->scale_dirty = TRUE;
00445         }
00446     }       
00447 }
00448 
00449 
00450 
00454 void
00455 set_title(PlotWindow *pw, const gchar* title)
00456 {
00457   pw->title = title;
00458 }
00459   
00460 static void create_all_gc(PlotWindow *pw)
00461 {
00462   GdkColor color;GdkColormap *colormap;
00463 
00464   /* Create buffer pixmap and gc*/
00465   if(pw->ready_buffer)
00466     {
00467       gdk_pixmap_unref(pw->ready_buffer);
00468     }
00469   pw->ready_buffer = gdk_pixmap_new(pw->widget.window, pw->widget.allocation.width, pw->widget.allocation.height, -1);
00470 
00471   if( pw->time_mode)
00472     {
00473       if(pw->scroll_gc) gdk_gc_unref(pw->scroll_gc);
00474       pw->scroll_gc = gdk_gc_new(pw->ready_buffer);
00475     }
00476 
00477   /* Create clear gc to erase the drawings */
00478   if(pw->clear_gc)
00479     {
00480       gdk_gc_unref(pw->clear_gc);
00481     }
00482   pw->clear_gc = gdk_gc_new(pw->ready_buffer);
00483   gdk_color_parse("#000000", &color);
00484   colormap = gtk_widget_get_colormap(&pw->widget);
00485   gdk_colormap_alloc_color(colormap, &color, FALSE, TRUE);
00486   gdk_gc_set_foreground(pw->clear_gc, &color);
00487         
00488   if(pw->buffer_gc)
00489     {
00490       gdk_gc_unref(pw->buffer_gc);    
00491     }
00492   pw->buffer_gc = gdk_gc_new(pw->widget.window);
00493 
00494   /* Create point gc */
00495   if(pw->point_gc)
00496     {
00497       gdk_gc_unref(pw->point_gc);    
00498     }
00499   pw->point_gc = gdk_gc_new(pw->ready_buffer);
00500   gdk_color_parse("#FFFF00", &color);
00501   colormap = gtk_widget_get_colormap(&pw->widget);
00502   gdk_colormap_alloc_color(colormap, &color, FALSE, TRUE);
00503   gdk_gc_set_foreground(pw->point_gc, &color);
00504 
00505   /* Create point gc */
00506   if(pw->axis_gc)
00507     {
00508       gdk_gc_unref(pw->axis_gc);    
00509     }
00510   pw->axis_gc = gdk_gc_new(pw->ready_buffer);
00511   gdk_color_parse("#888888", &color);
00512   colormap = gtk_widget_get_colormap(&pw->widget);
00513   gdk_colormap_alloc_color(colormap, &color, FALSE, TRUE);
00514   gdk_gc_set_foreground(pw->axis_gc, &color);
00515 
00516   /* Create box gc */
00517   if(pw->box_gc)
00518     {
00519       gdk_gc_unref(pw->box_gc);    
00520     }
00521   pw->box_gc = gdk_gc_new(pw->ready_buffer);
00522   gdk_color_parse("#FFFFFF", &color);
00523   colormap = gtk_widget_get_colormap(&pw->widget);
00524   gdk_colormap_alloc_color(colormap, &color, FALSE, TRUE);
00525   gdk_gc_set_foreground(pw->box_gc, &color);
00526 
00527   if (!pw->big_font)
00528     {
00529       pw->big_font = gdk_font_load("-misc-fixed-bold-r-normal-*-*-*-*-*-*-*-*-*");
00530       if (!pw->big_font)
00531         {
00532           pw->big_font = gdk_font_load("-misc-fixed-*-*-*-*-*-*-*-*-*-*-*-*");
00533         }
00534     }
00535   
00536   if (!pw->small_font)
00537     {
00538       pw->small_font = gdk_font_load("-misc-fixed-medium-r-semicondensed-*-*-*-*-*-*-*-*-*"); /*80 a slot 6*/
00539       if (!pw->small_font)
00540         {
00541           pw->small_font = gdk_font_load("-misc-fixed-*-*-*-*-*-*-*-*-*-*-*-*");
00542         }
00543     }
00544 
00545 }
00546 
00547 static void calc_scale(PlotWindow *pw)
00548 {
00549   int n;
00550   DoublePoint* p;
00551         
00552   for (n=0; n < pw->array_sample.nb_sample; n++)
00553     {
00554       p = &array_sample_index(&pw->array_sample, n);
00555       if (n == 0) {
00556         pw->all_points_bbox.maxX = p->x;
00557         pw->all_points_bbox.minX = p->x;
00558         pw->all_points_bbox.maxY = p->y;
00559         pw->all_points_bbox.minY = p->y;
00560       }
00561       
00562       if (p->x > pw->all_points_bbox.maxX) pw->all_points_bbox.maxX  = p->x;
00563       else if (p->x < pw->all_points_bbox.minX) pw->all_points_bbox.minX = p->x;
00564       if (p->y > pw->all_points_bbox.maxY) pw->all_points_bbox.maxY = p->y;
00565       else if (p->y < pw->all_points_bbox.minY) pw->all_points_bbox.minY = p->y;        
00566     }
00567 
00568   /* avoid 'always-autoscaling-phenomena' */
00569   {   
00570     double secur_y = (pw->all_points_bbox.maxY - pw->all_points_bbox.minY) * AUTOSCALE_RATIO;
00571     pw->all_points_bbox.maxY += secur_y;
00572     pw->all_points_bbox.minY -= secur_y;
00573     if( ! pw->time_mode )
00574       { 
00575         double secur_x = (pw->all_points_bbox.maxX - pw->all_points_bbox.minX) * AUTOSCALE_RATIO;
00576         pw->all_points_bbox.maxX += secur_x;
00577         pw->all_points_bbox.minX -= secur_x;
00578       }
00579     else
00580       {
00581         pw->all_points_bbox.maxX = pw->all_points_bbox.minX + pw->duration_sec;
00582       }
00583   }
00584     
00585   /* ---------------------------- */
00586   /* Update mapping with new bbox */
00587   /* ---------------------------- */
00588   calc_mapping(pw);
00589 
00590   /* ---------------------------- */
00591   /* Update some flags            */
00592   /* ---------------------------- */
00593   pw->scale_dirty = FALSE;
00594   /*pw->prev_pt_exists = FALSE;*/
00595 
00596   /* ---------------------------- */
00597   /* Create all GC                */
00598   /* ---------------------------- */
00599   create_all_gc(pw);
00600 }
00601 
00602 
00603 #define BUFFER_SIZE 1024
00604 #define DESCRIPTOR 0
00605 
00606 /* It makes the necessary calls to the drawing functions to draw the exposed portion on the screen. */
00607 static gint
00608 plotwindow_expose (GtkWidget      *widget,
00609                    GdkEventExpose *event)  {
00610 
00611   PlotWindow *pw;
00612   int x,y;
00613   void *point;
00614   GdkColor color = { 0, 0x12, 0x34, 0x56 };
00615   struct timeval begin;
00616   struct timeval end;
00617 
00618   g_return_val_if_fail (widget != NULL, FALSE);
00619   g_return_val_if_fail (IS_PLOTWINDOW (widget), FALSE);
00620   g_return_val_if_fail (event != NULL, FALSE);
00621   
00622   pw = PLOTWINDOW(widget);
00623             
00624   render_now(pw);
00625   if(pw->ready_buffer)
00626     {
00627       gdk_draw_pixmap (pw->widget.window,
00628                        pw->buffer_gc,
00629                        pw->ready_buffer,
00630                        0,0,
00631                        0,0,
00632                        pw->widget.allocation.width,
00633                        pw->widget.allocation.height);
00634     }
00635 
00636   return FALSE;
00637 }
00638 
00639 
00640   
00641 static clear_widget(PlotWindow *pw, GdkDrawable *where)
00642 {
00643   gdk_draw_rectangle(where,
00644                      pw->clear_gc,
00645                      TRUE,
00646                      0, 0,
00647                      pw->widget.allocation.width, 
00648                      pw->widget.allocation.height 
00649                      );    
00650 }
00651 
00652 static void draw_all_points(PlotWindow *pw, GdkDrawable *where)
00653 {
00654   int i;
00655   int nb_pix;
00656   DoublePoint* pt;    
00657 
00658   for ( i=0, nb_pix = 0 ; i < pw->array_sample.nb_sample; i++)
00659     {
00660       pt = &array_sample_index(&pw->array_sample, i);
00661       pw->points[nb_pix].x = COORD_SAMP_TO_PIX_X(pw,pt->x);
00662       pw->points[nb_pix].y = COORD_SAMP_TO_PIX_Y(pw,pt->y);
00663 
00664       /* Filter identical pixels */
00665       if( (nb_pix == 0) ||
00666           !IS_SAME_PIXEL(pw->points[nb_pix], pw->points[nb_pix-1]) )
00667         {
00668           nb_pix++;
00669         }       
00670     }
00671 
00672   gdk_draw_lines(where, pw->point_gc, pw->points, nb_pix);
00673 
00674   /* We prepare the point by point drawing with the latest point */
00675   if( pw->array_sample.nb_sample > 0)
00676     {
00677       pw->prev_pt = array_sample_index(&pw->array_sample, pw->array_sample.nb_sample - 1);
00678       pw->prev_pt_exists = TRUE;
00679     }
00680 }
00681 
00682 static void render_now (PlotWindow *pw) {
00683   DoublePoint prev;
00684   int i,n;
00685 
00686   /* If scale must change, recompute it */
00687   if(pw->scale_dirty)
00688     {
00689       if( pw->array_sample.nb_sample >= 2)
00690         {
00691           /* calc scale */
00692           calc_scale(pw);       
00693 
00694           /* FIXME : pw->ready_buffer est initialisé dans calc_scale */
00695           clear_widget(pw, pw->ready_buffer);
00696           draw_grids(pw, pw->ready_buffer, 0);
00697           draw_all_points(pw, pw->ready_buffer);            
00698         }
00699     }    
00700   else if(pw->data_dirty)
00701     {
00702       /*printf("data\n");*/
00703     }
00704 }
00705 
00706 
00707 
00708 /*
00709  * Draw Grid
00710  */
00711 #define NB_GRIDS_MAX 10
00712 void draw_grids(PlotWindow *pw, GdkDrawable *where, int partial) {
00713   int title_height, char_size, px, py;
00714   double unit, step, x, y, nb_grids;
00715   char buffer[512];
00716   
00717   title_height = gdk_text_height(pw->big_font,pw->title, strlen(pw->title));
00718     
00719   /* X axis (outside of the drawing area) */
00720   gdk_draw_line(where,
00721                 pw->box_gc,
00722                 X_LEFT_OUT(pw),Y_LOW_OUT(pw),
00723                 X_RIGHT_OUT(pw),Y_LOW_OUT(pw));
00724 
00725   /* Y axis (outside of the drawing area) */
00726   gdk_draw_line(where,
00727                 pw->box_gc,
00728                 X_LEFT_OUT(pw),Y_TOP_OUT(pw),
00729                 X_LEFT_OUT(pw),Y_LOW_OUT(pw));
00730 
00731   /* X top limit (outside of the drawing area)*/
00732   gdk_draw_line(where,
00733                 pw->box_gc,
00734                 X_LEFT_OUT(pw),Y_TOP_OUT(pw),
00735                 X_RIGHT_OUT(pw),Y_TOP_OUT(pw));
00736 
00737   /* Y top limit (outside of the drawing area)*/
00738   gdk_draw_line(where,
00739                 pw->box_gc,
00740                 X_RIGHT_OUT(pw),Y_TOP_OUT(pw),
00741                 X_RIGHT_OUT(pw),Y_LOW_OUT(pw));
00742 
00743   /* X grids */
00744   sprintf(buffer, " %g ", (double)pw->all_points_bbox.maxX);
00745   char_size = gdk_text_width(pw->small_font,buffer, strlen(buffer));
00746   nb_grids = (double)(pw->widget.allocation.width/char_size) ; /*nb digits per unit */
00747   if (nb_grids>NB_GRIDS_MAX)    nb_grids = NB_GRIDS_MAX;
00748   if (nb_grids<1)       nb_grids = 1;
00749   step = (pw->all_points_bbox.maxX - pw->all_points_bbox.minX)/(nb_grids); /* compute the average step */
00750   unit = pow(10, floor(log10(step)));  /* round it to the next 10 power */
00751   step = ceil(step/unit)*unit;
00752   if (step==0)  step=1;
00753 
00754   for (x = (int)(pw->all_points_bbox.minX/step)*step; x<pw->all_points_bbox.maxX; x+= step)
00755   {
00756     if ( x>pw->all_points_bbox.minX )
00757       {
00758         px = COORD_SAMP_TO_PIX_X (pw, x);
00759         sprintf(buffer, "%g", (double)x);
00760         gdk_draw_string(where, pw->small_font, pw->point_gc,
00761                         px-(gdk_text_width(pw->small_font,buffer, strlen(buffer))/2.0), 
00762                         (pw->widget.allocation.height)- (gdk_text_height(pw->small_font,buffer, strlen(buffer))),
00763                         buffer);
00764         
00765         if (partial && (x < (pw->all_points_bbox.maxX-pw->scroll_duration)) )
00766           {
00767             /* do nothing, point is either outisde box or already traced  */
00768           }
00769         else 
00770           {
00771             gdk_draw_line(where, (x==0) ? pw->box_gc : pw->axis_gc, 
00772                           px, Y_LOW_IN(pw),
00773                           px, Y_TOP_IN(pw));
00774           } /* not partial */
00775       } /* inside box */
00776   } /* end for */
00777  
00778   /* Y grids  */
00779   char_size = gdk_text_height(pw->small_font,"9", 1);
00780   nb_grids = (pw->widget.allocation.height / char_size /5) ; /*2 digits per unit */
00781   if (nb_grids>NB_GRIDS_MAX)
00782     nb_grids = NB_GRIDS_MAX;
00783   step = (pw->all_points_bbox.maxY - pw->all_points_bbox.minY)/nb_grids; /* compute the average step */
00784   unit = pow(10, floor(log10(step)));  /* round it to the next 10 power */
00785   if (unit != 0)
00786     step = ceil((step)/unit)*unit;
00787   else 
00788     step = 1;
00789   if (step==0) step=1;
00790 
00791   px = COORD_SAMP_TO_PIX_X(pw, pw->all_points_bbox.maxX-pw->scroll_duration);
00792   for (y = (int)(pw->all_points_bbox.minY/step)*step; y<pw->all_points_bbox.maxY; y+= step)
00793   {
00794     if ( y>pw->all_points_bbox.minY )
00795       {
00796         py = COORD_SAMP_TO_PIX_Y (pw, y);
00797         sprintf(buffer, " %.3g ", y);
00798         gdk_draw_line(where, (y==0) ? pw->box_gc : pw->axis_gc,
00799                       partial ? px : X_LEFT_IN(pw), py,
00800                       X_RIGHT_IN(pw), py);
00801         if (!partial)
00802           gdk_draw_string(where, pw->small_font, pw->point_gc,
00803                           X_LEFT_IN(pw)-gdk_text_width(pw->small_font,buffer,strlen(buffer)), 
00804                           py + gdk_text_height(pw->small_font,buffer,strlen(buffer))/2, 
00805                           buffer);
00806       } /* inside box */
00807   } /* end for */
00808 
00809   /* Title */
00810   gdk_draw_string(where, pw->big_font, pw->point_gc,
00811                   pw->widget.allocation.width/2-(gdk_text_width(pw->big_font,pw->title, strlen(pw->title))/2), 
00812                   title_height*2, pw->title );
00813 }
00814 
00815 
00816 
00817 static void 
00818 plotwindow_size_request (GtkWidget      *widget,
00819                          GtkRequisition *requisition) {
00820   requisition->width = PLOTWINDOW_PREFERRED_WIDTH;
00821   requisition->height = PLOTWINDOW_PREFERRED_WIDTH;
00822 }
00823 
00824 
00825 void set_time_mode(PlotWindow* pw, double duration_sec, double frequency_hz)
00826 {
00827   pw->time_mode = TRUE;
00828   if (frequency_hz==0)  frequency_hz=1; /* not a real frequency, but allow to plot by item */
00829   pw->array_sample.max_nb_sample = duration_sec * frequency_hz;
00830   pw->array_sample.samples = (DoublePoint*)g_malloc0(pw->array_sample.max_nb_sample * sizeof(DoublePoint));
00831   pw->points = (GdkPoint*)g_malloc0(pw->array_sample.max_nb_sample * sizeof(GdkPoint));
00832   pw->duration_sec = duration_sec;
00833   pw->scroll_duration = pw->duration_sec * SCROLL_RATIO;
00834 }
00835 
00836 
00837 
00838 
00839 
00840 
00841 /* If need to optimize the add pixel function */
00842 #if 0
00843   /* At least one elements ? */
00844   if( latest_index >= 0 )
00845     {
00846       PixelPoint* pix_last = &g_array_index(pw->pixel, PixelPoint ,latest_index );
00847         
00848       if( pix_last->x != pix.x)
00849         {
00850           add_pixel = TRUE;
00851           x_pixel = TRUE; 
00852         }
00853       else                
00854         {
00855           if( pix_last->y != pix.y)
00856             {
00857               /* With no Y filter : same as X */
00858               if( ! pw->time_mode)
00859                 {
00860                   add_pixel = TRUE;
00861                 }
00862               else /* filter Y values */
00863                 {
00864                   /* At least two elements ? */
00865                   if( latest_index >= 1 ) 
00866                     {
00867                       /* Compare two latest elements of pixel array */
00868                       PixelPoint* pix_prev = &g_array_index(pw->pixel, PixelPoint ,latest_index - 1);
00869                       if( pix_last->x !=  pix_prev->x)
00870                         {
00871                           add_pixel = TRUE;
00872                         }
00873                       else
00874                         {
00875                           /* If the new pix is vertically between the two lastest pix,
00876                              we do nothing */
00877                           if( pix_last->y > pix_prev->y)
00878                             {
00879                               if( pix.y > pix_last->y ){ 
00880                                 pw->data_dirty = TRUE;
00881                                 pix_last->y = pix.y;
00882                               } 
00883                               else if( pix.y < pix_prev->y ){ 
00884                                 pw->data_dirty = TRUE;
00885                                 pix_prev->y = pix.y;
00886                               }
00887                             }
00888                           else if ( pix_last->y < pix_prev->y)
00889                             {
00890                               if( pix.y > pix_prev->y ){ 
00891                                 pw->data_dirty = TRUE;
00892                                 pix_prev->y = pix.y;
00893                               } 
00894                               else if( pix.y < pix_last->y ){ 
00895                                 pw->data_dirty = TRUE;
00896                                 pix_last->y = pix.y;
00897                               }                                 
00898                             }
00899                           else
00900                             {/* bug ! */
00901                               assert(0);
00902                             }
00903                         }                       
00904                     }
00905                   else
00906                     {
00907                       add_pixel = TRUE;
00908                     }                 
00909                 }                                   
00910             }                                               
00911         }
00912     }
00913   else
00914     {
00915       add_pixel = TRUE;
00916     }
00917 #endif
00918 
Framework Home Page.

Beware !! TSP wave is coming...