View Raw SPL
/*****************************************************************************
*                                                                            *
*   WINCUT.SPL   Copyright (C) 2025 DSP Development Corporation              *
*                               All Rights Reserved                          *
*                                                                            *
*   Author:      Randy Race                                                  *
*                                                                            *
*   Synopsis:    Extracts series based on the displayed portion of a Window  *
*                                                                            *
*   Revisions:   30 Jul 2025  RRR  Creation - from cut.spl                   *
*                                                                            *
*****************************************************************************/

#if @HELP_WINCUT

    WINCUT

    Purpose: Extracts a series based on the displayed contents of a Window.

    Syntax:  WINCUT(srcwin, series, cutxy, zeropad)

              srcwin - A window, the source window to determine the
                       extraction range.

              series - A series, the target series to extract from.

              cutxy  - Optional. An integer, 1: cut using both the x and y
                       displayed range, 0: cut using the x range only (default).

             zeropad - Optional. An integer, 1: pad beginning and/or end
                       points with zeros if cut range beyond the series
                       size, 0: limit cut range to series extent (default).

    Returns: A series or array

    Example:
             W1: gnorm(1000, 1/1000);setx(.2, .5)
             W2: cumsum(w1)
             W3: wincut(W1, W2)

             W3 contains the data in W2 that is in the display range of W1.

    Example:
             W1: gnorm(1000, 1/1000);sety(-0.5, 1.5)
             W2: gnorm(1000, 1/1000)
             W3: wincut(W1, W2)
             W4: wincut(W1, W2, 1)

             W3 contains the same data as W2, but W4 contains the Y extracted
             portion of the data displayed in W1. The Y values of W4 range
             from -0.5 to 1.5.

    Example:
             W1: gnorm(1000, 1/1000);setx(-0.5, 1.5)
             W2: cumsum(w1)
             W3: wincut(W1, W2, 0, 0)
             W4: wincut(W1, W2, 0, 1)

             W3 contains the same data as W2 because the display range of W1
             is longer than the data extent of W2. However, W4 pads the starting
             and ending values of W2 with zeros to produce a series that extends
             from -0.5 to 1.5.

    Remarks:
             Wincut works properly on arrays and images.

             The ZEROPAD option only applies to series.

             See CUT to extract the displayed portion of a window.

    See Also:
             Cut
             Extract
             Setvport
#endif


/* extract series based on displayed portion of a window */
wincut(srcwin, targ = refseries(w0), cutxy = 0, zeropad = 0)
{
        local s;

        if ((argc < 1) || not(iswindow(srcwin)))
        {
                error(sprintf("%s - source window required", __FUNC__));
        }

        if (not(isarray(targ)))
        {
                error(sprintf("%s - target series required", __FUNC__));
        }

        /* extract */
        s = wincut_cut(srcwin, targ, cutxy, zeropad);
        
        return(s);
}


/* core extracter */
wincut_cut(src, targ, cutxy, zeropad)
{
        local nr, nc, s;

        if (not(iswindow(src)))
        {
                error(sprintf("%s - Window Required", __CALLER__));
        }

        (nr, nc) = size(targ);

        if (nc > 1 && not(ischart(targ)))
        {
                /* stripchart */
                if (isstripchart(targ))
                {
                        s = wincut_stripchart(src, targ, cutxy, zeropad, nr, nc);
                }
                else if (isxy(targ))
                {
                        /* XY */
                        s = wincut_xy(src, targ, cutxy, zeropad, nr, nc);
                }
                else if (isxyz(targ))
                {
                        /* XYZ */
                        s = wincut_xy(src, targ, 1, zeropad, nr, nc);
                }
                else
                {
                        /* array */
                        s = wincut_array(src, targ, cutxy, zeropad, nr, nc);
                }
        }
        else
        {
                s = wincut_interval(src, targ, cutxy, zeropad, nr, nc);
        }

        return(s);
}


