From 1f44a960cb1965a8b71bf0ebb0f94c59631b3935 Mon Sep 17 00:00:00 2001 From: Stefan Frederik Date: Sat, 25 Dec 2021 13:37:49 +0100 Subject: [PATCH] implement zoom/move/full on y axis graphs --- src/callback.c | 276 ++++++++++++++++++----- src/draw.c | 21 +- src/scheduler.c | 12 +- src/xschem.h | 2 + xschem_library/ngspice/autozero_comp.sch | 18 +- 5 files changed, 259 insertions(+), 70 deletions(-) diff --git a/src/callback.c b/src/callback.c index a3788d2c..6c433cd6 100644 --- a/src/callback.c +++ b/src/callback.c @@ -167,15 +167,16 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int double wx2 = 8e-6; double wy2 = 4; double x1, y1, x2, y2, marginx, marginy; - double cx; + double cx, dx, cy; int divx = 10; int divy = 5; const char *val; char s[30]; int n, c, i; - double xx1, xx2; + double xx1, xx2, yy1, yy2; int need_redraw = 0; double delta_threshold = 0.25; + int dataset = 0; #if HAS_CAIRO==1 cairo_save(xctx->cairo_ctx); @@ -203,74 +204,247 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int if(val[0]) wx2 = atof(val); val = get_tok_value(xctx->rect[c][n].prop_ptr,"y2",0); if(val[0]) wy2 = atof(val); + val = get_tok_value(xctx->rect[c][n].prop_ptr,"dataset",0); + if(val[0]) dataset = atoi(val); + if(dataset >= xctx->datasets) dataset = xctx->datasets - 1; + calc_graph_area(c, n, &x1, &y1, &x2, &y2, &marginx, &marginy); /* cache coefficients for faster graph coord transformations */ cx = (x2 - x1) / (wx2 - wx1); + dx = x1 - wx1 * cx; + cy = (y1 - y2) / (wy2 - wy1); dbg(1, "%g %g %g %g - %d %d\n", wx1, wy1, wx2, wy2, divx, divy); } if(event == MotionNotify && (state & Button2Mask)) { - double delta = (wx2 - wx1) / divx; - dbg(1, "waves_callback: Motion: %g %g --> %g %g\n", - xctx->mx_double_save, xctx->my_double_save, xctx->mousex_snap, xctx->mousey_snap); - delta_threshold = 0.10; - if(fabs(xctx->mx_double_save - xctx->mousex_snap) > fabs(cx * delta) * delta_threshold) { - xx1 = wx1 + (xctx->mx_double_save - xctx->mousex_snap) / cx; - xx2 = wx2 + (xctx->mx_double_save - xctx->mousex_snap) / cx; - if(i >= xctx->lastsel -1) { /* update saved mouse position after processing all graphs */ - xctx->mx_double_save = xctx->mousex_snap; - xctx->my_double_save = xctx->mousey_snap; + double delta; + if(xctx->mousex_snap < W_X(wx1)) { + delta = (wy2 - wy1) / divy; + delta_threshold = 0.10; + if(fabs(xctx->my_double_save - xctx->mousey_snap) > fabs(cy * delta) * delta_threshold) { + yy1 = wy1 + (xctx->my_double_save - xctx->mousey_snap) / cy; + yy2 = wy2 + (xctx->my_double_save - xctx->mousey_snap) / cy; + if(i >= xctx->lastsel -1) { /* update saved mouse position after processing all graphs */ + xctx->mx_double_save = xctx->mousex_snap; + xctx->my_double_save = xctx->mousey_snap; + } + my_snprintf(s, S(s), "%g", yy1); + my_strdup(1424, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y1", s)); + my_snprintf(s, S(s), "%g", yy2); + my_strdup(1425, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y2", s)); + need_redraw = 1; + } + + } else { + delta = (wx2 - wx1) / divx; + delta_threshold = 0.10; + if(fabs(xctx->mx_double_save - xctx->mousex_snap) > fabs(cx * delta) * delta_threshold) { + xx1 = wx1 + (xctx->mx_double_save - xctx->mousex_snap) / cx; + xx2 = wx2 + (xctx->mx_double_save - xctx->mousex_snap) / cx; + if(i >= xctx->lastsel -1) { /* update saved mouse position after processing all graphs */ + xctx->mx_double_save = xctx->mousex_snap; + xctx->my_double_save = xctx->mousey_snap; + } + my_snprintf(s, S(s), "%g", xx1); + my_strdup(1410, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x1", s)); + my_snprintf(s, S(s), "%g", xx2); + my_strdup(1411, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + need_redraw = 1; } - my_snprintf(s, S(s), "%g", xx1); - my_strdup(1410, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x1", s)); - my_snprintf(s, S(s), "%g", xx2); - my_strdup(1411, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); - need_redraw = 1; } } - else if(key == XK_Left || (button == Button5 && state == 0)) { - double delta = (wx2 - wx1) / divx; - delta_threshold = 2.0; - xx1 = wx1 - delta * delta_threshold; - xx2 = wx2 - delta * delta_threshold; - my_snprintf(s, S(s), "%g", xx1); - my_strdup(1395, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x1", s)); - my_snprintf(s, S(s), "%g", xx2); - my_strdup(1396, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + else if((button == Button5 && state == 0)) { + double delta; + if(xctx->mousex_snap < W_X(wx1)) { + delta = (wy2 - wy1) / divy; + delta_threshold = 1.0; + yy1 = wy1 + delta * delta_threshold; + yy2 = wy2 + delta * delta_threshold; + my_snprintf(s, S(s), "%g", yy1); + my_strdup(1420, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y1", s)); + my_snprintf(s, S(s), "%g", yy2); + my_strdup(1421, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y2", s)); + } else { + delta = (wx2 - wx1) / divx; + delta_threshold = 1.0; + xx1 = wx1 - delta * delta_threshold; + xx2 = wx2 - delta * delta_threshold; + my_snprintf(s, S(s), "%g", xx1); + my_strdup(1395, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x1", s)); + my_snprintf(s, S(s), "%g", xx2); + my_strdup(1396, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + } need_redraw = 1; } - else if(key == XK_Right || (button == Button4 && state == 0)) { - double delta = (wx2 - wx1) / divx; - delta_threshold = 2.0; - xx1 = wx1 + delta * delta_threshold; - xx2 = wx2 + delta * delta_threshold; - my_snprintf(s, S(s), "%g", xx1); - my_strdup(1397, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x1", s)); - my_snprintf(s, S(s), "%g", xx2); - my_strdup(1398, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + + else if(key == XK_Left) { + double delta; + if(xctx->mousex_snap < W_X(wx1)) { + delta = (wy2 - wy1); + yy2 = wy2 + delta * 0.1; + my_snprintf(s, S(s), "%g", yy2); + my_strdup(1419, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y2", s)); + + } else { + delta = (wx2 - wx1) / divx; + delta_threshold = 1.0; + xx1 = wx1 - delta * delta_threshold; + xx2 = wx2 - delta * delta_threshold; + my_snprintf(s, S(s), "%g", xx1); + my_strdup(1395, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x1", s)); + my_snprintf(s, S(s), "%g", xx2); + my_strdup(1396, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + } need_redraw = 1; } - else if(key == XK_Down || (button == Button5 && state == ShiftMask)) { - double delta = (wx2 - wx1); - xx2 = wx2 + delta * 0.1; - my_snprintf(s, S(s), "%g", xx2); - my_strdup(1399, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + + else if(button == Button4 && state == 0) { + double delta; + if(xctx->mousex_snap < W_X(wx1)) { + delta = (wy2 - wy1) / divy; + delta_threshold = 1.0; + yy1 = wy1 - delta * delta_threshold; + yy2 = wy2 - delta * delta_threshold; + my_snprintf(s, S(s), "%g", yy1); + my_strdup(1416, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y1", s)); + my_snprintf(s, S(s), "%g", yy2); + my_strdup(1417, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y2", s)); + } else { + delta = (wx2 - wx1) / divx; + delta_threshold = 1.0; + xx1 = wx1 + delta * delta_threshold; + xx2 = wx2 + delta * delta_threshold; + my_snprintf(s, S(s), "%g", xx1); + my_strdup(1397, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x1", s)); + my_snprintf(s, S(s), "%g", xx2); + my_strdup(1398, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + } need_redraw = 1; } - else if(key == XK_Up || (button == Button4 && state == ShiftMask)) { - double delta = (wx2 - wx1); - xx2 = wx2 - delta * 0.1; - my_snprintf(s, S(s), "%g", xx2); - my_strdup(1400, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + + else if(key == XK_Right) { + double delta; + if(xctx->mousex_snap < W_X(wx1)) { + delta = (wy2 - wy1); + yy2 = wy2 - delta * 0.1; + my_snprintf(s, S(s), "%g", yy2); + my_strdup(1418, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y2", s)); + } else { + delta = (wx2 - wx1) / divx; + delta_threshold = 1.0; + xx1 = wx1 + delta * delta_threshold; + xx2 = wx2 + delta * delta_threshold; + my_snprintf(s, S(s), "%g", xx1); + my_strdup(1397, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x1", s)); + my_snprintf(s, S(s), "%g", xx2); + my_strdup(1398, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + } + need_redraw = 1; + } + else if(button == Button5 && state == ShiftMask) { + double delta; + if(xctx->mousex_snap < W_X(wx1)) { + delta = (wy2 - wy1); + yy2 = wy2 + delta * 0.1; + my_snprintf(s, S(s), "%g", yy2); + my_strdup(1419, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y2", s)); + } else { + delta = (wx2 - wx1); + xx2 = wx2 + delta * 0.1; + my_snprintf(s, S(s), "%g", xx2); + my_strdup(1399, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + } + need_redraw = 1; + } + + else if(key == XK_Down) { + double delta; + if(xctx->mousex_snap < W_X(wx1)) { + delta = (wy2 - wy1) / divy; + delta_threshold = 1.0; + yy1 = wy1 - delta * delta_threshold; + yy2 = wy2 - delta * delta_threshold; + my_snprintf(s, S(s), "%g", yy1); + my_strdup(1420, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y1", s)); + my_snprintf(s, S(s), "%g", yy2); + my_strdup(1421, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y2", s)); + } else { + delta = (wx2 - wx1); + xx2 = wx2 + delta * 0.1; + my_snprintf(s, S(s), "%g", xx2); + my_strdup(1399, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + } + need_redraw = 1; + } + else if(button == Button4 && state == ShiftMask) { + double delta; + if(xctx->mousex_snap < W_X(wx1)) { + delta = (wy2 - wy1); + yy2 = wy2 - delta * 0.1; + my_snprintf(s, S(s), "%g", yy2); + my_strdup(1418, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y2", s)); + } else { + delta = (wx2 - wx1); + xx2 = wx2 - delta * 0.1; + my_snprintf(s, S(s), "%g", xx2); + my_strdup(1400, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + } + need_redraw = 1; + } + + else if(key == XK_Up) { + double delta; + if(xctx->mousex_snap < W_X(wx1)) { + delta = (wy2 - wy1) / divy; + delta_threshold = 1.0; + yy1 = wy1 + delta * delta_threshold; + yy2 = wy2 + delta * delta_threshold; + my_snprintf(s, S(s), "%g", yy1); + my_strdup(1416, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y1", s)); + my_snprintf(s, S(s), "%g", yy2); + my_strdup(1417, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y2", s)); + } else { + delta = (wx2 - wx1); + xx2 = wx2 - delta * 0.1; + my_snprintf(s, S(s), "%g", xx2); + my_strdup(1400, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + } need_redraw = 1; } else if(key == 'f') { if(xctx->values) { - xx1 = 0.0; - xx2 = xctx->values[0][xctx->npoints[0] -1]; - my_snprintf(s, S(s), "%g", xx1); - my_strdup(1409, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x1", s)); - my_snprintf(s, S(s), "%g", xx2); - my_strdup(1412, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + if(xctx->mousex_snap < W_X(wx1)) { + int i, j; + double v; + double min, max; + char *saven, *nptr, *ntok, *node = NULL;; + my_strdup2(1426, &node, get_tok_value(xctx->rect[c][n].prop_ptr,"node",0)); + nptr = node; + while( (ntok = my_strtok_r(nptr, "\n\t ", &saven)) ) { + nptr = NULL; + j = get_raw_index(ntok); + if(j >= 0) { + for(i = 0; i < xctx->npoints[dataset]; i++) { + v = get_raw_value(dataset, j, i); + if(i == 0 || v < min) min = v; + if(i == 0 || v > max) max = v; + } + if(max == min) max += 0.01; + } + } + my_free(1427, &node); + my_snprintf(s, S(s), "%g", min); + my_strdup(1422, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y1", s)); + my_snprintf(s, S(s), "%g", max); + my_strdup(1423, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "y2", s)); + + } else { + xx1 = 0; /* get_raw_value(dataset, 0, 0); */ + xx2 = get_raw_value(dataset, 0, xctx->npoints[dataset] -1); + my_snprintf(s, S(s), "%g", xx1); + my_strdup(1409, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x1", s)); + my_snprintf(s, S(s), "%g", xx2); + my_strdup(1412, &xctx->rect[c][n].prop_ptr, subst_token(xctx->rect[c][n].prop_ptr, "x2", s)); + } need_redraw = 1; } } diff --git a/src/draw.c b/src/draw.c index 6fe8c6a3..7a396599 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1651,7 +1651,23 @@ int read_rawfile(const char *f) dbg(0, "read_rawfile(): failed to open file %s for reading\n", f); return 0; } +int get_raw_index(const char *node) +{ + struct int_hashentry *entry; + entry = int_hash_lookup(xctx->raw_table, node, 0, XLOOKUP); + if(entry) return entry->value; + return -1; +} +double get_raw_value(int dataset, int idx, int point) +{ + int i, ofs; + ofs = 0; + for(i = 0; i < dataset; i++) { + ofs += xctx->npoints[i]; + } + return xctx->values[idx][ofs + point]; +} void calc_graph_area(int c, int i, double *x1, double *y1,double *x2,double *y2, double *marginx, double *marginy) { @@ -1936,9 +1952,8 @@ void draw_graph(int c, int i, int flags) dbg(1, "ntok=%s ctok=%s\n", ntok, ctok? ctok: "NULL"); if(ctok && ctok[0]) wave_color = atoi(ctok); if(stok && stok[0]) { - entry = int_hash_lookup(xctx->raw_table, stok, 0, XLOOKUP); - if(entry && entry->value) sweep_idx = entry->value; - else sweep_idx = 0; + sweep_idx = get_raw_index(stok); + if( sweep_idx == -1) sweep_idx = 0; } /* draw sweep variable(s) on x-axis */ if(wcnt == 0 || (stok && stok[0])) { diff --git a/src/scheduler.c b/src/scheduler.c index b5d32b5f..db1f71b5 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -1944,30 +1944,28 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg { int i; char s[30]; + int dataset = 0; cmd_found = 1; Tcl_ResetResult(interp); if(xctx->values) { + if(argc > 5) dataset = atoi(argv[5]); if(argc > 4) { /* xschem rawfile_query value v(ldcp) 123 */ if(!strcmp(argv[2], "value")) { - struct int_hashentry *entry; int point = atoi(argv[4]); const char *node = argv[3]; int idx = -1; - if(point >= 0 && point < xctx->npoints[0]) { + if(point >= 0 && point < xctx->npoints[dataset]) { if(isonlydigit(node)) { int i = atoi(node); if(i >= 0 && i < xctx->nvars) { idx = i; } } else { - entry = int_hash_lookup(xctx->raw_table, node, 0, XLOOKUP); - if(entry) { - idx = entry->value; - } + idx = get_raw_index(node); } if(idx >= 0) { - double val = xctx->values[idx][point]; + double val = get_raw_value(dataset, idx, point); my_snprintf(s, S(s), "%g", val); Tcl_AppendResult(interp, s, NULL); } diff --git a/src/xschem.h b/src/xschem.h index 4e23c000..f8a1610a 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -894,6 +894,8 @@ extern char cli_opt_netlist_dir[PATH_MAX]; extern Xschem_ctx *xctx; /* FUNCTIONS */ +extern int get_raw_index(const char *node); +extern double get_raw_value(int dataset, int idx, int point); extern int schematic_waves_loaded(void); extern void calc_graph_area(int c, int i, double *x1, double *y1,double *x2, double *y2, double *marginx,double *marginy); diff --git a/xschem_library/ngspice/autozero_comp.sch b/xschem_library/ngspice/autozero_comp.sch index a655668f..3c43cd3e 100644 --- a/xschem_library/ngspice/autozero_comp.sch +++ b/xschem_library/ngspice/autozero_comp.sch @@ -19,21 +19,21 @@ L 4 570 -170 570 -150 {} L 4 570 -170 690 -170 {} L 7 1090 -260 2520 -260 {} B 2 260 -1080 720 -920 {flags=1 -y1 = 0 -y2 = 1 +y1 = 0.00676696 +y2 = 0.922682 divy = 5 -x1=1.25e-07 -x2=3.75e-07 +x1=0 +x2=5e-07 divx=10 node="v(cal) v(saout)" color="4 5" } B 2 260 -1220 720 -1090 {flags=1 -y1 = 0.645 -y2 = 0.655 -divy = 10 -x1=1.25e-07 -x2=3.75e-07 +y1 = 0.648 +y2 = 0.652 +divy = 5 +x1=0 +x2=5e-07 divx=5 node="v(plus) v(minus)" color="4 5"}