From 651fca7d40742a4834de4be70a724ac79c399daf Mon Sep 17 00:00:00 2001
From: Jonathan Wilkes <jon.w.wilkes@gmail.com>
Date: Fri, 26 Jun 2020 23:06:52 -0400
Subject: [PATCH] interim commit, continuing to document plot_vis

---
 pd/src/g_graph.c    |  43 ++++-
 pd/src/g_scalar.c   |  33 ++--
 pd/src/g_template.c | 401 +++++++++++++++++++++++++++++++++-----------
 3 files changed, 357 insertions(+), 120 deletions(-)

diff --git a/pd/src/g_graph.c b/pd/src/g_graph.c
index 50173294a..404e14f20 100644
--- a/pd/src/g_graph.c
+++ b/pd/src/g_graph.c
@@ -740,6 +740,26 @@ t_float glist_xtopixels(t_glist *x, t_float xval)
     }
 }
 
+    /* convert an x coordinate value to an x pixel location in window */
+    /* we don't need the translation step for GOPS so we remove it here. Once
+       this is working with everything we can get rid of the one above. */
+t_float glist_xtopixels2(t_glist *x, t_float xval)
+{
+    if (!x->gl_isgraph)
+        return ((xval - x->gl_x1) / (x->gl_x2 - x->gl_x1));
+    else if (x->gl_isgraph && x->gl_havewindow)
+        return (x->gl_screenx2 - x->gl_screenx1) *
+            (xval - x->gl_x1) / (x->gl_x2 - x->gl_x1);
+    else
+    {
+        int x1, y1, x2, y2;
+        if (!x->gl_owner)
+            bug("glist_pixelstox");
+        graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
+        return ((x2 - x1) * (xval - x->gl_x1) / (x->gl_x2 - x->gl_x1));
+    }
+}
+
 t_float glist_ytopixels(t_glist *x, t_float yval)
 {
     if (!x->gl_isgraph)
@@ -757,6 +777,27 @@ t_float glist_ytopixels(t_glist *x, t_float yval)
     }
 }
 
+t_float glist_ytopixels2(t_glist *x, t_float yval)
+{
+    if (!x->gl_isgraph)
+        return ((yval - x->gl_y1) / (x->gl_y2 - x->gl_y1));
+    else if (x->gl_isgraph && x->gl_havewindow)
+        return (x->gl_screeny2 - x->gl_screeny1) *
+                (yval - x->gl_y1) / (x->gl_y2 - x->gl_y1);
+    else 
+    {
+        int x1, y1, x2, y2;
+        if (!x->gl_owner)
+            bug("glist_pixelstoy");
+        graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
+fprintf(stderr, "ytopixels: gl_y1 is %g\n", x->gl_y1);
+fprintf(stderr, "ytopixels: gl_y2 is %g\n", x->gl_y2);
+fprintf(stderr, "ytopixels: graph y1 is %d\n", y1);
+fprintf(stderr, "ytopixels: graph y2 is %d\n", y2);
+        return ((y2 - y1) * yval / (x->gl_y2 - x->gl_y1));
+    }
+}
+
     /* convert an X screen distance to an X coordinate increment.
       This is terribly inefficient;
       but probably not a big enough CPU hog to warrant optimizing. */
@@ -785,7 +826,7 @@ int text_xpix(t_text *x, t_glist *glist)
         xpix = glist_xtopixels(glist, glist->gl_x1) +
             x->te_xpix - glist->gl_xmargin;
     else xpix = (glist_xtopixels(glist, 
-            glist->gl_x1 + (glist->gl_x2 - glist->gl_x1) * 
+            glist->gl_x1 + (glist->gl_x2 - glist->gl_x1) *
                 x->te_xpix / (glist->gl_screenx2 - glist->gl_screenx1)));
     if (x->te_iemgui == 1)
         xpix += ((t_iemgui *)x)->legacy_x*sys_legacy;