/* swap lo to hi */
wincut_swap(a, b)
{
        if (a > b)
        {
                return(b, a);
        }
        else
        {
                return(a, b);
        }
}


/* cut XY window */
wincut_xy(src, targ, cutxy, zeropad, nr, nc)
{
        local ixl, ixr, s;

        /* X edges */
        ixl = getxl(src);
        ixr = getxr(src);
                        
        (ixl, ixr) = wincut_swap(ixl, ixr);

        /* Y edges */
        iyb = getyb(src);
        iyt = getyt(src);
                                
        (iyb, iyt) = wincut_swap(iyb, iyt);

        /* cut series */
        s = wincut_xy_series(targ, ixl, ixr, iyb, iyt, cutxy, zeropad);

        return(s);
}


/* cut XY series */
ITERATE wincut_xy_series(s, ixl, ixr, iyb, iyt, cutxy, zeropad)
{
        local x;

        if (not(isxy(s)) || isxymonotonic(s))
        {
                /* handles XY, offset set to actual series value */
                s = xextract(s, ixl, ixr, nan, 1, zeropad);
        }
        else
        {
                /* non-monotonic in X */
                x = xvals(s);

                /* delete x values out of window range */
                s = delete(s, x < ixl || x > ixr);
        }

        if (cutxy)
        {
                /* delete y values out of window range */
                y = yvals(s);
                                
                s = delete(s, y < iyb || y > iyt);
        }

        return(s);
}


/* cut array */
wincut_array(src, targ, cutxy, zeropad, nr, nc)
{
        local ptype, ixl, ixr, tmp, s = {};

        if (nc > 1)
        {
                ptype = getplottype(src);

                if (ptype > 0 && ptype < 6)
                {
                        /* waterfall, contour, density, z or image */
                        ixl = xtoidx(src, getxl(src), 1);
                        ixr = xtoidx(src, getxr(src), 1);

                        iyb = castint(ceil( (getyb(src) - yoffset(src)) / deltay(src)) + 1);
                        iyt = castint(floor((getyt(src) - yoffset(src)) / deltay(src)) + 1);

                        if (iyb < 1)  iyb = 1;
                        if (iyb > nc) iyb = nc;

                        if (iyt < 1)  iyt = 1;
                        if (iyt > nc) iyt = nc;

                        (iyb, iyt) = wincut_swap(iyb, iyt);

                        if (ixl == ixr && ixr < nr) ixr++;
                        if (iyb == iyt && iyt < nc) iyt++;

                        /* extract region */
                        s = targ[ixl..ixr, iyb..iyt];
                }
                else
                {
                        s = wincut_interval(src, targ, cutxy, zeropad, nr, nc);
                }
        }

        return(s);
}


/* cut interval series */
ITERATE wincut_interval(src, targ, cutxy, zeropad, nr, nc)
{
        local iyb, iyt, retarg, s = {};

        if (nr > 0)
        {
                retarg = not(zeropad);

                /* extract, offset set to actual series value */
                s = xextract(targ, getxl(src), getxr(src), nan, retarg, zeropad);
        
                if (cutxy)
                {
                        /* clip y values */
                        iyb = getyb(src);
                        iyt = getyt(src);
                        
                        (iyb, iyt) = wincut_swap(iyb, iyt);

                        s = clip(s, iyb, iyt);
                }
        }

        return(s);
}


/* cut stripchart */
wincut_stripchart(src, targ, cutxy, zeropad, nr, nc)
{
        local s;

        /* reset autoranging */
        setxauto(src, -1, -1);
        setyauto(src, -1, -1);

        if (nc == numitems(targ))
        {
                /* all traces are interval */
                s = wincut_interval(src, targ, cutxy, zeropad, nr, nc);
        }
        else
        {
                s = wincut_xy(src, targ, cutxy, zeropad, nr, nc);
        }

        return(s);
}