View Raw SPL
/*****************************************************************************
*                                                                            *
*   VECCROSS.SPL  Copyright (C) 2022 DSP Development Corporation             *
*                               All Rights Reserved                          *
*                                                                            *
*   Author:       Randy Race                                                 *
*                                                                            *
*   Synopsis:     Computes the vector cross product                          *
*                                                                            *
*   Revisions:    17 May 2022  RRR  Creation                                 *
*                                                                            *
*****************************************************************************/


#if @HELP_VECCROSS

    VECCROSS

    Purpose: Computes the vector cross product.

    Syntax:  VECCROSS(a, b, dim)

                  a - A series, XY or XYZ series.

                  b - A series, XY or XYZ series.

                dim - Optional, the scalar direction, defaults
                      to 0, the dimension is determined by the
                      input series.

    Returns: A series, the coordinates of one or more a vectors that
             are perpendicular to the input vectors.

    Example:
             u = {3, -3, 1};
             v = {4,  9, 1};

             c = veccross(u, v);

             c == {-12,
                    -1,
                    39}

             The input and output coordinates are column-wise.

             To verify that vector C is perpendicular to both U and V:

             d1 = vecdot(c, u);
             d2 = vecdot(c, v);

             d1 == d2 == 0.0.

    Example:
             u = {{3, -3, 1}};
             v = {{4,  9, 1}};

             c = veccross(u, v);

             c == {{-12, -1, 39}}

             Same as above except the coordinates are row-wise.

    Example:
             W1: ravel(1..9, 3)
             W2: ravel(3..11, 3)
             W3: veccross(w1, w2)
             W4: veccross(w1, w2, 2)

             W3 == {{-6, 12, -6},
                    {-6, 12, -6},
                    {-6, 12, -6}}

             W4 == {{-6, 12, -6},
                    {-6, 12, -6},
                    {-6, 12, -6}}

            Both inputs are 3x3 arrays. Both cross products are computed with
            the coordinates going row-wise.

    Example:
             W1: ravel(1..9, 3)
             W2: ravel(3..11, 3)
             W3: veccross(w1, w2, 1)

             W3 == {{-2, -2, -2},
                    { 4,  4,  4},
                    {-2, -2, -2}}

             Same as above except the coordinates go column-wise.

    Remarks:
             The cross product of two vectors A and B is defined as:
                                            
             a x b = ||a|| * ||b|| * sin(theta) n

             where:
             
             theta is the angle between A and B in the plane that
             contains them.

             ||a|| and ||b|| are the magnitudes of A and B.

             n is the unit vector perpendicular to the plane that contains
             A and B.

             The cross product of two 3x1 vectors A and B can be computed with:

             a x b = {a[2]*b[3] - a[3] * b[2],
                      a[1]*b[3] - a[3] * b[1],                        
                      a[1]*b[2] - a[2] * b[1]}

             DIM determines the direction of the coordinates.

             DIM == 0, data dependent
             DIM == 1, column-wise
             DIM == 2, row-wise

             For DIM == 0, if the number of columns is 3, the coordinates
             are row-wise (i, j, k), otherwise the coordinates are column-wise.

             VECCROSS handles XY and XYZ series as vector inputs.

             See VECDOT to compute the vector cross product.

    See Also:
             Norm
             Sum
             Vecdot
#endif


/* dot product of two vectors */
veccross(a, b, dim)
{
        local vcross, nr, nc;

        if (argc < 3)
        {
                if (argc < 2)
                {
                        if (argc < 1) error("veccross - input series required");

                        /* build axis projection vector */
                        (nr, nc) = size(a);
                        b = ones(nr, nc);

                        if (nc > 1)
                        {
                                b[.., nc] = zeros(nr, 1);
                        }
                }

                /* use inputs for dimension */
                dim = 0;
        }

        /* handle XY and XYZ series */
        if (isxyz(a) || isxy(a))
        {
                a = ravel(xvals(a), yvals(a), zvals(a));
        }

        if (isxyz(b) || isxy(b))
        {
                b = ravel(xvals(b), yvals(b), zvals(b));
        }

        /* dimension */
        if (dim == 0)
        {
                dim = (numcols(a) == 3 || numcols(b) == 3) ? 2 : 1;
        }
                
        /* dot product */
        vcross = veccross_cross(a, b, dim, __FUNC__);

        return(vcross);
}


/* cross product */
veccross_cross(a, b, dim, func)
{
        local nra, nrb, nca, ncb, c;

        (nra, nca) = size(a);
        (nrb, ncb) = size(b);

        if (not(nra == nrb && nca == ncb))
        {
                error(sprintf("%s - input dimensions must be equal", func));
        }

        if (((dim == 1) && not(nra == 3)) || ((dim == 2) && not(nca == 3)))
        {
                error(sprintf("%s - input dimension must be 3 in cross product direction", func));
        }

        if (dim == 1)
        {
                c = {a[2,..] * b[3,..] - a[3,..] * b[2,..],
                         a[3,..] * b[1,..] - a[1,..] * b[3,..],
                         a[1,..] * b[2,..] - a[2,..] * b[1,..]};

                setcomment(c, "i j k", 1, 1);
        }
        else
        {
                c = {a[..,2] * b[..,3] - a[..,3] * b[..,2],
                         a[..,3] * b[..,1] - a[..,1] * b[..,3],
                         a[..,1] * b[..,2] - a[..,2] * b[..,1]};

                /* reshape */
                c = ravel(c, length(a));

                /* attributes */
                setcomment(c, "i", 1, 1);
                setcomment(c, "j", 1, 2);
                setcomment(c, "k", 1, 3);
        }

        return(c);
}