diff --git a/pd/src/g_scalar.c b/pd/src/g_scalar.c
index d6204eada..a1f4cca73 100644
--- a/pd/src/g_scalar.c
+++ b/pd/src/g_scalar.c
@@ -838,7 +838,7 @@ void scalar_doconfigure(t_gobj *xgobj, t_glist *owner)
             glist_getcanvas(owner), 
             tagbuf,
             glist_isselected(owner, &x->sc_gobj),
-            xscale, 0.0, 0.0, yscale,
+            1.0, 0.0, 0.0, 1.0,
             (int)glist_xtopixels(owner, basex),
             (int)glist_ytopixels(owner, basey));
 
@@ -954,11 +954,14 @@ static void scalar_groupvis(t_scalar *x, t_glist *owner, t_template *template,
 /* At present, scalars have a three-level hierarchy in the gui,
    with two levels accessible by the user from within Pd:
    scalar - ".scalar%lx", x->sc_vec
-     |      <g> with matrix derived from x/y fields,
-     |      gop basexy, and gop scaling values. This group is
-     |      not configurable by the user. This means that the
-     |      a [draw g] below can ignore basexy and gop junk
-     |      when computing the transform matrix.
+     |      <g> with matrix derived from x/y fields and GOP
+     |      basex/y. This group is not configurable by the
+     |      user. This means that the a [draw g] child
+     |      object below it can ignore basexy and gop junk
+     |      when computing the transform matrix. For backward-
+     |      compatibility the old drawing instructions still
+     |      have to do a transform to get the pixel values, but
+     |      they were already using glist_xtopixel/etc. anyway.
      v
    dgroup - ".dgroup%lx.%lx", templatecanvas, x->sc_vec
      |      group used as parent for all the toplevel drawing
@@ -979,6 +982,10 @@ static void scalar_groupvis(t_scalar *x, t_glist *owner, t_template *template,
    The tag "blankscalar" is for scalars that don't have a visual
    representation, but maybe this can just be merged with "scalar"
 */
+
+t_float glist_xtopixels2(t_glist *x, t_float xval);
+t_float glist_ytopixels2(t_glist *x, t_float yval);
+
 static void scalar_vis(t_gobj *z, t_glist *owner, int vis)
 {
     //fprintf(stderr,"scalar_vis %d %lx\n", vis, (t_int)z);
@@ -1023,25 +1030,13 @@ static void scalar_vis(t_gobj *z, t_glist *owner, int vis)
 
     if (vis)
     {
-        t_float xscale = glist_xtopixels(owner, 1) - glist_xtopixels(owner, 0);
-        t_float yscale = glist_ytopixels(owner, 1) - glist_ytopixels(owner, 0);
-        /* we translate the .scalar%lx group to displace it on the tk side.
-           This is the outermost group for the scalar, something like a
-           poor man's viewport.
-           Also:
-             * the default stroke is supposed to be "none"
-             * default fill is supposed to be black.
-             * stroke-linejoin should be "miter", not "round"  
-           To fix these, we set the correct fill/stroke/strokelinjoin options
-           here on the .scalar%lx group. (Notice also that tkpath doesn't
-           understand "None"-- instead we must send an empty symbol.) */
         char tagbuf[MAXPDSTRING];
         sprintf(tagbuf, "scalar%lx", (long unsigned int)x->sc_vec);
         gui_vmess("gui_scalar_new", "xsiffffiii",
             glist_getcanvas(owner), 
             tagbuf,
             glist_isselected(owner, &x->sc_gobj),
-            xscale, 0.0, 0.0, yscale,
+            1.0, 0.0, 0.0, 1.0,
             (int)glist_xtopixels(owner, basex),
             (int)glist_ytopixels(owner, basey),
             glist_istoplevel(owner));
diff --git a/pd/src/g_template.c b/pd/src/g_template.c
index 006dbd868..6d0a13ee9 100644
--- a/pd/src/g_template.c
+++ b/pd/src/g_template.c
@@ -5740,7 +5740,7 @@ int array_getfields(t_symbol *elemtemplatesym,
         varname = wfielddesc->fd_un.fd_varsym;
     else varname = gensym("w");
     if (!template_find_field(elemtemplate, varname, &wonset, &type, &dummy)
-        || type != DT_FLOAT) 
+        || type != DT_FLOAT)
             wonset = -1;
 
         /* fill in slots for return values */
@@ -6023,7 +6023,15 @@ int plot_has_drawcommand(t_canvas *elemtemplatecanvas)
     return 0;
 }
 
+t_float glist_xtopixels2(t_glist *x, t_float xval);
+t_float glist_ytopixels2(t_glist *x, t_float yval);
+
 #define VIS_FIRSTTIME 1
+#define VIS_UPDATE -1
+#define TRACE_NMAX 2000
+
+#define CLIP(x) ((x) < 1e20 && (x) > -1e20 ? x : 0)
+
 
 /* Alright, time to actually document some of this spaghetti interface...
  *
@@ -6046,13 +6054,15 @@ int plot_has_drawcommand(t_canvas *elemtemplatecanvas)
  *     a template for the array which contains us. Tricky stuff.
  * t_template *template: the template that defines the structure of the data
  *     for our scalar
- * t_float basex: x coordinate of the containing scalar. In Purr Data we draw
- *     the plot as a child of the scalar's group, so we don't need this
- * t_float basey: same for y coordinate
+ * t_float basex: if the template has the magic field "x", its value is
+ *     reported here. If there is no "x" field this is set to 0.
+ *     For simplicity, in Purr Data we set this value in the matrix for the
+ *     scalar's group in scalar_new, so we don't use this here.
+ * t_float basey: same for magic "y" field from the template
  * t_array *parentarray: if we are plotting array data from within another
  *     array (e.g., this is a nested array) this is set. Not sure how it's
  *     currently used or whether nested arrays are even displayed properly.
- * int tovis: 1 for drawing the first time
+ * int tovis: VIS_FIRSTTIME for drawing the first time
  *           -1 if we just want to send new data without recreating the gobj
  *            0 to erase the drawing. However, it appears we don't actually
  *            erase anything here and depend on the parent element to do that
@@ -6063,37 +6073,125 @@ static void plot_vis(t_gobj *z, t_glist *glist, t_glist *parentglist,
     t_scalar *sc, t_word *data, t_template *template,
     t_float basex, t_float basey, t_array *parentarray, int tovis)
 {
-    t_plot *x = (t_plot *)z;
-    int elemsize, yonset, wonset, xonset, i;
+    t_plot *x = (t_plot *)z; /* our parent [plot] object */
+
+    int elemsize, /* size of an array element, measured in bytes */
+
+        yonset, /* how far into a given array element to index in order to point
+                   to the magic "y" value. If there's no magic "y" defined
+                   in the element's template this is set to -1 */
+
+        wonset, /* same as above but for the magic "w" value */
+
+        xonset, /* same as yonset but for the magic "x" value */
+
+        i;      /* used to iterate through the array we're plotting or drawing
+                   scalar elements for. */
+
         /* canvas containing the [struct] that defines structure of the data
            for the elements we're plotting. */
-    t_canvas *elemtemplatecanvas;
+    t_canvas *elemtemplatecanvas; 
     t_template *elemtemplate; /* the actual template for the element data */
     t_symbol *elemtemplatesym; /* symbolic name, i.e., 2nd arg to [struct] */
 
-        /* most of these are member fields of t_plot, but drawing commands like
+        /* most of the following are fields of t_plot, but drawing commands like
            plot have a clunky fielddesc type which requires sending the
            data and template in order to fetch the actual values. So these
-           are retrieved below in a single function call. */
-    t_float linewidth, xloc, xinc, yloc, style, usexloc, xsum, yval, vis,
-        scalarvis;
+           are retrieved below in a single function call.
+
+           They map to the plot object args like so:
+
+           [plot array outline linewidth xloc yloc xinc]
+        */
+    t_float linewidth, /* width of the trace */
+            xloc,      /* x position relative to the containing scalar
+                          scalar. If the template has no "x" field then xloc is 
+                          relative to the top left corner of the canvas. */
+
+            xinc,      /* for templates with no magic "x" field and for which
+                          there is no "-x" flag set in the [plot] we're about
+                          to display, the number of pixels to increment each
+                          element's x position.
+                          Also used to increment x for the trace. */
+
+            yloc,      /* same as xloc, for relative y position */
+
+            style,     /* one of the PLOTSTYLE_* values as defined in
+                          g_canvas.h. */
+
+            xsum,      /* rolling sum used to calculate x coordinate for
+                          templates that don't have the magic "x" field */
+
+            yval,      /* the y value of the trace/child elements, as set
+                          below */
+
+            vis,       /* value from the x_vis fielddesc of t_plot-- this
+                          controls visibility of the plot and any associated
+                          scalars for the particular plot about to be drawn.
+                          It can be associate with a template field using
+                          the "-v" flag, like [plot -v visfield etc.].
+                          Since this is a fielddesc this value can be set
+                          independently for different scalars/arrays that
+                          use plot_vis-- for example, you could show
+                          two scalars from the same template on a canvas,
+                          and have only one of them with visfield=1 to make
+                          the plot visible. */
+
+            scalarvis, /* value from the x_scalarvis fielddesc of t_plot--
+                          this independently controls whether the scalar
+                          elements get displayed for this plot, independent
+                          of the plot's trace. This may be set with
+                          the "-vs" flag, as in
+                          [plot -vs svis etc.]
+                          So you could have two scalars from the same
+                          template on a canvas, and have only one of them
+                          with svis=1 to make the plot's scalar elements
+                          visible. */
+
+            usexloc;   /* temp variable used below */
+
         /* two fields hacked in after the fact for Purr Data to display
-           garrays in different colors */
+           garrays in different colors. These aren't used for data structures */
     t_symbol *symfill;
     t_symbol *symoutline;
-        /* for the old drawing commands there's a three digit, buggy color
-           field for setting colors... */
-    char outline[20];
-    numbertocolor(fielddesc_getfloat(&x->x_outlinecolor, template,
-        data, 1), outline);
+
         /* the actual array whose data we want to plot. This is one of the
-           t_word's from the data pointer-- we just have to use the template
-           to figure out which one it is. This is one of the many tasks done
-           in plot_readownertemplate below... */
+           t_word's from the data pointer. We just have to use the template
+           to figure out which one it is. (This is one of the many tasks done
+           in plot_readownertemplate below...) */
     t_array *array;
     int nelem; /* total number of elements in the array */
     char *elem; /* a pointer to our array data */
-    t_fielddesc *xfielddesc, *yfielddesc, *wfielddesc;
+
+        /* data structures have these so-called "fielddesc" types. They
+           can be used to map data to a particular argument used by a
+           drawing instruction, either constants or variables. For example,
+           [plot a 5] will have an outline width of 5, and
+           [plot a outline] will have an outline width defined by the
+           value of the "outline" for the associated parent scalar or array. */
+
+    t_fielddesc *xfielddesc, /* associated with x_xpoints field of t_plot. This
+                                defaults to the magic "x" field of the
+                                element's template, and may be changed using
+                                the "-x" flag to plot.
+                                If there's no "-x" flag and no magic "x" in
+                                the element's template then we take a special
+                                branch below based off the confusingly-named
+                                "xonset" variable.
+                                Keep in mind this refers to a field from
+                                the _element's_ template. */
+
+                *yfielddesc, /* same as above but for the magic "y" variable
+                                for the element's template to control the y-
+                                coordinate for the plot and scalar elements */
+
+                *wfielddesc; /* same as above, but for the magic "w" field
+                                for the element's template to control the
+                                width of the trace at each element. As far
+                                as I can tell this magic "w" variable doesn't
+                                have any effect on the child scalars. This is
+                                unlike the magic "x" and "y" which control the
+                                relative positions for the child scalars. */
 
         /* not sure how much of the following comment from Vanilla applies
            here. Basically we're getting our variables filled, and if there are
@@ -6107,28 +6205,41 @@ static void plot_vis(t_gobj *z, t_glist *glist, t_glist *parentglist,
         Tk behavior in Pd Vanilla where a command that doesn't match the
         tag just gets ignored. */
         
-    if (plot_readownertemplate(x, data, template, 
-        &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc, &style,
-        &vis, &scalarvis, &xfielddesc, &yfielddesc, &wfielddesc, &symfill,
-        &symoutline) ||
-            ((vis == 0) && tovis) /* see above for 'tovis' */
-            || array_getfields(elemtemplatesym, &elemtemplatecanvas,
-                &elemtemplate, &elemsize, xfielddesc, yfielddesc, wfielddesc,
-                &xonset, &yonset, &wonset))
-                    return;
-    nelem = array->a_n;
-    elem = (char *)array->a_vec; /* our array data, cast to char* so we can
-                                    jump around inside it and recast in a
+        /* let's scoop up all the ridiculous amount of data we need to
+           plot the damn array. plot_readownertemplate and array_getfields
+           will return 1 if something went wrong. In that case we just
+           return before we've drawn anything */
+    if (plot_readownertemplate(x, data, template, &elemtemplatesym, &array,
+           &linewidth, &xloc, &xinc, &yloc, &style, &vis, &scalarvis,
+           &xfielddesc, &yfielddesc, &wfielddesc, &symfill, &symoutline)
+       ||
+       ((vis == 0) && tovis) /* if we didn't short-circuit in the above call to
+                                plot_readownertemplate, then we must have
+                                set a value for vis from our data. If it's zero
+                                AND our tovis parameter is supposed to undraw
+                                the plot, just return without doing anything. */
+       ||
+       array_getfields(elemtemplatesym, &elemtemplatecanvas,
+           &elemtemplate, &elemsize, xfielddesc, yfielddesc, wfielddesc,
+           &xonset, &yonset, &wonset))
+    {
+        return;
+    }
+
+    nelem = array->a_n; /* number of element in our array */
+    elem = (char *)array->a_vec; /* our array data, which is type char* so we
+                                    can jump around inside it and recast in a
                                     well-defined manner */
 
-    if (tovis != 0) /* either draw it for the first time or update the data */
+    /* now it's time to draw or go home. */
+    if (tovis == VIS_FIRSTTIME || tovis == VIS_UPDATE)
     {
             /* compare data argument to the data field of our scalar. If it's
                the same then we're plotting on behalf of an array field inside
                a scalar. If not then we are nested inside another data structure
                array.
                
-               Now let's make it even more complicated: Garrays from the
+               now let's make it even more complicated: Garrays from the
                "Put" menu contain a scalar that draws the plot. So here are
                our choices:
 
@@ -6137,15 +6248,19 @@ static void plot_vis(t_gobj *z, t_glist *glist, t_glist *parentglist,
                * plotting an array for a garray: !in_array
             */ 
         int in_array = (sc->sc_vec == data) ? 0 : 1;
-            /* For the newer [draw] commands we forgo the complicated vis
+
+            /* for the newer [draw] commands we forgo the complicated vis
                flag. So if [plot] points to a template that has [draw] commands
                we will draw them further down... */
         int draw_scalars = plot_has_drawcommand(elemtemplatecanvas);
-            /* check if old 3-digit color field is being used... */
+
+            /* check if old, imprecise 3-digit color field is being used... */
         int dscolor = fielddesc_getfloat(&x->x_outlinecolor, template, data, 1);
         if (dscolor != 0)
         {
             char outline[20];
+                /* convert the screwy 3-digit format to the long-standard
+                   "#123456" format */
             numbertocolor(dscolor, outline);
             symoutline = gensym(outline);
         }
@@ -6157,91 +6272,162 @@ static void plot_vis(t_gobj *z, t_glist *glist, t_glist *parentglist,
             /* handle the newfangled fill color for garray bar graphs */
         if (symfill == &s_) symfill = gensym("#000000");
 
-        t_float xscale = glist_xtopixels(glist, 1) - glist_xtopixels(glist, 0);
-        t_float yscale = glist_ytopixels(glist, 1) - glist_ytopixels(glist, 0);
-        t_float x_inverse = 1 / xscale;
-        t_float y_inverse = 1 / yscale; /* for the stroke-width */
+//        t_float xscale = glist_xtopixels(glist, 1) - glist_xtopixels(glist, 0);
+//        t_float yscale = glist_ytopixels(glist, 1) - glist_ytopixels(glist, 0);
+//        t_float x_inverse = 1 / xscale;
+//        t_float y_inverse = 1 / yscale; /* for the stroke-width */
+
+//        t_float transformed_linewidth_x = glist_dpixtodx(glist, 1.);
+//        t_float transformed_linewidth_y = glist_dpixtody(glist, linewidth);
+
 
-            /* First let's set the call to the GUI:
+            /* first let's set up the string for the call to the GUI:
                gui_plot_vis: called the first time we need to draw. This
                    will create new DOM elements.
                gui_plot_configure: this will just update the path data
             */
         char gui_call[MAXPDSTRING];
-        if (tovis == 1)
-        {
-            /* draw for the first time */
-            sprintf(gui_call, "gui_plot_vis");
-        }
-        else
-        {
-            /* just update the plot */
-            sprintf(gui_call, "gui_plot_configure");
-        }
+        sprintf(gui_call, VIS_FIRSTTIME ? "gui_plot_vis" :
+            "gui_plot_configure");
+
+            /* the following branches will now start incrementally building
+               some messages to send to the GUI.
 
-            /* the following branches will add some array arguments to the
-               GUI message-- one for the point data and another for the
-               tags */
+               BE CAREFUL HERE! If you interleave these incremental messages
+               with debugging messages to the GUI it won't work properly. Use
+               stderr if you need to debug beyond this point... */
 
+            /* bar graph and point styles */
         if (style == PLOTSTYLE_POINTS || style == PLOTSTYLE_BARS)
         {
-
+                /* point style doesn't have a stroke, so we set its
+                   fill to the outline color */
             symfill = (style == PLOTSTYLE_POINTS ? symoutline : symfill);
+
+                /* no idea what these are doing here. They're outside of the
+                   for loop scope below, yet they get reset to these values
+                   at the end of each loop. */
             t_float minyval = 1e20, maxyval = -1e20;
-            int ndrawn = 0;
+                /* since we're handling garrays-- which even in the common
+                   case can hold thousands or millions of elements-- we
+                   put a hard limit of PLOT_NMAX on the number of subsections
+                   we'll draw for the trace. */
+            int ndrawn = 0; /* number of trace segments we've drawn so far */
 
+                /* okay, let's start the call to the GUI... */
             gui_start_vmess(gui_call, "x", glist_getcanvas(glist));
 
+                /* first we'll build an array that contains path drawing
+                   commands and data. This will be the trace for the plot. */
             gui_start_array();
 
+                /* loop through the elements. For the case with no magic "x"
+                   (including garrays) we keep a running sum of our x position
+                   with xsum, starting at xloc which was specified in our
+                   parent [plot]. Later we could abstract xloc out and put
+                   it in the matrix... */
             for (xsum = xloc, i = 0; i < nelem; i++)
             {
-                t_float yval;
-                int ixpix, inextx, render;
-
-                if (xonset >= 0)
+                t_float yval; /* our y coordinate for a point in the plot,
+                                 still in user coordinates */
+                int xpix1, /* x1 pixel coordinate for the plotted point */
+                    xpix2, /* the x2 pixel coord for the next element */
+                    ypix1, /* same, for y coord */
+                    ypix2, /* same, for y2 coord */
+                    
+                    render; /* to selectively draw a point, see below */
+
+                if (xonset >= 0) /* if our template has the magic "x" field */
                 {
+                        /* the next statemend does the following:
+
+                           index into our array to find our element, then
+                           add xonset to find the value of our magic "x" field.
+                           Finally, cast to a float pointer and then
+                           get the value out.
+
+                           I'm fairly certain this isn't the correct way to
+                           cast the element to t_float. The original
+                           container is t_word, and sizeof(t_word*) is not
+                           guaranteed to be sizeof(t_float*)
+                        */
                     usexloc = xloc +
                         *(t_float *)((elem + elemsize * i) + xonset);
-                    ixpix = fielddesc_cvttocoord(xfielddesc, usexloc);
-                    inextx = ixpix + 2;
-                    /* we use 'render' as a stopgap to choose whether
-                       or not to draw this point in the trace. For
-                       templates that have an x field we always render */
+
+                        /* now let's convert the raw x value to a pixel
+                           value, where point (0,0) is either the top-
+                           left corner of the GOP or the top-left corner
+                           of a canvas window. */
+                    xpix1 = glist_xtopixels2(glist,
+                        fielddesc_cvttocoord(xfielddesc, usexloc));
+
+                        /* just make a "point" 2 pixels wide */
+                    xpix2 = xpix1 + 2;
+
+                        /* we use 'render' as a stopgap to choose whether
+                           or not to draw this point in the trace. For
+                           templates that have an x field we always render */
                     render = 1;
+
                 }
                 else
                 {
+                    /* for cases where there is not a magic "x" field, we
+                       keep a running tally of our xinc steps in the variable
+                       xsum. Then we set the position of our "point" to reach
+                       all the way to the beginning of the next point. This
+                       ends up stretching the points into steps and probably
+                       confusing the heck out of people who listen to sines
+                       while staring at a plot of steps. But that's the way
+                       Vanilla does it so we're kinda stuck with this. */
                     usexloc = xsum;
                     xsum += xinc;
-                    ixpix = (int)(glist_xtopixels(glist,
+                    xpix1 = (int)(glist_xtopixels2(glist,
                             fielddesc_cvttocoord(xfielddesc, usexloc)));
-                    inextx = (int)(glist_xtopixels(glist,
+                    xpix2 = (int)(glist_xtopixels2(glist,
                             fielddesc_cvttocoord(xfielddesc, xsum)));
 
-                    /* For y-only templates, we only render the point
-                       if its at a different x-coordinate than the
-                       previous one. (For example, if you try to fit
-                       a 44,100 point array into a 100 pixel wide
-                       graph.) We're doing the scaling on the GUI side,
-                       but we must still use glist_xtopixels in order
-                       to test for a new x-pixel value. */
-                    render = ixpix != inextx;
+                    /* for y-only templates, we only render the point if it's
+                       at a different x-coordinate than the previous one.
+                       (For example, if you try to fit a 44,100-point array
+                       into a 100 pixel wide graph.) */
+                    render = xpix1 != xpix2;
                 }
 
-                if (yonset >= 0)
-                    yval = yloc + *(t_float *)((elem + elemsize * i) + yonset);
-                else yval = 0;
-                if (yval > maxyval)
-                    maxyval = yval;
-                if (yval < minyval)
-                    minyval = yval;
-                if (i == nelem-1 || render)
+                    /* now let's draw the point. I don't understand why we
+                       need the special case for the final element-- that should
+                       be covered by the value of the render variable */
+                if (i == nelem - 1 || render)
                 {
-                    int py2 = 0;
+                        /* fetch the y value if we have one, or set it to zero
+                           if we don't. Add in the yloc-- as with xloc we could
+                           squirrel this away in the matrix but it's probably
+                           not necessary */
+                    if (yonset >= 0)
+                        yval = yloc +
+                            *(t_float *)((elem + elemsize * i) + yonset);
+                    else yval = 0;
+
+                        /* keep it in reasonable numeric bounds. Because we're
+                           scaling an already small range-- often -1 to 1-- to
+                           a larger pixel range, sending a wild value can end up
+                           growing it by several orders of magnitude */
+                    yval = CLIP(yval);
+
+                        /* we're clipping again manually? Why? It appears that
+                           either maxyval == minyval, or we overflowed above
+                           and the value for both is 0 */
+                    if (yval > maxyval)
+                        maxyval = yval;
+                    if (yval < minyval)
+                        minyval = yval;
+
+                    t_float py2 = 0;
                     if (style == PLOTSTYLE_POINTS)
-                        py2 = (int)fielddesc_cvttocoord(yfielddesc, maxyval)
-                                + linewidth - 1;
+                    {
+                        py2 = fielddesc_cvttocoord(yfielddesc, maxyval)
+                            + linewidth;
+                    }
                     else
                     {
                         if (glist->gl_isgraph && !glist->gl_havewindow)
@@ -6256,25 +6442,40 @@ static void plot_vis(t_gobj *z, t_glist *glist, t_glist *parentglist,
                             py2 = glist->gl_y2;
                         }
                     }
-                    int mex1 = fielddesc_cvttocoord(xfielddesc, usexloc);
+//fprintf(stderr, "usexloc is %g\n", usexloc);
+//fprintf(stderr, "usexloc after glist_xtopixelsx is %g\n", glist_xtopixels(glist, usexloc));
+//fprintf(stderr, "usexloc after glist_xtopixelsx2 is %g\n", glist_xtopixels2(glist, usexloc));
+//fprintf(stderr, "basey is %g\n", basey);
+                    t_float mex1 = fielddesc_cvttocoord(xfielddesc, usexloc);
+
+//                    int is_garray = 1;
+//                    if (is_garray && i == 0) mex1 += transformed_linewidth_x;
+
                     //t_float mey1 = fielddesc_cvttocoord(yfielddesc, minyval) - 1;
-                    int mex2 = fielddesc_cvttocoord(xfielddesc, xsum + x_inverse);
+//                    int mex2 = fielddesc_cvttocoord(xfielddesc, xsum + x_inverse);
+                    int mex2 = fielddesc_cvttocoord(xfielddesc, xsum);
+//                    t_float mey2 = style == PLOTSTYLE_POINTS ?
+//                        yval + y_inverse * linewidth : py2;
 
                     t_float mey2 = style == PLOTSTYLE_POINTS ?
-                        yval + y_inverse * linewidth : py2;
+                        yval + linewidth : py2;
 
+//fprintf(stderr, "ixpix is %d\n", ixpix);
+//fprintf(stderr, "inextx %d\n", inextx);
                     gui_s("M");
-                    gui_i(mex1);
-                    gui_f(yval);
+                    gui_i(xpix1);
+                    gui_i((int)glist_ytopixels2(glist, yval));
 
                     gui_s("H");
-                    gui_i(mex2);
-
+                    gui_i(xpix2);
+//fprintf(stderr, "mey2 is %g\n", mey2);
+//fprintf(stderr, "0 is %g\n", glist_ytopixels2(glist, 0.));
                     gui_s("V");
-                    gui_f(mey2);
+                    gui_i((int)glist_ytopixels2(glist, mey2));
+//                    gui_f(mey2);
 
                     gui_s("H");
-                    gui_i(mex1);
+                    gui_i(xpix1);
 
                     gui_s("z");
 
@@ -6282,12 +6483,12 @@ static void plot_vis(t_gobj *z, t_glist *glist, t_glist *parentglist,
                     minyval = 1e20;
                     maxyval = -1e20;
                 }
-                if (ndrawn > 2000 || ixpix >= 3000) break;
+                if (ndrawn > TRACE_NMAX || xpix1 >= 3000) break;
             }
 
             gui_end_array();
 
-            /* stroke and fill */
+                /* stroke and fill */
             gui_start_array();
             gui_s("fill");
             gui_s(symfill->s_name);
@@ -6301,7 +6502,7 @@ static void plot_vis(t_gobj *z, t_glist *glist, t_glist *parentglist,
             gui_s("non-scaling-stroke");
             gui_end_array();
 
-            /* tags */
+                /* tags */
             gui_start_array();
             char pbuf[MAXPDSTRING];
             char tbuf[MAXPDSTRING];
-- 
GitLab