[xiph-commits] r12389 - trunk/sushivision
xiphmont at svn.xiph.org
xiphmont at svn.xiph.org
Mon Jan 29 05:58:16 PST 2007
Author: xiphmont
Date: 2007-01-29 05:58:10 -0800 (Mon, 29 Jan 2007)
New Revision: 12389
Modified:
trunk/sushivision/dimension.c
trunk/sushivision/dimension.h
trunk/sushivision/internal.h
trunk/sushivision/main.c
trunk/sushivision/mapping.c
trunk/sushivision/mapping.h
trunk/sushivision/panel-1d.c
trunk/sushivision/panel-1d.h
trunk/sushivision/panel-2d.c
trunk/sushivision/panel-2d.h
trunk/sushivision/panel.c
trunk/sushivision/plot.c
trunk/sushivision/plot.h
trunk/sushivision/scale.c
trunk/sushivision/scale.h
Log:
Huge round of changes to bring multiple plane types and continuous
dimensions to 2d panels. THEIS DOES NOT RUN YET. This is going into SVN
because it's a month of changes I don't feel like losing.
Modified: trunk/sushivision/dimension.c
===================================================================
--- trunk/sushivision/dimension.c 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/dimension.c 2007-01-29 13:58:10 UTC (rev 12389)
@@ -37,10 +37,8 @@
underlying data vector (often the same as the display), and the
third the same as the second, but over the absolute range [0 - n)
such that discrete dimensions will count from 0 in iteration. */
-/* if a dimension is linked, that is not handled here; the passed in x
- must be the linked x_v scale in which case it will be unaltered (it
- will be filtered through the discrete transformation a second time,
- which will not alter it) but x_i will bre generated fresh. */
+/* data_w ignored except in the continuous case, where it may be used
+ to generate linked or over/undersampled data scales. */
int _sushiv_dimension_scales(sushiv_dimension_t *d,
double lo,
double hi,
@@ -112,6 +110,25 @@
return data_w;
}
+int _sushiv_dimension_scales_from_panel(sushiv_dimension_t *d,
+ scalespace panel,
+ int data_w,
+ scalespace *data,
+ scalespace *iter){
+
+ return _sushiv_dimension_scales(d,
+ panel.lo,
+ panel.hi,
+ panel.pixels,
+ data_w,
+ panel.spacing,
+ panel.legend,
+ &panel, // dummy
+ data,
+ iter);
+}
+
+
static double discrete_quantize_val(sushiv_dimension_t *d, double val){
if(d->type == SUSHIV_DIM_DISCRETE){
val *= d->private->discrete_denominator;
Modified: trunk/sushivision/dimension.h
===================================================================
--- trunk/sushivision/dimension.h 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/dimension.h 2007-01-29 13:58:10 UTC (rev 12389)
@@ -60,6 +60,12 @@
scalespace *panel,
scalespace *data,
scalespace *iter);
+extern int _sushiv_dimension_scales_from_panel(sushiv_dimension_t *d,
+ scalespace panel,
+ int data_w,
+ scalespace *data,
+ scalespace *iter);
+
extern void _sushiv_dimension_set_value(sushiv_dim_widget_t *d, int thumb, double val);
extern void _sushiv_dim_widget_set_thumb_active(sushiv_dim_widget_t *dw, int thumb, int active);
extern sushiv_dim_widget_t *_sushiv_new_dimension_widget(sushiv_dimension_list_t *dl,
Modified: trunk/sushivision/internal.h
===================================================================
--- trunk/sushivision/internal.h 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/internal.h 2007-01-29 13:58:10 UTC (rev 12389)
@@ -19,6 +19,7 @@
*
*/
+#include <time.h>
#include <signal.h>
#include <gtk/gtk.h>
#include "sushivision.h"
@@ -54,11 +55,9 @@
int box_active;
} sushiv_panel_undo_t;
-typedef struct {
- void (**call)(double *, double *);
- double **fout; // [function number][outval_number*x]
- int storage_width;
-
+typedef union {
+ _sushiv_compute_cache_1d p1;
+ _sushiv_compute_cache_2d p2;
} _sushiv_compute_cache;
struct sushiv_panel_internal {
@@ -72,6 +71,8 @@
int maps_rendering;
int legend_rendering;
+ time_t last_map_throttle;
+
// function bundles
void (*realize)(sushiv_panel_t *p);
void (*map_redraw)(sushiv_panel_t *p);
@@ -99,8 +100,11 @@
int *objectives,
int *dimensions,
unsigned flags);
+extern void set_map_throttle_time(sushiv_panel_t *p);
+
extern void _sushiv_panel_dirty_map(sushiv_panel_t *p);
+extern void _sushiv_panel_dirty_map_throttled(sushiv_panel_t *p);
extern void _sushiv_panel_dirty_legend(sushiv_panel_t *p);
extern void _sushiv_wake_workers(void);
Modified: trunk/sushivision/main.c
===================================================================
--- trunk/sushivision/main.c 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/main.c 2007-01-29 13:58:10 UTC (rev 12389)
@@ -85,38 +85,6 @@
}
}
-void _maintain_cache(sushiv_panel_t *p, _sushiv_compute_cache *c, int w){
-
- /* toplevel initialization */
- if(c->fout == 0){
- int i,j;
-
- /* determine which functions are actually needed */
- c->call = calloc(p->sushi->functions,sizeof(*c->call));
- c->fout = calloc(p->sushi->functions,sizeof(*c->fout));
- for(i=0;i<p->objectives;i++){
- sushiv_objective_t *o = p->objective_list[i].o;
- for(j=0;j<o->outputs;j++)
- c->call[o->function_map[j]]=
- p->sushi->function_list[o->function_map[j]]->callback;
- }
- }
-
- /* once to begin, as well as anytime the data width changes */
- if(c->storage_width < w){
- int i;
- c->storage_width = w;
-
- for(i=0;i<p->sushi->functions;i++){
- if(c->call[i]){
- if(c->fout[i])free(c->fout[i]);
- c->fout[i] = malloc(w * p->sushi->function_list[i]->outputs *
- sizeof(**c->fout));
- }
- }
- }
-}
-
static void *worker_thread(void *dummy){
/* set up temporary working space for function rendering; this saves
continuously recreating it in the loop below */
@@ -156,6 +124,7 @@
gdk_threads_enter ();
p->private->maps_rendering = 0;
+ set_map_throttle_time(p);
}
// pending legend work?
Modified: trunk/sushivision/mapping.c
===================================================================
--- trunk/sushivision/mapping.c 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/mapping.c 2007-01-29 13:58:10 UTC (rev 12389)
@@ -319,6 +319,37 @@
}
}
+u_int32_t mapping_calc_a(mapping *m, float num, float den, u_int32_t mix){
+ u_int32_t o;
+ int r = (mix>>16)&0xff;
+ int g = (mix>>8)&0xff;
+ int b = mix&0xff;
+
+ if(den>0.f)
+ num /= den;
+
+ if(m->i_range==0){
+ if(num<=m->low)
+ o = m->mapfunc(0.,mix);
+ else
+ o = m->mapfunc(1.,mix);
+ }else{
+ double val = (num - m->low) * m->i_range;
+ o = m->mapfunc(val,mix);
+ }
+
+ r += (((o>>16)&0xff) - r)*den;
+ g += (((o>>8)&0xff) - g)*den;
+ b += ((o&0xff) - b)*den;
+ if(r<0)r=0;
+ if(g<0)g=0;
+ if(b<0)b=0;
+ if(r>255)r=255;
+ if(g>255)g=255;
+ if(b>255)b=255;
+ return (r<<16) + (g<<8) + b;
+}
+
int mapping_inactive_p(mapping *m){
if(m->mapfunc == inactive)return 1;
return 0;
Modified: trunk/sushivision/mapping.h
===================================================================
--- trunk/sushivision/mapping.h 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/mapping.h 2007-01-29 13:58:10 UTC (rev 12389)
@@ -36,6 +36,7 @@
extern void mapping_set_func(mapping *m, int funcnum);
extern double mapping_val(mapping *m, double in);
extern u_int32_t mapping_calc(mapping *m, double in, u_int32_t mix);
+extern u_int32_t mapping_calc_a(mapping *m, float num, float den, u_int32_t mix);
extern int mapping_inactive_p(mapping *m);
extern int num_solids();
Modified: trunk/sushivision/panel-1d.c
===================================================================
--- trunk/sushivision/panel-1d.c 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/panel-1d.c 2007-01-29 13:58:10 UTC (rev 12389)
@@ -346,7 +346,7 @@
// choose the value under the crosshairs
{
double val = (p1->flip?plot->sely:plot->selx);
- int bin = scalespace_pixel(&p1->x_v, val);
+ int bin = rint(scalespace_pixel(&p1->x_v, val));
u_int32_t color = mapping_calc(p1->mappings+i,1.,0);
for(i=0;i<p->objectives;i++){
@@ -534,7 +534,7 @@
double x_max,
int w,
double *dim_vals,
- _sushiv_compute_cache *c){
+ _sushiv_compute_cache_1d *c){
sushiv_panel1d_t *p1 = p->subtype->p1;
double work[w];
int i,j,fn=p->sushi->functions;
@@ -599,12 +599,12 @@
int i,j;
if(p1->link_x){
- dw = p2->data_w;
+ dw = p2->x_v.pixels;
p1->x_d = p2->x_d;
p1->x_scale = p2->x_scale;
}
if(p1->link_y){
- dw = p2->data_h;
+ dw = p2->y_v.pixels;
p1->x_d = p2->y_d;
p1->x_scale = p2->y_scale;
}
@@ -871,6 +871,38 @@
update_context_menus(p);
}
+void _maintain_cache_1d(sushiv_panel_t *p, _sushiv_compute_cache_1d *c, int w){
+
+ /* toplevel initialization */
+ if(c->fout == 0){
+ int i,j;
+
+ /* determine which functions are actually needed */
+ c->call = calloc(p->sushi->functions,sizeof(*c->call));
+ c->fout = calloc(p->sushi->functions,sizeof(*c->fout));
+ for(i=0;i<p->objectives;i++){
+ sushiv_objective_t *o = p->objective_list[i].o;
+ for(j=0;j<o->outputs;j++)
+ c->call[o->function_map[j]]=
+ p->sushi->function_list[o->function_map[j]]->callback;
+ }
+ }
+
+ /* once to begin, as well as anytime the data width changes */
+ if(c->storage_width < w){
+ int i;
+ c->storage_width = w;
+
+ for(i=0;i<p->sushi->functions;i++){
+ if(c->call[i]){
+ if(c->fout[i])free(c->fout[i]);
+ c->fout[i] = malloc(w * p->sushi->function_list[i]->outputs *
+ sizeof(**c->fout));
+ }
+ }
+ }
+}
+
int _sushiv_panel_cooperative_compute_1d(sushiv_panel_t *p,
_sushiv_compute_cache *c){
sushiv_panel1d_t *p1 = p->subtype->p1;
@@ -939,7 +971,7 @@
dim_vals[i]=dim->val;
}
- _maintain_cache(p,c,dw);
+ _maintain_cache_1d(p,&c->p1,dw);
// update scales if we're just starting
if(p1->last_line==0){
@@ -959,7 +991,7 @@
}
/* compute */
- compute_1d(p, serialno, x_d, x_min, x_max, dw, dim_vals, c);
+ compute_1d(p, serialno, x_d, x_min, x_max, dw, dim_vals, &c->p1);
gdk_threads_enter ();
_sushiv_panel_dirty_map(p);
_sushiv_panel_dirty_legend(p);
@@ -1067,65 +1099,6 @@
}
}
-// called with lock
-static void panel1d_find_peak(sushiv_panel_t *p){
- sushiv_panel1d_t *p1 = p->subtype->p1;
- Plot *plot = PLOT(p->private->graph);
- int i,j;
- int dw = p1->data_size;
- int count = 0;
-
- // finds in order each peak (in the event there's more than one) of
- // each active objective
- while(1){
-
- for(i=0;i<p->objectives;i++){
- if(p1->data_vec && p1->data_vec[i] && !mapping_inactive_p(p1->mappings+i)){
- double *data=p1->data_vec[i];
- double best_val = data[0];
- double best_j = 0;
- int inner_count = count+1;
-
- for(j=1;j<dw;j++){
- if(!isnan(data[j])){
- if(data[j]>best_val){
- inner_count = count+1;
- best_val = data[j];
- best_j = j;
- }else if (data[j]==best_val){
- if(inner_count <= p1->peak_count){
- inner_count++;
- best_val = data[j];
- best_j = j;
- }
- }
- }
- }
-
- count = inner_count;
- if(count>p1->peak_count){
- double xv = scalespace_value(&p1->x_v,best_j);
-
- if(p1->flip)
- plot_set_crosshairs(plot,0,xv);
- else
- plot_set_crosshairs(plot,xv,0);
- crosshair_callback(p);
-
- p1->peak_count++;
-
- return;
- }
- }
- }
-
- if(p1->peak_count==0)
- return; // must be all inactive
- else
- p1->peak_count=0;
- }
-}
-
static gboolean panel1d_keypress(GtkWidget *widget,
GdkEventKey *event,
gpointer in){
@@ -1154,10 +1127,6 @@
_sushiv_panel_undo_up(p);
return TRUE;
- case GDK_p:
- // find [next] peak
- panel1d_find_peak(p);
- return TRUE;
}
return FALSE;
@@ -1238,7 +1207,6 @@
"",
"Start zoom selection",
"Clear readouts",
- "Find peaks",
"",
"Quit",
NULL
@@ -1250,7 +1218,6 @@
NULL,
"Enter",
"Escape",
- "p",
NULL,
"q",
NULL
@@ -1263,7 +1230,6 @@
&wrap_enter,
&wrap_escape,
- &panel1d_find_peak,
NULL,
&wrap_exit,
NULL,
Modified: trunk/sushivision/panel-1d.h
===================================================================
--- trunk/sushivision/panel-1d.h 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/panel-1d.h 2007-01-29 13:58:10 UTC (rev 12389)
@@ -70,3 +70,10 @@
int peak_count;
} sushiv_panel1d_t;
+typedef struct {
+ void (**call)(double *, double *);
+ double **fout; // [function number][outval_number*x]
+ int storage_width;
+
+} _sushiv_compute_cache_1d;
+
Modified: trunk/sushivision/panel-2d.c
===================================================================
--- trunk/sushivision/panel-2d.c 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/panel-2d.c 2007-01-29 13:58:10 UTC (rev 12389)
@@ -33,10 +33,498 @@
#include <gdk/gdkkeysyms.h>
#include "internal.h"
+/* helper functions for performing progressive computation */
+
+/* performs render helper cleanup after finishing a progressive
+ render; makes sure old map is completely replaced by new. */
+/* Don't check serialno or size; we must force any completion before a
+ resize/rerender, so it will always match anyway */
+/* call from lock */
+static void compute_complete_render(sushiv_panel_t *p,
+ int true_complete){
+
+ sushiv_panel2d_t *p2 = p->subtype->p2;
+ scalespace *panelx = &p2->x;
+ scalespace *panely = &p2->y;
+ scalespace *datay = &p2->y_v;
+
+ int i,x,y;
+ int w = panelx->pixels;
+ int h = panely->pixels;
+
+ /* these progressive rendering helpers are specific to resampled y;
+ if ph=dh, there's nothing to do */
+
+ if(h != datay->pixels){
+ if(p2->render_flag){
+ if(true_complete){
+ /* fully complete render; swap and zero */
+
+ for(i=0;i<p2->y_obj_num;i++){
+ float *n = p2->y_num_rend[i];
+ float *d = p2->y_den_rend[i];
+
+ p2->y_num_rend[i] = p2->y_num[i];
+ p2->y_num = n;
+ p2->y_den_rend[i] = p2->y_den[i];
+ p2->y_den = d;
+
+ memset(p2->y_num_rend[i],0,sizeof(**p2->y_num_rend)*w*h);
+ memset(p2->y_den_rend[i],0,sizeof(**p2->y_den_rend)*w*h);
+
+ }
+
+ }else{
+ /* partially complete render; force the completion as a mix of current/pending */
+
+ for(i=0;i<p2->y_obj_num;i++){
+ for(y=0;y<h;y++){
+ float del = p2->y_rend[y];
+ if(del>0){
+ float *a = p2->y_num[i] + y*w;
+ float *b = p2->y_num_rend[i] + y*w;
+ for(x=0;x<w;x++){
+ *a = (*a) + (*a - *b++)*del;
+ a++;
+ }
+
+ a = p2->y_den[i] + y*w;
+ b = p2->y_den_rend[i] + y*w;
+ for(x=0;x<w;x++){
+ *a = *a+(*a-*b++)*del;
+ a++;
+ }
+ }
+ }
+
+ memset(p2->y_num_rend[i],0,sizeof(**p2->y_num_rend)*w*h);
+ memset(p2->y_den_rend[i],0,sizeof(**p2->y_den_rend)*w*h);
+
+ }
+
+ }
+
+ memset(p2->y_rend,0,sizeof(*p2->y_rend)*h);
+ }
+
+ p2->render_flag = 0;
+ }
+}
+
+/* prepares for a render (checks for / sets up resampling) */
+// call from lock
+static void compute_prepare_render(sushiv_panel_t *p){
+ sushiv_panel2d_t *p2 = p->subtype->p2;
+ scalespace *panelx = &p2->x;
+ scalespace *panely = &p2->y;
+ scalespace *datay = &p2->y_v;
+
+ int i;
+ int w = panelx->pixels;
+ int h = panely->pixels;
+
+ if(p2->render_flag)
+ compute_complete_render(p, 0);
+
+ /* progressive rendering helpers are specific to resampled y;
+ if ph=dh, there's nothing to do */
+ if(!p2->y_rend && h != datay->pixels){
+ p2->y_rend = calloc(h,sizeof(*p2->y_rend));
+
+ if(!p2->y_num_rend)
+ p2->y_num_rend = calloc(p2->y_obj_num,sizeof(*p2->y_num_rend));
+ if(!p2->y_den_rend)
+ p2->y_den_rend = calloc(p2->y_obj_num,sizeof(*p2->y_den_rend));
+
+ for(i=0;i<p2->y_obj_num;i++){
+ p2->y_num_rend[i] = calloc(w*h,sizeof(**p2->y_num_rend));
+ p2->y_den_rend[i] = calloc(w*h,sizeof(**p2->y_den_rend));
+ }
+ }
+}
+
+static void compute_free_render(sushiv_panel_t *p){
+ sushiv_panel2d_t *p2 = p->subtype->p2;
+ int i;
+
+ if(p2->y_rend){
+ free(p2->y_rend);
+ p2->y_rend = NULL;
+ }
+
+ if(p2->y_num_rend){
+ for(i=0;i<p2->y_obj_num;i++){
+ free(p2->y_num_rend[i]);
+ p2->y_num_rend[i]=NULL;
+ }
+ }
+
+ if(p2->y_den_rend){
+ for(i=0;i<p2->y_obj_num;i++){
+ free(p2->y_den_rend[i]);
+ p2->y_den_rend[i]=NULL;
+ }
+ }
+}
+
+// enter unlocked
+static void compute_one_data_line_2d(sushiv_panel_t *p,
+ scalespace panelx,
+ scalespace datax,
+ int x_d,
+ double x_min,
+ double x_max,
+ double *dim_vals,
+ _sushiv_compute_cache_2d *c){
+ int pw = panelx.pixels;
+ int dw = datax.pixels;
+
+ sushiv_panel2d_t *p2 = p->subtype->p2;
+ int i,j;
+
+ /* cache access is unlocked because the cache is private to this
+ worker thread */
+
+ if(pw != dw){
+ /* resampled computation */
+ float scaledel = scalespace_scaledel(&panelx,&datax);
+ float outdel = scalespace_pixel(&panelx,scalespace_value(&datax,0));
+ int outbin = floor(outdel);
+ outdel -= outbin;
+
+ /* zero obj line cache */
+ for(i=0;i<p->objectives;i++){
+ if(c->y_num[i])
+ memset(c->y_num[i],0, c->storage_width * sizeof(**c->y_num));
+ if(c->y_den[i])
+ memset(c->y_den[i],0, c->storage_width * sizeof(**c->y_den));
+ }
+
+ /* by x */
+ for(j=0;j<dw;j++){
+ float outdel2 = outdel + scaledel;
+
+ double *fout = c->fout;
+ sushiv_function_t **f = p2->used_function_list;
+ int *obj_y_off = p2->y_fout_offset;
+
+ float obj_y[p2->y_obj_num];
+ int *onum = p2->y_obj_to_panel;
+
+ /* by function */
+ dim_vals[x_d] = (x_max-x_min) * j / dw + x_min;
+ for(i=0;i<p2->used_functions;i++){
+ (*f)->callback(dim_vals,fout);
+ fout += (*f)->outputs;
+ f++;
+ }
+
+ /* process function output by plane type/objective */
+ /* 2d panels currently only care about the Y output value */
+
+ /* slider map */
+ for(i=0;i<p2->y_obj_num;i++){
+ obj_y[i] = (float)slider_val_to_del(p2->range_scales[*onum], c->fout[*obj_y_off]);
+ obj_y_off++;
+ onum++;
+ }
+
+ /* resample */
+ while(outdel2>1.f){
+ float addel = (1.f - outdel);
+
+ if(outbin >= 0 && outbin < pw){
+ for(i=0;i<p2->y_obj_num;i++){
+ if(!isnan(obj_y[i])){
+ c->y_num[i][outbin] += obj_y[i] * addel;
+ c->y_den[i][outbin] += addel;
+ }
+ }
+ }
+
+ outdel2 -= addel;
+ outbin++;
+ outdel = 0.f;
+ }
+
+ if(outdel2>0.f){
+ float addel = (outdel2 - outdel);
+
+ if(outbin >= 0 && outbin < pw){
+ for(i=0;i<p2->y_obj_num;i++){
+ if(!isnan(obj_y[i])){
+ c->y_num[i][outbin] += obj_y[i] * addel;
+ c->y_den[i][outbin] += addel;
+ }
+ }
+ }
+ }
+ }
+
+ }else{
+ /* simpler non-resampling case */
+ /* by x */
+ for(j=0;j<dw;j++){
+ double *fout = c->fout;
+ sushiv_function_t **f = p2->used_function_list;
+ int *obj_y_off = p2->y_fout_offset;
+ int *onum = p2->y_obj_to_panel;
+
+ /* by function */
+ dim_vals[x_d] = (x_max-x_min) * j / dw + x_min;
+ for(i=0;i<p2->used_functions;i++){
+ (*f)->callback(dim_vals,fout);
+ fout += (*f)->outputs;
+ f++;
+ }
+
+ /* process function output by plane type/objective */
+ /* 2d panels currently only care about the Y output value */
+
+ /* slider map */
+ for(i=0;i<p2->y_obj_num;i++){
+ float yval = (float)slider_val_to_del(p2->range_scales[*onum], c->fout[*obj_y_off]);
+
+ if(!isnan(yval)){
+ c->y_num[i][j] = yval;
+ c->y_den[i][j] = 1.f;
+ }else{
+ c->y_num[i][j] = 0.f;
+ c->y_den[i][j] = 0.f;
+ }
+
+ obj_y_off++;
+ onum++;
+ }
+ }
+ }
+}
+
+/* Although render/swizzle is done by data line, we still need to
+ display panel lines. This is a wrapper around data line rendering
+ that updates the relevant panel line[s] with the computed
+ data. */
+static void compute_one_line_2d(sushiv_panel_t *p,
+ int serialno,
+ scalespace panelx,
+ scalespace datax,
+ scalespace panely,
+ scalespace datay,
+
+ int y, // data line
+ int x_d,
+ double x_min,
+ double x_max,
+ double *dim_vals,
+ _sushiv_compute_cache_2d *c){
+
+ sushiv_panel2d_t *p2 = p->subtype->p2;
+ int i,j;
+ int w = panelx.pixels;
+ int ph = panely.pixels;
+ int dh = datay.pixels;
+
+ /* before anything else-- compute the line. */
+ compute_one_data_line_2d(p, panelx, datax, x_d, x_min, x_max,
+ dim_vals, c);
+
+ if(ph != dh){
+ /* this is a resampling population */
+
+ float scaledel = scalespace_scaledel(&panely,&datay);
+ float outdel = scalespace_pixel(&panely,scalespace_value(&datay,y));
+ int outbin = floor(outdel);
+ float outdel2 = (outdel-outbin) + scaledel;
+ outdel -= outbin;
+
+ while(outdel2>1.f){
+ float addel = (1.f - outdel);
+
+ if(outbin >= 0 && outbin < ph){
+ gdk_threads_enter ();
+
+ if(p2->serialno == serialno){
+ for(j=0;j<p2->y_obj_num;j++){
+ float *n = p2->y_num_rend[j] + outbin*w;
+ float *d = p2->y_den_rend[j] + outbin*w;
+ float *tn = c->y_num[j];
+ float *td = c->y_den[j];
+
+ for(i=0;i<w;i++){
+ n[i] += tn[i] * addel;
+ d[i] += td[i] * addel;
+ }
+ }
+ p2->y_rend[outbin]+=addel;
+ }else{
+ gdk_threads_leave ();
+ return;
+ }
+ gdk_threads_leave ();
+ }
+
+ outdel2 -= addel;
+ outbin++;
+ outdel = 0.f;
+ }
+
+ if(outdel2>0.f){
+ float addel = (outdel2 - outdel);
+
+ if(outbin >= 0 && outbin < ph){
+ gdk_threads_enter ();
+ if(p2->serialno == serialno){
+ for(j=0;j<p2->y_obj_num;j++){
+ float *n = p2->y_num_rend[j] + outbin*w;
+ float *d = p2->y_den_rend[j] + outbin*w;
+ float *tn = c->y_num[j];
+ float *td = c->y_den[j];
+
+ for(i=0;i<w;i++){
+ n[i] += tn[i] * addel;
+ d[i] += td[i] * addel;
+ }
+ }
+ p2->y_rend[outbin]+=addel;
+ }
+ gdk_threads_leave ();
+ }
+ }
+ }else{
+
+ gdk_threads_enter ();
+
+ if(p2->serialno == serialno){
+ for(j=0;j<p2->y_obj_num;j++){
+ float *n = p2->y_num[j] + y*w;
+ float *d = p2->y_den[j] + y*w;
+ float *tn = c->y_num[j];
+ float *td = c->y_den[j];
+
+ memcpy(n,tn,w*sizeof(*n));
+ memcpy(d,td,w*sizeof(*n));
+
+ }
+ }
+ gdk_threads_leave ();
+ }
+}
+
+// call with lock
+static void clear_pane(sushiv_panel_t *p){
+
+ sushiv_panel2d_t *p2 = p->subtype->p2;
+ scalespace *panelx = &p2->x;
+ scalespace *panely = &p2->y;
+ int i;
+ int w = panelx->pixels;
+ int h = panely->pixels;
+
+ for(i=0;i<p2->y_obj_num;i++){
+ memset(p2->y_num[i],0,sizeof(**p2->y_num)*w*h);
+ memset(p2->y_den[i],0,sizeof(**p2->y_den)*w*h);
+ if(p2->y_num_rend && p2->y_num_rend[i])
+ memset(p2->y_num_rend[i],0,sizeof(**p2->y_num_rend)*w*h);
+ if(p2->y_den_rend && p2->y_den_rend[i])
+ memset(p2->y_den_rend[i],0,sizeof(**p2->y_den_rend)*w*h);
+ }
+ if(p2->y_rend)
+ memset(p2->y_rend,0,sizeof(*p2->y_rend)*h);
+ p2->render_flag = 0;
+}
+
+typedef struct{
+ double x;
+ double y;
+ double z;
+ double e1;
+ double e2;
+ double p1;
+ double p2;
+ double m;
+} compute_result;
+
+// used by the legend code. this lets us get away with having only a mapped display pane
+// call with lock
+static void compute_single_point(sushiv_panel_t *p,sushiv_objective_t *o, double x, double y, compute_result *out){
+ double dim_vals[p->sushi->dimensions];
+ sushiv_panel2d_t *p2 = p->subtype->p2;
+ int i,j;
+ int pflag=0;
+ int eflag=0;
+
+ // fill in dimensions
+ int x_d = p2->x_d->number;
+ int y_d = p2->y_d->number;
+
+ for(i=0;i<p->sushi->dimensions;i++){
+ sushiv_dimension_t *dim = p->sushi->dimension_list[i];
+ dim_vals[i]=dim->val;
+ }
+
+ gdk_threads_leave();
+
+ dim_vals[x_d] = x;
+ dim_vals[y_d] = y;
+
+ *out = (compute_result){NAN,NAN,NAN,NAN,NAN,NAN,NAN,NAN};
+
+ // compute
+ for(i=0;i<p->sushi->functions;i++){
+ sushiv_function_t *f = p->sushi->function_list[i];
+ int compflag = 0;
+ double fout[f->outputs];
+ double val;
+
+ // compute and demultiplex output
+ for(j=0;j<o->outputs;j++){
+ if(o->function_map[j] == i){
+
+ if(!compflag) f->callback(dim_vals,fout);
+ compflag = 1;
+
+ val = fout[o->output_map[j]];
+ switch(o->output_types[j]){
+ case 'X':
+ out->x = val;
+ break;
+ case 'Y':
+ out->y = val;
+ break;
+ case 'Z':
+ out->z = val;
+ break;
+ case 'E':
+ if(eflag)
+ out->e2 = val;
+ else
+ out->e1 = val;
+ eflag = 1;
+ break;
+ case 'P':
+ if(pflag)
+ out->p2 = val;
+ else
+ out->p1 = val;
+ pflag = 1;
+ break;
+ case 'M':
+ out->m = val;
+ break;
+ }
+ }
+ }
+ }
+ gdk_threads_enter();
+
+}
+
+/* functions that perform actual graphical rendering */
+
static void render_checks(int w, int y, u_int32_t *render){
int x,j;
/* default checked background */
- /* 16x16 'mid-checks' */
+ /* 16x16 'mid-checks' */
int phase = (y>>4)&1;
for(x=0;x<w;){
u_int32_t phaseval = 0x505050;
@@ -47,40 +535,75 @@
}
}
+static void render_y_plane(sushiv_panel_t *p, int y, int objnum, u_int32_t *render){
+ sushiv_panel2d_t *p2 = p->subtype->p2;
+
+ int w,h,x;
+ int cond_onum = p2->y_obj_from_panel[objnum];
+ double alpha = p2->alphadel[objnum];
+ w = p2->x.pixels;
+ h = p2->y.pixels;
+
+ // is this a resampled render in-progress?
+ if(p2->render_flag){
+ // resampled render in-progress; we must merge the panel and render buffers
+ float del = p2->y_rend[y];
+ float *numA = p2->y_num[cond_onum] + w*y;
+ float *denA = p2->y_den[cond_onum] + w*y;
+ float *numB = p2->y_num_rend[cond_onum] + w*y;
+ float *denB = p2->y_den_rend[cond_onum] + w*y;
+
+ for(x=0;x<w;x++){
+ float num = numA[x] + (numB[x] - numA[x])*del;
+ float den = denA[x] + (denB[x] - denA[x])*del;
+ if(den>0.f){
+ num /= den;
+ /* map/render result */
+ if(!isnan(num) && num>=alpha)
+ render[x] = mapping_calc_a(p2->mappings+objnum,num,den,render[x]);
+ }
+ }
+
+ }else{
+ // normal render or fully complete resampled render
+
+ float *num = p2->y_num[cond_onum] + w*y;
+ float *den = p2->y_den[cond_onum] + w*y;
+
+ for(x=0;x<w;x++){
+ /* map/render result */
+ if(!isnan(num[x]) && num[x]>=alpha)
+ render[x] = mapping_calc_a(p2->mappings+objnum,num[x],den[x],render[x]);
+ }
+ }
+}
+
static void _sushiv_panel2d_remap(sushiv_panel_t *p){
sushiv_panel2d_t *p2 = p->subtype->p2;
Plot *plot = PLOT(p->private->graph);
- int w,h,x,y,i;
- w = p2->data_w;
- h = p2->data_h;
+ int w,h,y,i;
+ w = p2->x.pixels;
+ h = p2->y.pixels;
if(plot){
- u_int32_t render[w];
-
- /* iterate */
- /* by line */
for(y = 0; y<h; y++){
-
+ u_int32_t *render = plot->datarect + y*w;
+
+ /* background checks */
render_checks(w,y,render);
-
+
/* by objective */
for(i=0;i<p->objectives;i++){
- double *data_rect = p2->data_rect[i] + y*w;
- double alpha = p2->alphadel[i];
+
+ /**** render Y plane */
+ render_y_plane(p, y, i, render);
+
+ /**** render Z plane */
- /* by x */
- for(x=0;x<w;x++){
- double val = data_rect[x];
-
- /* map/render result */
- if(!isnan(val) && val>=alpha)
- render[x] = mapping_calc(p2->mappings+i,val,render[x]);
- }
+ /**** render vector plane */
+
}
-
- /* store result in panel */
- memcpy(plot->datarect+y*w,render,w*sizeof(*render));
}
}
}
@@ -90,10 +613,6 @@
Plot *plot = PLOT(p->private->graph);
gdk_threads_enter ();
- int w = p2->data_w;
- int h = p2->data_h;
- int x = plot_get_crosshair_xpixel(plot);
- int y = plot_get_crosshair_ypixel(plot);
if(plot){
int i;
@@ -106,36 +625,29 @@
if(3-p2->x.decimal_exponent > depth) depth = 3-p2->x.decimal_exponent;
if(3-p2->y.decimal_exponent > depth) depth = 3-p2->y.decimal_exponent;
for(i=0;i<p->dimensions;i++){
- //int depth = del_depth(p->dimension_list[i].d->bracket[0],
- // p->dimension_list[i].d->bracket[1]) + offset;
snprintf(buffer,320,"%s = %+.*f",
p->dimension_list[i].d->name,
depth,
p->dimension_list[i].d->val);
plot_legend_add(plot,buffer);
}
-
+
// one space
plot_legend_add(plot,NULL);
- // add each active objective to the legend
+ // add each active objective plane to the legend
// choose the value under the crosshairs
for(i=0;i<p->objectives;i++){
- float val=NAN;
- if(p2->data_rect && p2->data_rect[i] &&
- x<w && x>0 &&
- y<h && y>0 )
- val = p2->data_rect[i][y*w+x];
+ if(!mapping_inactive_p(p2->mappings+i)){
+ compute_result vals;
+ compute_single_point(p,p->objective_list[i].o, plot->selx, plot->sely, &vals);
- if(!isnan(val) && val >= p2->alphadel[i]){
-
- val = slider_del_to_val(p2->range_scales[i],val);
-
- if(!isnan(val) && !mapping_inactive_p(p2->mappings+i)){
+ if(!isnan(vals.y)){
+
snprintf(buffer,320,"%s = %f",
p->objective_list[i].o->name,
- val);
+ vals.y);
plot_legend_add(plot,buffer);
}
}
@@ -265,81 +777,6 @@
}
}
-static void compute_one_line_2d(sushiv_panel_t *p,
- int serialno,
- int y,
- int x_d,
- double x_min,
- double x_max,
- int w,
- double *dim_vals,
- u_int32_t *render,
- _sushiv_compute_cache *c){
-
- sushiv_panel2d_t *p2 = p->subtype->p2;
- int i,j,fn=p->sushi->functions;
- double work[w];
-
- render_checks(w,y,render);
-
- /* by function */
- for(i=0;i<fn;i++){
- if(c->call[i]){
- sushiv_function_t *f = p->sushi->function_list[i];
- int step = f->outputs;
- double *fout = c->fout[i];
-
- /* by x */
- for(j=0;j<w;j++){
-
- dim_vals[x_d] = (x_max-x_min) * j / w + x_min;
- c->call[i](dim_vals,fout);
- fout+=step;
- }
- }
- }
-
- /* process function output by objective */
- /* 2d panels only care about the Y output value */
- for(i=0;i<p->objectives;i++){
- sushiv_objective_t *o = p->objective_list[i].o;
- int offset = o->private->y_fout;
- sushiv_function_t *f = o->private->y_func;
- if(f){
- int step = f->outputs;
- double *fout = c->fout[f->number]+offset;
- mapping m;
- double alpha;
-
- /* map result */
- /* range scales are static so no need to lock; if that ever
- changes, locking should happen in the scales... */
- for(j=0;j<w;j++){
- work[j] = slider_val_to_del(p2->range_scales[i],*fout);
- fout+=step;
- }
-
- gdk_threads_enter (); // misuse me as a global mutex
- if(p2->serialno == serialno){
- memcpy(p2->data_rect[i]+y*w,work,w*sizeof(*work));
- memcpy(&m,p2->mappings+i,sizeof(m));
- alpha = p2->alphadel[i];
- gdk_threads_leave (); // misuse me as a global mutex
- }else{
- gdk_threads_leave (); // misuse me as a global mutex
- break;
- }
-
- for(j=0;j<w;j++){
- double val = work[j];
- if(!isnan(val) && val>=alpha)
- render[j] = mapping_calc(&m,val,render[j]);
-
- }
- }
- }
-}
-
static int v_swizzle(int y, int height){
int yy = height >> 5;
if(y < yy)
@@ -370,15 +807,15 @@
}
// assumes data is locked
-static void fast_scale_x(double *data,
+static void fast_scale_x(float *data,
int w,
int h,
scalespace new,
scalespace old){
int x,y;
- double work[w];
+ float work[w];
int mapbase[w];
- double mapdel[w];
+ float mapdel[w];
double old_w = old.pixels;
double new_w = new.pixels;
@@ -396,19 +833,16 @@
}
for(y=0;y<h;y++){
- double *data_line = data+y*w;
+ float *data_line = data+y*w;
for(x=0;x<w;x++){
if(mapbase[x]<0 || mapbase[x]>=(w-1)){
- work[x]=NAN;
+ work[x]=0.f;
}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;
+ float del = mapdel[x];
+ float A = data_line[base];
+ float B = data_line[base+1];
+ work[x]= A + (B - A)*del;
}
}
@@ -416,15 +850,15 @@
}
}
-static void fast_scale_y(double *data,
+static void fast_scale_y(float *data,
int w,
int h,
scalespace new,
scalespace old){
int x,y;
- double work[h];
+ float work[h];
int mapbase[h];
- double mapdel[h];
+ float mapdel[h];
double old_h = old.pixels;
double new_h = new.pixels;
@@ -443,21 +877,18 @@
}
for(x=0;x<w;x++){
- double *data_column = data+x;
+ float *data_column = data+x;
int stride = w;
for(y=0;y<h;y++){
if(mapbase[y]<0 || mapbase[y]>=(h-1)){
- work[y]=NAN;
+ work[y]=0.f;
}else{
int base = mapbase[y]*stride;
- double del = mapdel[y];
- double A = data_column[base];
- double B = data_column[base+stride];
+ float del = mapdel[y];
+ float A = data_column[base];
+ float B = data_column[base+stride];
- if(isnan(A) || isnan(B)) // damn you SIGFPE
- work[y]=NAN;
- else
- work[y]= A - A*del + B*del;
+ work[y]= A + (B-A)*del;
}
}
@@ -468,10 +899,10 @@
}
}
-static void fast_scale(double *newdata,
+static void fast_scale(float *newdata,
scalespace xnew,
scalespace ynew,
- double *olddata,
+ float *olddata,
scalespace xold,
scalespace yold){
int y;
@@ -485,8 +916,8 @@
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;
+ float *new_line = newdata+y*new_w;
+ float *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);
@@ -495,8 +926,8 @@
// 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;
+ float *new_line = newdata+y*new_w;
+ float *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);
@@ -506,8 +937,8 @@
// 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;
+ float *new_line = newdata+y*new_w;
+ float *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);
@@ -518,8 +949,8 @@
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;
+ float *new_line = newdata+y*new_w;
+ float *old_line = olddata+y*old_w;
memcpy(new_line,old_line,new_w*(sizeof*new_line));
}
}
@@ -534,61 +965,96 @@
Plot *plot = PLOT(p->private->graph);
int w = plot->w.allocation.width;
int h = plot->w.allocation.height;
+ int remapflag = 0;
if(plot && GTK_WIDGET_REALIZED(GTK_WIDGET(plot))){
+
+ if( p2->serialno && // we've been through once and alloced
+ (p2->x.pixels != w ||
+ p2->y.pixels != h)){
+
+
+ // if a render was in progress, force completion
+ compute_complete_render(p, 0);
+ compute_free_render(p);
- if( (p2->data_w != w ||
- p2->data_h != h) &&
- 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++){
- double *new_rect = malloc(w * h* sizeof(**p2->data_rect));
+
+ /* Y planes */
+ for(i=0;i<p2->y_obj_num;i++){
+ float *new_n = calloc(w*h,sizeof(*new_n));
+ float *new_d = calloc(w*h,sizeof(*new_d));
- fast_scale(new_rect,plot->x,plot->y,p2->data_rect[i],p2->x,p2->y);
+ fast_scale(new_n,plot->x,plot->y,p2->y_num[i],p2->x,p2->y);
+ fast_scale(new_d,plot->x,plot->y,p2->y_den[i],p2->x,p2->y);
- free(p2->data_rect[i]);
- p2->data_rect[i] = new_rect;
+ free(p2->y_num[i]);
+ free(p2->y_den[i]);
+ p2->y_num[i] = new_n;
+ p2->y_den[i] = new_d;
}
+
+ /* match data scales to new panel size/scale */
p2->x = plot->x;
+ _sushiv_dimension_scales_from_panel(p2->x_d,
+ p2->x,
+ p2->x.pixels, // over/undersample will go here
+ &p2->x_v,
+ &p2->x_i);
p2->y = plot->y;
- p2->data_w = w;
- p2->data_h = h;
-
+ _sushiv_dimension_scales_from_panel(p2->y_d,
+ p2->y,
+ p2->y.pixels, // over/undersample will go here
+ &p2->y_v,
+ &p2->y_i);
_sushiv_panel2d_map_redraw(p);
}else{
-
- p2->data_w = w;
- p2->data_h = h;
-
- p2->x = scalespace_linear(p2->x_d->bracket[0],
- p2->x_d->bracket[1],
- w,
- PLOT(p->private->graph)->scalespacing,
- p2->x_d->name);
-
- p2->y = scalespace_linear(p2->y_d->bracket[0],
- p2->y_d->bracket[1],
- h,
- PLOT(p->private->graph)->scalespacing,
- p2->y_d->name);
+
+ _sushiv_dimension_scales(p2->x_d,
+ p2->x_d->bracket[0],
+ p2->x_d->bracket[1],
+ w,w,// over/undersample will go here
+ plot->scalespacing,
+ p2->x_d->name,
+ &p2->x,
+ &p2->x_v,
+ &p2->x_i);
+ _sushiv_dimension_scales(p2->y_d,
+ p2->y_d->bracket[0],
+ p2->y_d->bracket[1],
+ h,h,// over/undersample will go here
+ plot->scalespacing,
+ p2->y_d->name,
+ &p2->y,
+ &p2->y_v,
+ &p2->y_i);
}
- if(!p2->data_rect){
- int i,j;
+ if(!p2->y_num){
+ int i;
// allocate it
+
+ p2->y_num = calloc(p2->y_obj_num,sizeof(*p2->y_num));
+ for(i=0;i<p2->y_obj_num;i++)
+ p2->y_num[i] = calloc(w*h, sizeof(**p2->y_num));
- 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));
+ remapflag = 1;
+ }
+
+ if(!p2->y_den){
+ int i;
+ // allocate it
- // blank it
- for(i=0;i<p->objectives;i++)
- for(j=0;j<p2->data_w*p2->data_h;j++)
- p2->data_rect[i][j]=NAN;
+ p2->y_den = calloc(p2->y_obj_num,sizeof(*p2->y_den));
+ for(i=0;i<p2->y_obj_num;i++)
+ p2->y_den[i] = calloc(w*h, sizeof(**p2->y_den));
+
+ remapflag = 1;
+ }
+
+ if(remapflag)
_sushiv_panel2d_map_redraw(p);
- }
p2->serialno++;
p2->last_line = 0;
@@ -655,8 +1121,6 @@
static void dimchange_callback_2d(GtkWidget *button,gpointer in){
sushiv_panel_t *p = (sushiv_panel_t *)in;
- sushiv_panel2d_t *p2 = p->subtype->p2;
- int i,j;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))){
@@ -666,10 +1130,7 @@
plot_unset_box(PLOT(p->private->graph));
update_xy_availability(p);
- /* if the data_rect already exists, blank it */
- for(i=0;i<p->objectives;i++)
- for(j=0;j<p2->data_w*p2->data_h;j++)
- p2->data_rect[i][j]=NAN;
+ clear_pane(p);
_sushiv_panel2d_map_redraw(p);
_mark_recompute_2d(p);
@@ -735,6 +1196,44 @@
p->private->update_menus(p);
}
+void _maintain_cache_2d(sushiv_panel_t *p, _sushiv_compute_cache_2d *c, int w){
+ sushiv_panel2d_t *p2 = p->subtype->p2;
+
+ /* toplevel initialization */
+ if(c->fout == 0){
+ int i,count=0;
+
+ /* allocate output temporary buffer */
+ for(i=0;i<p2->used_functions;i++){
+ int fnum = p2->used_function_list[i]->number;
+ sushiv_function_t *f = p->sushi->function_list[fnum];
+ count += f->outputs;
+ }
+ c->fout = calloc(count, sizeof(*c->fout));
+
+ /* objective line buffer index */
+ c->y_num = calloc(p2->y_obj_num,sizeof(*c->y_num));
+ c->y_den = calloc(p2->y_obj_num,sizeof(*c->y_den));
+ for(i=0;i<p2->y_obj_num;i++){
+ c->y_num[i] = calloc(w,sizeof(**c->y_num));
+ c->y_den[i] = calloc(w,sizeof(**c->y_den));
+ }
+ c->storage_width = w;
+ }
+
+ /* anytime the data width changes */
+ if(c->storage_width != w){
+ int i;
+ c->storage_width = w;
+
+ for(i=0;i<p2->y_obj_num;i++){
+ p2->y_num[i] = realloc(p2->y_num[i],w*sizeof(**p2->y_num));
+ p2->y_den[i] = realloc(p2->y_den[i],w*sizeof(**p2->y_den));
+ }
+ }
+}
+
+
// called from one/all of the worker threads; the idea is that several
// of the threads will all call this and they collectively interleave
// ongoing computation of the pane
@@ -744,23 +1243,28 @@
sushiv_panel2d_t *p2 = p->subtype->p2;
Plot *plot;
- int w,h,i,d;
+ int pw,ph,dw,dh,i,d;
int serialno;
double x_min, x_max;
double y_min, y_max;
int x_d=-1, y_d=-1;
int render_scale_flag = 0;
- scalespace sx;
- scalespace sy;
+ scalespace sx,sx_v;
+ scalespace sy,sy_v;
// lock during setup
gdk_threads_enter ();
- w = p2->data_w;
- h = p2->data_h;
sx = p2->x;
+ sx_v = p2->x_i;
sy = p2->y;
+ sy_v = p2->y_i;
- if(p2->last_line>=h){
+ pw = sx.pixels;
+ ph = sy.pixels;
+ dw = sx_v.pixels;
+ dh = sy_v.pixels;
+
+ if(p2->last_line>=dh){
gdk_threads_leave ();
return 0;
}
@@ -774,52 +1278,45 @@
computing objectives */
double dim_vals[p->sushi->dimensions];
- /* render into temporary line; computation may be interrupted by
- events such as resizing, so we must be careful to simply assume
- the widget is unaltered between locks. This allows us to minimize
- checks. */
- u_int32_t render[w];
-
- x_min = scalespace_value(&sx,0);
- x_max = scalespace_value(&sx,w);
+ x_min = scalespace_value(&p2->x_i,0);
+ x_max = scalespace_value(&p2->x_i,dw);
x_d = p2->x_d->number;
- y_min = scalespace_value(&sy,h);
- y_max = scalespace_value(&sy,0);
+ y_min = scalespace_value(&p2->y_i,dh);
+ y_max = scalespace_value(&p2->y_i,0);
y_d = p2->y_d->number;
// 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,
+ for(i=0;i<p2->y_obj_num;i++){
+ fast_scale_x(p2->y_num[i],pw,ph,
sx,plot->x);
+ fast_scale_x(p2->y_den[i],pw,ph,
+ 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,
+ for(i=0;i<p2->y_obj_num;i++){
+ fast_scale_y(p2->y_num[i],pw,ph,
sy,plot->y);
+ fast_scale_y(p2->y_den[i],pw,ph,
+ 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 ();
- fprintf(stderr,"Invalid/missing x/y dimension setting in panel x_d=%d, y_d=%d\n",
- x_d,y_d);
- return 0;
- }
-
// Initialize local dimension value array
for(i=0;i<p->sushi->dimensions;i++){
sushiv_dimension_t *dim = p->sushi->dimension_list[i];
dim_vals[i]=dim->val;
}
- _maintain_cache(p,c,w);
+ _maintain_cache_2d(p,&c->p2,pw);
+ compute_prepare_render(p);
// update scales if we're just starting
if(p2->last_line==0){
@@ -828,10 +1325,9 @@
/* iterate */
/* by line */
- if(plot->w.allocation.height == h &&
- p2->last_line<h &&
+ if(p2->last_line<dh &&
serialno == p2->serialno){
- int y = v_swizzle(p2->last_line,h);
+ int y = v_swizzle(p2->last_line,dh);
p2->last_line++;
@@ -843,27 +1339,26 @@
render_scale_flag = 0;
}
- dim_vals[y_d]= (y_max - y_min) / h * y + y_min;
+ dim_vals[y_d]= (y_max - y_min) / dh * y + y_min;
/* compute line */
- compute_one_line_2d(p, serialno, y, x_d, x_min, x_max, w, dim_vals, render, c);
-
- /* move rendered line back into widget */
+ compute_one_line_2d(p, serialno, sx, sx_v, sy, sy_v, y, x_d, x_min, x_max, dim_vals, &c->p2);
+
gdk_threads_enter ();
p2->completed_lines++;
if(p2->serialno == serialno){
- u_int32_t *line = plot_get_background_line(plot, y);
- memcpy(line,render,w*sizeof(*render));
- if(p2->completed_lines==h){
+ if(p2->completed_lines==dh){
+ compute_complete_render(p, 1);
+ _sushiv_panel_dirty_map(p);
_sushiv_panel_dirty_legend(p);
plot_expose_request(plot);
}else{
- plot_expose_request_line(plot,y);
+ _sushiv_panel_dirty_map_throttled(p);
}
}
}
-
+
gdk_threads_leave ();
return 1;
}
@@ -945,67 +1440,6 @@
}
}
-// called with lock
-static void panel2d_find_peak(sushiv_panel_t *p){
- sushiv_panel2d_t *p2 = p->subtype->p2;
- Plot *plot = PLOT(p->private->graph);
- int i,j;
- int w = p2->data_w;
- int h = p2->data_h;
- int n = w*h;
- int count = 0;
-
- // finds in order each peak (in the event there's more than one) of
- // each active objective
- while(1){
-
- for(i=0;i<p->objectives;i++){
- if(p2->data_rect && p2->data_rect[i] && !mapping_inactive_p(p2->mappings+i)){
- double *data=p2->data_rect[i];
- double best_val = data[0];
- double best_j = 0;
- int inner_count = count+1;
-
- for(j=1;j<n;j++){
- if(!isnan(data[j])){
- if(data[j]>best_val){
- inner_count = count+1;
- best_val = data[j];
- best_j = j;
- }else if (data[j]==best_val){
- if(inner_count <= p2->peak_count){
- inner_count++;
- best_val = data[j];
- best_j = j;
- }
- }
- }
- }
-
- count = inner_count;
- if(count>p2->peak_count){
- int y = best_j/w;
- int x = best_j - y*w;
- double xv = scalespace_value(&p2->x,x);
- double yv = scalespace_value(&p2->y,h-y);
-
- plot_set_crosshairs(plot,xv,yv);
- _sushiv_panel2d_crosshairs_callback(p);
-
- p2->peak_count++;
-
- return;
- }
- }
- }
-
- if(p2->peak_count==0)
- return; // must be all inactive
- else
- p2->peak_count=0;
- }
-}
-
static gboolean panel2d_keypress(GtkWidget *widget,
GdkEventKey *event,
gpointer in){
@@ -1035,10 +1469,6 @@
_sushiv_panel_undo_up(p);
return TRUE;
- case GDK_p:
- // find [next] peak
- panel2d_find_peak(p);
- return TRUE;
}
return FALSE;
@@ -1119,7 +1549,6 @@
"",
"Start zoom box",
"Clear readouts",
- "Find peaks",
"",
"Quit",
NULL
@@ -1131,7 +1560,6 @@
NULL,
"Enter",
"Escape",
- "p",
NULL,
"q",
NULL
@@ -1144,7 +1572,6 @@
&wrap_enter,
&wrap_escape,
- &panel2d_find_peak,
NULL,
&wrap_exit,
NULL,
@@ -1323,10 +1750,11 @@
int *dimensions,
unsigned flags){
- int i;
+ int i,j;
int ret = _sushiv_new_panel(s,number,name,objectives,dimensions,flags);
sushiv_panel_t *p;
sushiv_panel2d_t *p2;
+ int fout_offsets[s->functions];
if(ret<0)return ret;
p = s->panel_list[number];
@@ -1370,6 +1798,81 @@
p->private->undo_log = panel2d_undo_log;
p->private->undo_restore = panel2d_undo_restore;
p->private->update_menus = update_context_menus;
+
+ /* set up helper data structures for rendering */
+
+ /* determine which functions are actually needed; if it's referenced
+ by an objective, it's used. Precache them in dense form. */
+ {
+ int fn = p->sushi->functions;
+ int used[fn],count=0,offcount=0;
+ memset(used,0,sizeof(used));
+ memset(fout_offsets,-1,sizeof(fout_offsets));
+
+ for(i=0;i<p->objectives;i++){
+ sushiv_objective_t *o = p->objective_list[i].o;
+ for(j=0;j<o->outputs;j++)
+ used[o->function_map[j]]=1;
+ }
+
+ for(i=0;i<fn;i++)
+ if(used[i]){
+ sushiv_function_t *f = p->sushi->function_list[i];
+ fout_offsets[i] = offcount;
+ offcount += f->outputs;
+ count++;
+ }
+
+ p2->used_functions = count;
+ p2->used_function_list = calloc(count, sizeof(*p2->used_function_list));
+
+ for(count=0,i=0;i<fn;i++)
+ if(used[i]){
+ p2->used_function_list[count]=p->sushi->function_list[i];
+ count++;
+ }
+ }
+
+ /* set up computation/render helpers for Y planes */
+
+ /* set up Y object mapping index */
+ {
+ int yobj_count = 0;
+
+ for(i=0;i<p->objectives;i++){
+ sushiv_objective_t *o = p->objective_list[i].o;
+ if(o->private->y_func) yobj_count++;
+ }
+
+ p2->y_obj_num = yobj_count;
+ p2->y_obj_list = calloc(yobj_count, sizeof(*p2->y_obj_list));
+ p2->y_obj_to_panel = calloc(yobj_count, sizeof(*p2->y_obj_to_panel));
+ p2->y_obj_from_panel = calloc(p->objectives, sizeof(*p2->y_obj_from_panel));
+
+ yobj_count=0;
+ for(i=0;i<p->objectives;i++){
+ sushiv_objective_t *o = p->objective_list[i].o;
+ if(o->private->y_func){
+ p2->y_obj_list[yobj_count] = o;
+ p2->y_obj_to_panel[yobj_count] = i;
+ p2->y_obj_from_panel[i] = yobj_count;
+ yobj_count++;
+ }else
+ p2->y_obj_from_panel[i] = -1;
+
+ }
+ }
+
+ /* set up function Y output value demultiplex helper */
+ {
+ p2->y_fout_offset = calloc(p2->y_obj_num, sizeof(*p2->y_fout_offset));
+ for(i=0;i<p2->y_obj_num;i++){
+ sushiv_objective_t *o = p2->y_obj_list[i];
+ int funcnum = o->private->y_func->number;
+ p2->y_fout_offset[i] = fout_offsets[funcnum] + o->private->y_fout;
+ }
+ }
+
return 0;
}
Modified: trunk/sushivision/panel-2d.h
===================================================================
--- trunk/sushivision/panel-2d.h 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/panel-2d.h 2007-01-29 13:58:10 UTC (rev 12389)
@@ -26,20 +26,48 @@
GtkWidget *popmenu;
GtkWidget *graphmenu;
- int data_w;
- int data_h;
int serialno;
- double **data_rect;
+
+ /* only run those functions used by this panel */
+ int used_functions;
+ sushiv_function_t **used_function_list;
+
+ /**** Y PLANES ******/
+ float **y_num; // not indirected; unused planes are simply empty
+ float **y_den; // not indirected; unused planes are simply empty
+
+ int y_obj_num;
+ sushiv_objective_t **y_obj_list; // list of objectives with a y plane
+ int *y_obj_to_panel; /* maps from position in condensed list to position in full list */
+ int *y_obj_from_panel; /* maps from position in full list to position in condensed list */
+ int *y_fout_offset;
+
+ /* these are gratuitous temporary storage to make progressive
+ resampled render after a fast scale look nicer. They're here
+ purely on the premise that 'lots of memory is cheap'. I'm sure
+ Firefox is at least this stupidly wasteful of memory for cosmetic
+ benefit. */
+ int render_flag;
+ float **y_num_rend;
+ float **y_den_rend;
+ float *y_rend;
+
+ /* scales and data -> display scale mapping */
scalespace x;
+ scalespace x_v;
+ scalespace x_i;
scalespace y;
+ scalespace y_v;
+ scalespace y_i;
+
int scales_init;
double oldbox[4];
int oldbox_active;
- mapping *mappings;
+ mapping *mappings;
Slider **range_scales;
GtkWidget **range_pulldowns;
- double *alphadel;
+ double *alphadel;
GtkWidget **dim_xb;
GtkWidget **dim_yb;
@@ -48,8 +76,8 @@
sushiv_dimension_t *y_d;
sushiv_dim_widget_t *x_scale;
sushiv_dim_widget_t *y_scale;
- int x_dnum; // number of dimension within panel, not global instance
- int y_dnum; // number of dimension within panel, not global instance
+ int x_dnum; // panel, not global list context
+ int y_dnum; // panel, not global list context
int last_line;
int completed_lines;
@@ -58,3 +86,13 @@
} sushiv_panel2d_t;
+typedef struct {
+ double *fout; // [function number * outval_number]
+
+ float **y_num; // [y_obj_list[i]][px]
+ float **y_den; // [y_obj_list[i]][px]
+
+ int storage_width;
+
+} _sushiv_compute_cache_2d;
+
Modified: trunk/sushivision/panel.c
===================================================================
--- trunk/sushivision/panel.c 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/panel.c 2007-01-29 13:58:10 UTC (rev 12389)
@@ -47,6 +47,25 @@
return 0;
}
+void set_map_throttle_time(sushiv_panel_t *p){
+ struct timeval now;
+ gettimeofday(&now,NULL);
+
+ p->private->last_map_throttle = now.tv_sec*1000 + now.tv_usec/1000;
+}
+
+static int test_throttle_time(sushiv_panel_t *p){
+ struct timeval now;
+ long test;
+ gettimeofday(&now,NULL);
+
+ test = now.tv_sec*1000 + now.tv_usec/1000;
+ if(p->private->last_map_throttle + 500 < test)
+ return 1;
+
+ return 0;
+}
+
// the following is slightly odd; we want map and legend updates to
// fire when the UI is otherwise idle (only good way to do event
// compression in gtk), but we don't want it processed int he main UI
@@ -78,6 +97,13 @@
gdk_threads_leave ();
}
+void _sushiv_panel_dirty_map_throttled(sushiv_panel_t *p){
+ gdk_threads_enter ();
+ if(test_throttle_time(p))
+ g_idle_add(_idle_map_fire,p);
+ gdk_threads_leave ();
+}
+
void _sushiv_panel_dirty_legend(sushiv_panel_t *p){
gdk_threads_enter ();
g_idle_add(_idle_legend_fire,p);
Modified: trunk/sushivision/plot.c
===================================================================
--- trunk/sushivision/plot.c 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/plot.c 2007-01-29 13:58:10 UTC (rev 12389)
@@ -27,7 +27,6 @@
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
-#include <time.h>
#include <string.h>
#include "scale.h"
@@ -856,11 +855,6 @@
p->box_data = box_data;
p->flags = flags;
- struct timeval now;
- gettimeofday(&now,NULL);
-
- p->begin = now.tv_sec;
- p->last_line_expose = 0;
return p;
}
@@ -896,36 +890,6 @@
gdk_threads_leave();
}
-// 'in progress' exposes that may or may not be honored
-void plot_expose_request_line(Plot *p, int num){
- gdk_threads_enter();
- GtkWidget *widget = GTK_WIDGET(p);
- GdkRectangle r;
- struct timeval now;
- int64_t msec;
-
- if(num<p->expose_y_lo)
- p->expose_y_lo=num;
- if(num>p->expose_y_hi)
- p->expose_y_hi=num;
- gettimeofday(&now,NULL);
- msec = (now.tv_sec-p->begin)*100LL + now.tv_usec/10000;
-
- if(msec > p->last_line_expose + 25){
- r.x=0;
- r.y=p->expose_y_lo;
- r.width=widget->allocation.width;
- r.height=p->expose_y_hi-p->expose_y_lo+1;
-
- gdk_window_invalidate_rect (widget->window, &r, FALSE);
-
- p->expose_y_lo = widget->allocation.height;
- p->expose_y_hi=0;
- p->last_line_expose = msec;
- }
- gdk_threads_leave();
-}
-
void plot_set_x_scale(Plot *p, scalespace x){
scalespace temp = p->x;
p->x = x;
Modified: trunk/sushivision/plot.h
===================================================================
--- trunk/sushivision/plot.h 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/plot.h 2007-01-29 13:58:10 UTC (rev 12389)
@@ -75,11 +75,6 @@
u_int32_t *legend_colors;
char **legend_list;
- int expose_y_lo;
- int expose_y_hi;
- time_t last_line_expose;
- time_t begin;
-
unsigned flags;
};
@@ -98,7 +93,6 @@
// the widget subclass half
void plot_expose_request(Plot *p);
-void plot_expose_request_line(Plot *p, int num);
void plot_expose_request_partial(Plot *p,int x, int y, int w, int h);
void plot_set_x_scale(Plot *p, scalespace x);
void plot_set_y_scale(Plot *p, scalespace y);
Modified: trunk/sushivision/scale.c
===================================================================
--- trunk/sushivision/scale.c 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/scale.c 2007-01-29 13:58:10 UTC (rev 12389)
@@ -214,6 +214,10 @@
return val;
}
+double scalespace_scaledel(scalespace *from, scalespace *to){
+ return from->step_val / from->step_pixel * from->m / to->m * to->step_pixel / to->step_val;
+}
+
int scalespace_mark(scalespace *s, int num){
return s->first_pixel + s->step_pixel*num;
}
@@ -247,6 +251,7 @@
ret.init = 1;
ret.pixels=pixels;
ret.legend=name;
+ ret.spacing = max_spacing;
if(orange < 1e-30*pixels){
// insufficient to safeguard the int64 first var below all by
Modified: trunk/sushivision/scale.h
===================================================================
--- trunk/sushivision/scale.h 2007-01-29 13:18:50 UTC (rev 12388)
+++ trunk/sushivision/scale.h 2007-01-29 13:58:10 UTC (rev 12389)
@@ -36,11 +36,12 @@
int init;
int pixels;
+ int spacing;
} scalespace;
int del_depth(double A, double B);
extern char **scale_generate_labels(unsigned scalevals, double *scaleval_list);
-
+extern double scalespace_scaledel(scalespace *from, scalespace *to);
extern double scalespace_value(scalespace *s, double pixel);
extern double scalespace_pixel(scalespace *s, double val);
extern int scalespace_mark(scalespace *s, int num);
More information about the commits
mailing list