[xiph-commits] r11973 - trunk/sushivision
xiphmont at svn.xiph.org
xiphmont at svn.xiph.org
Tue Oct 31 14:37:27 PST 2006
Author: xiphmont
Date: 2006-10-31 14:37:23 -0800 (Tue, 31 Oct 2006)
New Revision: 11973
Modified:
trunk/sushivision/internal.h
trunk/sushivision/panel-2d.c
trunk/sushivision/panel-2d.h
trunk/sushivision/plot.c
trunk/sushivision/plot.h
trunk/sushivision/scale.c
trunk/sushivision/scale.h
Log:
Add some rescaling/resizing nicities (interpolated display until rerender)
Modified: trunk/sushivision/internal.h
===================================================================
--- trunk/sushivision/internal.h 2006-10-31 21:08:19 UTC (rev 11972)
+++ trunk/sushivision/internal.h 2006-10-31 22:37:23 UTC (rev 11973)
@@ -37,7 +37,3 @@
extern int _sushiv_panel_cooperative_compute(sushiv_panel_t *p);
extern sig_atomic_t _sushiv_exiting;
-
-#define SUSHIV_DIM_MASK 0x003
-#define SUSHIV_X_DIM 0x001
-#define SUSHIV_Y_DIM 0x002
Modified: trunk/sushivision/panel-2d.c
===================================================================
--- trunk/sushivision/panel-2d.c 2006-10-31 21:08:19 UTC (rev 11972)
+++ trunk/sushivision/panel-2d.c 2006-10-31 22:37:23 UTC (rev 11973)
@@ -52,9 +52,7 @@
}
}
-/* called from idle handler only, and as such, we can be sure we're
- locked and uninterruptable */
-void _sushiv_panel2d_map_redraw(sushiv_panel_t *p){
+static void _sushiv_panel2d_remap(sushiv_panel_t *p){
sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
Plot *plot = PLOT(p2->graph);
@@ -90,10 +88,22 @@
/* store result in panel */
memcpy(plot->datarect+y*w,render,w*sizeof(*render));
}
- plot_expose_request(plot);
}
}
+void _sushiv_panel2d_map_redraw(sushiv_panel_t *p){
+ sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
+ Plot *plot = PLOT(p2->graph);
+
+ gdk_threads_enter (); // misuse me as a global mutex
+
+ _sushiv_panel2d_remap(p);
+ if(plot)
+ plot_expose_request(plot);
+
+ gdk_threads_leave (); // misuse me as a global mutex
+}
+
static void mapchange_callback_2d(GtkWidget *w,gpointer in){
sushiv_objective_t **optr = (sushiv_objective_t **)in;
sushiv_objective_t *o = *optr;
@@ -139,28 +149,34 @@
// make the y insensitive
if(p2->dim_yb[i])
gtk_widget_set_sensitive(p2->dim_yb[i],FALSE);
- // set the dim x flag
- p->dimension_list[i]->flags |= SUSHIV_X_DIM;
+ // set the x dim flag
+ p2->x_d = p->dimension_list[i];
+ // set panel x scale to this dim
+ p2->x = scalespace_linear(p2->x_d->bracket[0],
+ p2->x_d->bracket[1],
+ p2->data_w,
+ PLOT(p2->graph)->scalespacing);
}else{
// if there is a y, make it sensitive
if(p2->dim_yb[i])
gtk_widget_set_sensitive(p2->dim_yb[i],TRUE);
- // unset dim x flag
- p->dimension_list[i]->flags &= ~SUSHIV_X_DIM;
}
if(p2->dim_yb[i] &&
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2->dim_yb[i]))){
// make the x insensitive
if(p2->dim_xb[i])
gtk_widget_set_sensitive(p2->dim_xb[i],FALSE);
- // set the dim y flag
- p->dimension_list[i]->flags |= SUSHIV_Y_DIM;
+ // set the y dim
+ p2->y_d = p->dimension_list[i];
+ // set panel y scale to this dim
+ p2->y = scalespace_linear(p2->y_d->bracket[0],
+ p2->y_d->bracket[1],
+ p2->data_h,
+ PLOT(p2->graph)->scalespacing);
}else{
// if there is a x, make it sensitive
if(p2->dim_xb[i])
gtk_widget_set_sensitive(p2->dim_xb[i],TRUE);
- // unset dim y flag
- p->dimension_list[i]->flags &= ~SUSHIV_Y_DIM;
}
if((p2->dim_xb[i] &&
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2->dim_xb[i]))) ||
@@ -205,7 +221,7 @@
for(j=0;j<w;j++){
/* compute value for this objective for this pixel */
- dim_vals[x_d] = (x_max-x_min) * inv_w * j;
+ dim_vals[x_d] = (x_max-x_min) * inv_w * j + x_min;
work[j] = o->callback(dim_vals);
}
@@ -260,38 +276,214 @@
return y<<1;
}
+// assumes data is locked
+static void fast_scale_x(double *data,
+ int w,
+ int h,
+ scalespace new,
+ scalespace old){
+ int x,y;
+ double work[w];
+ int mapbase[w];
+ double mapdel[w];
+
+ double old_w = old.pixels;
+ double new_w = new.pixels;
+ double old_lo = scalespace_value(&old,0);
+ double old_hi = scalespace_value(&old,old_w);
+ double new_lo = scalespace_value(&new,0);
+ double new_hi = scalespace_value(&new,new_w);
+ double newscale = (new_hi-new_lo)/new_w;
+ double oldscale = old_w/(old_hi-old_lo);
+ for(x=0;x<w;x++){
+ double xval = x*newscale+new_lo;
+ double map = ((xval-old_lo)*oldscale);
+ mapbase[x]=(int)floor(map);
+ mapdel[x]=map-floor(map);
+ }
+
+ for(y=0;y<h;y++){
+ double *data_line = data+y*w;
+ for(x=0;x<w;x++){
+ if(mapbase[x]<0 || mapbase[x]>=(w-1)){
+ work[x]=NAN;
+ }else{
+ int base = mapbase[x];
+ double del = mapdel[x];
+ double A = data_line[base];
+ double B = data_line[base+1];
+ if(isnan(A) || isnan(B)) // damn you SIGFPE
+ work[x]=NAN;
+ else
+ work[x]= A - A*del + B*del;
+
+ }
+ }
+ memcpy(data_line,work,w*(sizeof(*work)));
+ }
+}
+
+static void fast_scale_y(double *data,
+ int w,
+ int h,
+ scalespace new,
+ scalespace old){
+ int x,y;
+ double work[w];
+ int mapbase[w];
+ double mapdel[w];
+
+ double old_h = old.pixels;
+ double new_h = new.pixels;
+ double old_lo = scalespace_value(&old,0);
+ double old_hi = scalespace_value(&old,old_h);
+ double new_lo = scalespace_value(&new,0);
+ double new_hi = scalespace_value(&new,new_h);
+ double newscale = (new_hi-new_lo)/new_h;
+ double oldscale = old_h/(old_hi-old_lo);
+
+ for(y=0;y<h;y++){
+ double yval = y*newscale+new_lo;
+ double map = ((yval-old_lo)*oldscale);
+ mapbase[y]=(int)floor(map);
+ mapdel[y]=map-floor(map);
+ }
+
+ for(x=0;x<w;x++){
+ double *data_column = data+x;
+ int stride = w;
+ for(y=0;y<h;y++){
+ if(mapbase[y]<0 || mapbase[y]>=(h-1)){
+ work[y]=NAN;
+ }else{
+ int base = mapbase[y]*stride;
+ double del = mapdel[y];
+ double A = data_column[base];
+ double B = data_column[base+stride];
+
+ if(isnan(A) || isnan(B)) // damn you SIGFPE
+ work[y]=NAN;
+ else
+ work[y]= A - A*del + B*del;
+
+ }
+ }
+ for(y=0;y<h;y++){
+ *data_column = work[y];
+ data_column+=stride;
+ }
+ }
+}
+
+static void fast_scale(double *newdata,
+ scalespace xnew,
+ scalespace ynew,
+ double *olddata,
+ scalespace xold,
+ scalespace yold){
+ int y;
+
+ int new_w = xnew.pixels;
+ int new_h = ynew.pixels;
+ int old_w = xold.pixels;
+ int old_h = yold.pixels;
+
+ if(new_w > old_w){
+ if(new_h > old_h){
+ // copy image to new, scale there
+ for(y=0;y<old_h;y++){
+ double *new_line = newdata+y*new_w;
+ double *old_line = olddata+y*old_w;
+ memcpy(new_line,old_line,old_w*(sizeof*new_line));
+ }
+ fast_scale_x(newdata,new_w,new_h,xnew,xold);
+ fast_scale_y(newdata,new_w,new_h,ynew,yold);
+ }else{
+ // scale y in old pane, copy to new, scale x
+ fast_scale_y(olddata,old_w,old_h,ynew,yold);
+ for(y=0;y<new_h;y++){
+ double *new_line = newdata+y*new_w;
+ double *old_line = olddata+y*old_w;
+ memcpy(new_line,old_line,old_w*(sizeof*new_line));
+ }
+ fast_scale_x(newdata,new_w,new_h,xnew,xold);
+ }
+ }else{
+ if(new_h > old_h){
+ // scale x in old pane, o=copy to new, scale y
+ fast_scale_x(olddata,old_w,old_h,xnew,xold);
+ for(y=0;y<old_h;y++){
+ double *new_line = newdata+y*new_w;
+ double *old_line = olddata+y*old_w;
+ memcpy(new_line,old_line,new_w*(sizeof*new_line));
+ }
+ fast_scale_y(newdata,new_w,new_h,ynew,yold);
+ }else{
+ // scale in old pane, copy to new
+ // also the case where newdata == olddata and the size is unchanged
+ fast_scale_x(olddata,old_w,old_h,xnew,xold);
+ fast_scale_y(olddata,old_w,old_h,ynew,yold);
+ if(olddata != newdata){
+ for(y=0;y<new_h;y++){
+ double *new_line = newdata+y*new_w;
+ double *old_line = olddata+y*old_w;
+ memcpy(new_line,old_line,new_w*(sizeof*new_line));
+ }
+ }
+ }
+ }
+}
+
// call only from main gtk thread!
void _mark_recompute_2d(sushiv_panel_t *p){
sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
Plot *plot = PLOT(p2->graph);
+ int w = plot->w.allocation.width;
+ int h = plot->w.allocation.height;
if(plot && GTK_WIDGET_REALIZED(GTK_WIDGET(plot))){
if(p2->data_w != plot->w.allocation.width ||
p2->data_h != plot->w.allocation.height){
if(p2->data_rect){
+
+ // make new rects, do a fast/dirty scaling job from old to new
int i;
- for(i=0;i<p->objectives;i++)
+ for(i=0;i<p->objectives;i++){
+ double *new_rect = malloc(w * h* sizeof(**p2->data_rect));
+
+ fast_scale(new_rect,plot->x,plot->y,p2->data_rect[i],p2->x,p2->y);
+
free(p2->data_rect[i]);
- free(p2->data_rect);
- p2->data_rect = NULL;
+ p2->data_rect[i] = new_rect;
+ }
+ p2->x = plot->x;
+ p2->y = plot->y;
+ p2->data_w = w;
+ p2->data_h = h;
+ _sushiv_panel2d_map_redraw(p);
}
-
}
- p2->data_w = plot->w.allocation.width;
- p2->data_h = plot->w.allocation.height;
p2->serialno++;
p2->last_line = 0;
if(!p2->data_rect){
- int i;
+ int i,j;
// allocate it
+ p2->data_w = w;
+ p2->data_h = h;
+ p2->x = scalespace_linear(p2->x_d->bracket[0],
+ p2->x_d->bracket[1],
+ w,
+ PLOT(p2->graph)->scalespacing);
+ p2->y = scalespace_linear(p2->y_d->bracket[0],
+ p2->y_d->bracket[1],
+ h,
+ PLOT(p2->graph)->scalespacing);
p2->data_rect = calloc(p->objectives,sizeof(*p2->data_rect));
for(i=0;i<p->objectives;i++)
p2->data_rect[i] = malloc(p2->data_w * p2->data_h* sizeof(**p2->data_rect));
- }
- {
- int i,j;
+
// blank it
for(i=0;i<p->objectives;i++)
for(j=0;j<p2->data_w*p2->data_h;j++)
@@ -316,9 +508,9 @@
for(i=0;i<p->dimensions;i++){
sushiv_dimension_t *d = p->dimension_list[i];
sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
- if(d->flags & SUSHIV_X_DIM)
+ if(d == p2->x_d)
x = slider_get_value(p2->dim_scales[i],1);
- if(d->flags & SUSHIV_Y_DIM)
+ if(d == p2->y_d)
y = slider_get_value(p2->dim_scales[i],1);
}
@@ -333,7 +525,7 @@
sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
int dnum = dptr - p->dimension_list;
- int axisp = (d->flags & SUSHIV_DIM_MASK);
+ int axisp = (d == p2->x_d || d == p2->y_d);
d->val = slider_get_value(p2->dim_scales[dnum],1);
@@ -355,11 +547,21 @@
sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
int dnum = dptr - p->dimension_list;
- int axisp = (d->flags & SUSHIV_DIM_MASK);
+ int axisp = (d == p2->x_d || d == p2->y_d);
- d->bracket[0] = slider_get_value(p2->dim_scales[dnum],0);
- d->bracket[1] = slider_get_value(p2->dim_scales[dnum],2);
+ double lo = slider_get_value(p2->dim_scales[dnum],0);
+ double hi = slider_get_value(p2->dim_scales[dnum],2);
+ if(axisp){
+ double xy_p = d == p2->x_d;
+ scalespace s = scalespace_linear(lo,hi,(xy_p?p2->data_w:p2->data_h),
+ PLOT(p2->graph)->scalespacing);
+ xy_p?(p2->x=s):(p2->y=s);
+ }
+
+ d->bracket[0] = lo;
+ d->bracket[1] = hi;
+
// if the bracketing of an axis dimension changed, rerender
if(axisp)
_mark_recompute_2d(p);
@@ -368,10 +570,11 @@
static void dimchange_callback_2d(GtkWidget *button,gpointer in){
sushiv_panel_t *p = (sushiv_panel_t *)in;
-
- update_xy_availability(p);
- update_crosshairs(p);
- _mark_recompute_2d(p);
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))){
+ update_xy_availability(p);
+ update_crosshairs(p);
+ _mark_recompute_2d(p);
+ }
}
static void crosshairs_callback(void *in){
@@ -384,9 +587,9 @@
for(i=0;i<p->dimensions;i++){
sushiv_dimension_t *d = p->dimension_list[i];
sushiv_panel2d_t *p2 = (sushiv_panel2d_t *)p->internal;
- if(d->flags & SUSHIV_X_DIM)
+ if(d == p2->x_d)
slider_set_value(p2->dim_scales[i],1,x);
- if(d->flags & SUSHIV_Y_DIM)
+ if(d == p2->y_d)
slider_set_value(p2->dim_scales[i],1,y);
}
}
@@ -405,10 +608,15 @@
double invh;
int x_d=-1, y_d=-1;
int render_scale_flag = 0;
+ scalespace sx;
+ scalespace sy;
+
// lock during setup
gdk_threads_enter ();
w = p2->data_w;
h = p2->data_h;
+ sx = p2->x;
+ sy = p2->y;
if(p2->last_line>=h){
gdk_threads_leave ();
@@ -433,24 +641,41 @@
/* which dim is our x? Our y? */
for(i=0;i<d;i++){
sushiv_dimension_t *dim = p->dimension_list[i];
- if((dim->flags & SUSHIV_DIM_MASK) == SUSHIV_X_DIM ){
+ if(dim == p2->x_d){
+ x_min = scalespace_value(&sx,0);
+ x_max = scalespace_value(&sx,w);
x_d = dim->number;
- x_min = dim->bracket[0];
- x_max = dim->bracket[1];
break;
}
}
for(i=0;i<d;i++){
sushiv_dimension_t *dim = p->dimension_list[i];
- if((dim->flags & SUSHIV_DIM_MASK) == SUSHIV_Y_DIM){
+ if(dim == p2->y_d){
+ y_min = scalespace_value(&sy,0);
+ y_max = scalespace_value(&sy,h);
y_d = dim->number;
- y_min = dim->bracket[0];
- y_max = dim->bracket[1];
break;
}
}
+ // if the scale bound has changed, fast scale our background data to fill
+ // the pane while new, more precise data renders.
+ if(memcmp(&sx,&plot->x,sizeof(sx))){
+ for(i=0;i<p->objectives;i++)
+ fast_scale_x(p2->data_rect[i],w,h,
+ sx,plot->x);
+ plot->x = sx;
+ _sushiv_panel2d_remap(p);
+ }
+ if(memcmp(&sy,&plot->y,sizeof(sy))){
+ for(i=0;i<p->objectives;i++)
+ fast_scale_y(p2->data_rect[i],w,h,
+ sy,plot->y);
+ plot->y = sy;
+ _sushiv_panel2d_remap(p);
+ }
+
// Bulletproofing; shouldn't ever come up
if(x_d == y_d || x_d==-1 || y_d==-1){
gdk_threads_leave ();
@@ -475,19 +700,19 @@
int y;
if(plot->w.allocation.height != h)break;
if(last>=h)break;
+ if(serialno != p2->serialno)break;
p2->last_line++;
/* unlock for computation */
gdk_threads_leave ();
if(render_scale_flag){
- plot_set_x_scale(plot,x_min,x_max);
- plot_set_y_scale(plot,y_min,y_max);
+ plot_draw_scales(plot);
render_scale_flag = 0;
}
y = v_swizzle(last,h);
- dim_vals[y_d]= (y_max - y_min) * h * y;
+ dim_vals[y_d]= (y_max - y_min) / h * y + y_min;
/* compute line */
compute_one_line_2d(p, serialno, y, x_d, x_min, x_max, w, dim_vals, render);
Modified: trunk/sushivision/panel-2d.h
===================================================================
--- trunk/sushivision/panel-2d.h 2006-10-31 21:08:19 UTC (rev 11972)
+++ trunk/sushivision/panel-2d.h 2006-10-31 22:37:23 UTC (rev 11973)
@@ -30,6 +30,9 @@
int data_h;
int serialno;
double **data_rect;
+ scalespace x;
+ scalespace y;
+ int scales_init;
mapping *mappings;
Slider **range_scales;
@@ -40,6 +43,9 @@
GtkWidget **dim_xb;
GtkWidget **dim_yb;
+ sushiv_dimension_t *x_d;
+ sushiv_dimension_t *y_d;
+
int last_line;
int dirty_flag;
} sushiv_panel2d_t;
Modified: trunk/sushivision/plot.c
===================================================================
--- trunk/sushivision/plot.c 2006-10-31 21:08:19 UTC (rev 11972)
+++ trunk/sushivision/plot.c 2006-10-31 22:37:23 UTC (rev 11973)
@@ -136,9 +136,9 @@
cairo_destroy(c);
}
-// enter with lock; releases lock before exit
-static void draw_scales(Plot *p){
+void plot_draw_scales(Plot *p){
// render into a temporary surface; do it [potentially] outside the global Gtk lock.
+ gdk_threads_enter();
scalespace x = p->x;
scalespace y = p->y;
int w = GTK_WIDGET(p)->allocation.width;
@@ -323,8 +323,7 @@
widget->allocation = *allocation;
p->x = scalespace_linear(p->x.lo,p->x.hi,widget->allocation.width,p->scalespacing);
p->y = scalespace_linear(p->y.lo,p->y.hi,widget->allocation.height,p->scalespacing);
- gdk_threads_enter();
- draw_scales(p); // releases one lock level
+ plot_draw_scales(p);
if(p->recompute_callback)p->recompute_callback(p->app_data);
}
@@ -464,41 +463,31 @@
gdk_threads_leave();
}
-void plot_set_x_scale(Plot *p, double low, double high){
- gdk_threads_enter();
- GtkWidget *widget = GTK_WIDGET(p);
+void plot_set_x_scale(Plot *p, scalespace x){
scalespace temp = p->x;
- p->x = scalespace_linear(low,high,widget->allocation.width,p->scalespacing);
+ p->x = x;
p->selx = scalespace_pixel(&p->x,p->selx_val);
if(memcmp(&temp,&p->x,sizeof(temp)))
- draw_scales(p); // releases one lock level
- else
- gdk_threads_leave();
+ plot_draw_scales(p);
}
-void plot_set_y_scale(Plot *p, double low, double high){
- gdk_threads_enter();
+void plot_set_y_scale(Plot *p, scalespace y){
GtkWidget *widget = GTK_WIDGET(p);
scalespace temp = p->y;
- p->y = scalespace_linear(low,high,widget->allocation.height,p->scalespacing);
+ p->y = y;
p->sely = widget->allocation.height - scalespace_pixel(&p->y,p->sely_val);
-
if(memcmp(&temp,&p->y,sizeof(temp)))
- draw_scales(p); // releases one lock level
- else
- gdk_threads_leave();
+ plot_draw_scales(p);
}
void plot_set_x_name(Plot *p, char *name){
- gdk_threads_enter();
p->namex = name;
- draw_scales(p); // releases one lock level
+ plot_draw_scales(p); // releases one lock level
}
void plot_set_y_name(Plot *p, char *name){
- gdk_threads_enter();
p->namey = name;
- draw_scales(p); // releases one lock level
+ plot_draw_scales(p); // releases one lock level
}
u_int32_t *plot_get_background_line(Plot *p, int num){
Modified: trunk/sushivision/plot.h
===================================================================
--- trunk/sushivision/plot.h 2006-10-31 21:08:19 UTC (rev 11972)
+++ trunk/sushivision/plot.h 2006-10-31 22:37:23 UTC (rev 11973)
@@ -78,10 +78,11 @@
// the widget subclass half
void plot_expose_request(Plot *p);
void plot_expose_request_line(Plot *p, int num);
-void plot_set_x_scale(Plot *p, double low, double high);
-void plot_set_y_scale(Plot *p, double low, double high);
+void plot_set_x_scale(Plot *p, scalespace x);
+void plot_set_y_scale(Plot *p, scalespace y);
void plot_set_x_name(Plot *p, char *name);
void plot_set_y_name(Plot *p, char *name);
u_int32_t * plot_get_background_line(Plot *p, int num);
cairo_t *plot_get_background_cairo(Plot *p);
void plot_set_crosshairs(Plot *p, double x, double y);
+void plot_draw_scales(Plot *p);
Modified: trunk/sushivision/scale.c
===================================================================
--- trunk/sushivision/scale.c 2006-10-31 21:08:19 UTC (rev 11972)
+++ trunk/sushivision/scale.c 2006-10-31 22:37:23 UTC (rev 11973)
@@ -189,15 +189,19 @@
ret.lo = lowpoint;
ret.hi = highpoint;
+ ret.init = 1;
+ ret.pixels=pixels;
- while(pixels / range < max_spacing){
- place++;
- range *= .1;
+ if(range!=0.){
+ while(pixels / range < max_spacing){
+ place++;
+ range *= .1;
+ }
+ while(pixels / range > max_spacing){
+ place--;
+ range *= 10;
+ }
}
- while(pixels / range > max_spacing){
- place--;
- range *= 10;
- }
ret.decimal_exponent = place;
@@ -211,7 +215,10 @@
}
ret.step_val = step;
- ret.step_pixel = rint(pixels / range);
+ if(pixels == 0. || range == 0.)
+ ret.step_pixel = max_spacing;
+ else
+ ret.step_pixel = rint(pixels / range);
ret.m = pow(10,place);
first = (int)(lowpoint/ret.m)/step*step;
Modified: trunk/sushivision/scale.h
===================================================================
--- trunk/sushivision/scale.h 2006-10-31 21:08:19 UTC (rev 11972)
+++ trunk/sushivision/scale.h 2006-10-31 22:37:23 UTC (rev 11973)
@@ -31,6 +31,9 @@
int decimal_exponent;
double m;
+
+ int init;
+ int pixels;
} scalespace;
extern char **scale_generate_labels(unsigned scalevals, double *scaleval_list);
More information about the commits
mailing list