/* * gawlabel.c - X or Y label or grid functions * * include LICENSE */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include // #include #include #include #include #ifdef TRACE_MEM #include #endif /* *** \brief Allocates memory for a new GawLabels object. */ GawLabels *al_label_new( UserPrefs *up, int logAxis, int dir ) { GawLabels *lb; lb = app_new0(GawLabels, 1); al_label_construct( lb, up, logAxis, dir ); app_class_overload_destroy( (AppClass *) lb, al_label_destroy ); return lb; } /** \brief Constructor for the GawLabels object. */ void al_label_construct( GawLabels *lb, UserPrefs *up, int logAxis, int dir ) { app_class_construct( (AppClass *) lb ); al_label_set_logAxis(lb, logAxis ); lb->up = up; lb->xdir = dir; } /** \brief Destructor for the GawLabels object. */ void al_label_destroy(void *lb) { GawLabels *this = (GawLabels *) lb; if (lb == NULL) { return; } g_list_foreach(this->label_list, (GFunc) lbd_destroy, this); g_list_free(this->label_list); app_class_destroy( lb ); } int al_label_count_label(GawLabels *lb, int flag) { int i; int j; double val; double step ; int max_count = g_list_length( lb->label_list); int count = 0; LabelData *lbd; for ( i = 0 ; ; i++ ) { step = pow(10, lb->lb_Lstart + i ); /* 1, 2, 3 ... => 10, 100, 1000 */ val = 0.0; for (j = 0; j < 9 ; j++ ) { val += step; if ( val < lb->start_val ) { continue; } if ( val >= lb->end_val || count >= max_count ) { return count; } if ( (flag == 1 && j > 1 && (j % 2) == 0) || (flag == 0 && j > 0) ) { continue; } lbd = (LabelData *) g_list_nth_data ( lb->label_list, count++ ); lbd->lbval = val; msg_dbg( "Log %s, val %f, step %f, count %d", XDIR(lb), val, step, count); if ( flag == 0 ) { break; } } } return count; } void al_label_log_compute(GawLabels *lb, int max_labels) { if ( ! lb->logAble ) { return; } double diff; lb->lb_start = floor(lb->start_Lval); lb->lb_Lstart = lb->lb_start; if ( lb->lb_start != lb->start_Lval ){ lb->lb_start += 1.0; } diff = lb->end_Lval - lb->start_Lval ; if ( diff < 1.0 ) { lb->nlabels = al_label_count_label(lb, 2); } else if ( diff < 2.0 ) { lb->nlabels = al_label_count_label(lb, 1); } else { lb->nlabels = al_label_count_label(lb, 0); } msg_dbg("Log %s, [%.3f %.3f] [%.3f %.3f] start %.3f Lstart %.3f, nlabels (%d < %d)", XDIR(lb), lb->start_val, lb->end_val, lb->start_Lval, lb->end_Lval, lb->lb_start, lb->lb_Lstart, lb->nlabels, max_labels ); } void al_label_lin_compute(GawLabels *lb, int max_labels) { int i; double nstep; LabelData *lbd; nstep = (lb->end_val - lb->start_val) / (double) max_labels; lb->step = find_rounded(nstep, 0); lb->lb_start = find_rounded(lb->start_val, 0); i = (int) ( (lb->lb_start - lb->start_val) / lb->step ); if ( i > 0 ) { lb->lb_start = lb->lb_start - ( (double) i * lb->step); } if ( fabs(lb->lb_start) < lb->step ) { lb->lb_start = 0.0; } for ( i = 0 ; i < max_labels ; i++ ) { double val = lb->lb_start + ( (double) i * lb->step); // msg_dbg("Lin %s, [%d] val %f end val %", XDIR(lb), // i, val, lb->end_val ); lbd = (LabelData *) g_list_nth_data ( lb->label_list, i ); lbd->lbval = val; if ( val > lb->end_val ) { break; } } lb->nlabels = i; msg_dbg("Lin %s, [%.3f %.3f] start %.3f step %.3f, nlabels (%d < %d)", XDIR(lb), lb->start_val, lb->end_val, lb->lb_start, lb->step, lb->nlabels, max_labels ); } void al_label_compute(GawLabels *lb) { int max_labels; if ( ! lb->wh ){ return; } if ( lb->xdir ) { /* X label */ max_labels = lb->wh / lb->lbwidth; } else { /* Y label */ max_labels = lb->wh / ( lb->lbheight + ( lb->lbheight / 4)); } al_label_add_remove( lb, max_labels ); if ( lb->logAxis ){ al_label_log_compute(lb, max_labels); } else { al_label_lin_compute(lb, max_labels); } } void al_label_set_logAxis(GawLabels *lb, int logAxis ) { lb->logAxis = logAxis; } int al_label_get_logAxis(GawLabels *lb ) { return lb->logAxis; } int al_label_do_logAxis(GawLabels *lb ) { return (lb->logAble & lb->logAxis); } int al_label_get_logAble(GawLabels *lb ) { return lb->logAble; } void al_label_update_vals(GawLabels *lb, double start, double end ) { lb->start_val = start; lb->end_val = end; if ( lb->logAble ) { lb->start_Lval = log10(start); lb->end_Lval = log10(end); } } void al_label_update_min_max_vals(GawLabels *lb, double min, double max ) { lb->min_val = min; lb->max_val = max; if ( lb->min_val > 0.0 ) { lb->logAble = 1; lb->min_Lval = log10(lb->min_val); lb->max_Lval = log10(lb->max_val); } else { lb->logAble = 0; } } double al_label_get_label_val( GawLabels *lb, double i ) { double val = lb->lb_start + lb->step * i; if ( val < lb->start_val ) { val = lb->start_val; } if ( val > lb->end_val ) { val = lb->end_val; } return val; } void lbd_destroy( LabelData *lbd, gpointer data) { GawLabels *lb = (GawLabels *) data; GtkWidget *label; label = lbd->label; /* destroy the label as well because it has only 1 reference */ gtk_container_remove (GTK_CONTAINER(lb->label_layout), label); app_free(lbd); lb->label_list = g_list_remove (lb->label_list, lbd ); app_memcheck(); } /* * remove a gtklabel from the list */ void al_label_remove( GawLabels *lb ) { LabelData *lbd; int n; if ( ! lb->label_list ){ return ; } n = g_list_length( lb->label_list); lbd = (LabelData *) g_list_nth_data ( lb->label_list, n - 1 ); lbd_destroy( lbd, (gpointer) lb); } /* * add a gtklabel to the list */ void al_label_add( GawLabels *lb ) { GtkWidget *label; LabelData *lbd; label = gtk_label_new(" "); gtk_widget_show(label); lbd = app_new0( LabelData, 1 ); lbd->label = label; lb->label_list = g_list_append(lb->label_list, lbd); gtk_layout_put (GTK_LAYOUT(lb->label_layout), label, 1, 1); } void al_label_add_remove(GawLabels *lb, int nreq) { int i; int nexisting = g_list_length( lb->label_list); msg_dbg("%s, req nlabels %d existing %d", XDIR(lb), nreq, nexisting); if ( nreq == nexisting ) { return; } else if ( nreq < nexisting ) { for ( i = 0 ; i < nexisting - nreq ; i++ ){ al_label_remove(lb); } } else { for ( i = 0 ; i < nreq - nexisting ; i++ ){ al_label_add( lb ); } } } void al_label_get_pos(GawLabels *lb, double val, int i, int *xpos, int *ypos) { int x = 0; int y = 0; if ( lb->xdir ) { /* X label */ if ( al_label_do_logAxis(lb) ) { x = VAL2LX(lb, val, lb->wh); } else { x = VAL2X(lb, val, lb->wh); } if ( x >= lb->char_width ) { x -= lb->char_width; } } else { /* Y label */ if ( al_label_do_logAxis(lb) ) { y = VAL2LY(lb, val, lb->wh); } else { y = VAL2Y(lb, val, lb->wh); } if ( y >= lb->lbheight ) { y = y - lb->lbheight + 5; } else { y -= 3; } } *xpos = x; *ypos = y; } /* * update text labeling the waveform graphs X or Y axis */ void al_label_draw(GawLabels *lb) { int i; int x; int y; LabelData *lbd; int nlabels = g_list_length( lb->label_list); for ( i = 0 ; i < lb->nlabels ; i++ ){ lbd = (LabelData *) g_list_nth_data ( lb->label_list, i ); double val = lbd->lbval; al_label_get_pos(lb, val, i, &x, &y); msg_dbg("%s, [val %.3f] i %d x %d y %d", XDIR(lb), val, i, x, y); gtk_layout_move (GTK_LAYOUT(lb->label_layout), lbd->label, x, y); gtk_label_set_text(GTK_LABEL(lbd->label), val2str_lb(val, lb->up->scientific) ); gtk_widget_show(lbd->label); } for ( ; i < nlabels ; i++ ){ lbd = (LabelData *) g_list_nth_data ( lb->label_list, i ); gtk_widget_hide(lbd->label); } } /* * vertical lines, linear scale */ int al_label_draw_vlin_grid(GawLabels *lb, ArrayStruct *ary, int w, int h ) { guint i; int n = 2; for ( i = 0; i < lb->nlabels * n ; i++ ) { double val = al_label_get_label_val( lb, (double) i / (double) n ) ; if ( val >= lb->end_val ) { break; } GawSegment *segp = (GawSegment *) array_struct_next(ary); segp->x1 = segp->x2 = VAL2X(lb, val, w); // msg_dbg( "%s, val %f, x %d", XDIR(lb), val, segp->x1); segp->y1 = 0; segp->y2 = h - 1; } return array_struct_get_nelem(ary); } /* * horizontal lines, linear scale */ int al_label_draw_hlin_grid(GawLabels *lb, ArrayStruct *ary, int w, int h ) { guint i; int n = 2; for ( i = 0; i < lb->nlabels * n ; i++ ) { double val = al_label_get_label_val( lb, (double) i / (double) n ) ; if ( val >= lb->end_val ) { break; } GawSegment *segp = (GawSegment *) array_struct_next(ary); segp->y1 = segp->y2 = VAL2Y(lb, val, h); // msg_dbg( "%s, val %f, y %d", XDIR(lb), val, segp->y1); segp->x1 = 0; segp->x2 = w - 1; } return array_struct_get_nelem(ary); } /* * vertical lines, log scale */ int al_label_draw_vlog_grid(GawLabels *lb, ArrayStruct *ary, int w, int h ) { int i; int j; double val; double step ; for ( i = 0 ; ; i++ ) { step = pow(10, lb->lb_Lstart + i ); /* 1, 2, 3 ... => 10, 100, 1000 */ val = 0.0; for (j = 0; j < 9 ; j++ ) { val += step; if ( val < lb->start_val ) { continue; } if ( val >= lb->end_val ) { return array_struct_get_nelem(ary) ; } GawSegment *segp = (GawSegment *) array_struct_next(ary); segp->x1 = segp->x2 = VAL2LX(lb, val, w); // msg_dbg( "Log %s, val %f, step %f, x %d", XDIR(lb), val, step, segp->x1); segp->y1 = 0; segp->y2 = h - 1; } } return array_struct_get_nelem(ary) ; } /* * horizontal lines, log scale */ int al_label_draw_hlog_grid(GawLabels *lb, ArrayStruct *ary, int w, int h ) { int i; int j; double val; double step; for ( i = 0 ; ; i++ ) { step = pow(10, lb->lb_Lstart + i); /* 1, 2, 3 ... => 10, 100, 1000 */ val = 0.0; for (j = 0; j < 9 ; j++ ) { val += step; if ( val < lb->start_val ) { continue; } if ( val >= lb->end_val ) { return array_struct_get_nelem(ary); } GawSegment *segp = (GawSegment *) array_struct_next(ary); segp->y1 = segp->y2 = VAL2LY(lb, val, h); // msg_dbg( "%s, val %f, step %f, y %d", XDIR(lb), val, step, segp->y1); segp->x1 = 0; segp->x2 = w - 1; } } return array_struct_get_nelem(ary); } /******************************************************/ /* * Linear scale * data |min |val max| * view |start |val end| * pixel |0 |x width| * * x_pixel = width * (val - start) / (end - start) * * What is a log scale ? * A logarithmic scale is a scale of measurement that uses the logarithm * of a physical quantity instead of the quantity itself. * a linear space |0 |x width| * mapped to |Lstart |Lval Lend| * Lstart = log10 (Fstart) : 10 hz -> 1 * Lend = log10 (Fend) : 100000 hz -> 5 * Lval = log10 (Fval) : 1000 hz -> 3 */ /* * convert a variable value to a normalized value 0.0 ... 1.0 */ double al_label_val2n(GawLabels *lb, double val) { if ( lb->end_val == lb->start_val ) { return 0.0; } return (val - lb->start_val) / (lb->end_val - lb->start_val); } double al_label_val2Ln(GawLabels *lb, double val) { if ( lb->end_Lval == lb->start_Lval ) { return 0.0; } return (log10(val) - lb->start_Lval) / (lb->end_Lval - lb->start_Lval); } int al_label_val2xy(GawLabels *lb, double val, int d) { return d * al_label_val2n(lb, val); } int al_label_val2Lxy(GawLabels *lb, double val, int d) { return d * al_label_val2Ln(lb, val); } /* * convert pixmap X or Y coordinate to user dependent-variable value */ double al_label_xy2val(GawLabels *lb, int v, int d) { double frac = (double) v / (double) d; return lb->start_val + (frac * (lb->end_val - lb->start_val)); } double al_label_xy2Lval(GawLabels *lb, int v, int d) { double frac = (double) v / (double) d; double a = lb->start_Lval + (frac * ( lb->end_Lval - lb->start_Lval)) ; return pow(10, a); } /* * convert double yval to y coordinate */ int al_label_val2y(GawLabels *lby, double yval) { if ( al_label_do_logAxis(lby) ) { return VAL2LY(lby, yval, lby->h); } else { return VAL2Y(lby, yval, lby->h); } } /* * convert y coordinate to double yval */ double al_label_y2val(GawLabels *lby, int y) { if ( al_label_do_logAxis(lby) ) { return Y2LVAL(lby, y, lby->h); } else { return Y2VAL(lby, y, lby->h); } } /* * convert double xval to x coordinate */ int al_label_val2x(GawLabels *lbx, double xval) { if ( al_label_do_logAxis(lbx) ) { return VAL2LX(lbx, xval, lbx->w); } else { return VAL2X(lbx, xval, lbx->w); } } /* * convert x coordinate to double xval */ double al_label_x2val(GawLabels *lbx, int x) { if ( al_label_do_logAxis(lbx) ) { return X2LVAL(lbx, x, lbx->w); } else { return X2VAL(lbx, x, lbx->w); } }