/**********************************************************

                  File for vector math

 **********************************************************/

#include <math.h>
#include "qrt.h"

/* #define MATHDEBUG TRUE */
/* #define MATHMAIN TRUE */


/**********************************************************

    Returns pseudo random number between one and 100

 **********************************************************/

int PsRand() {
  static int val=43;

  val=(val*73+97);
  return(val%CNUM);
}

/**********************************************************
                                    -
                    Vector clear to 0

 **********************************************************/

VectEqZero(v)
  VECT_PTR v;
{
  v->x=v->y=v->z=0.0;
}


/**********************************************************
                   -    -       -       -
     Vector math:  V1 = V1 + k2 V2 + k3 V3

 **********************************************************/

VectAddMult(v1,k2,v2,k3,v3)
  VECT_PTR v1,v2,v3;
  float k2,k3;
{
  v1->x+=k2*(v2->x)+k3*(v3->x);
  v1->y+=k2*(v2->y)+k3*(v3->y);
  v1->z+=k2*(v2->z)+k3*(v3->z);
}

/**********************************************************
                   -      -
     Vector math:  V1 = - V2

 **********************************************************/

VectNegate(v1,v2)
  VECT_PTR v1,v2;
{
  v1->x = -(v2->x);
  v1->y = -(v2->y);
  v1->z = -(v2->z);
}


/**********************************************************
                   -    -    -
     Vector math:  V1 = V2 + V3

 **********************************************************/

VectorAdd(v1,v2,v3)
  VECT_PTR v1,v2,v3;
{
  v1->x=v2->x+v3->x;
  v1->y=v2->y+v3->y;
  v1->z=v2->z+v3->z;
}


/**********************************************************
                   -    -    -
     Vector math:  V1 = V2 * V3

 **********************************************************/

VectorMult(v1,v2,v3)
  VECT_PTR v1,v2,v3;
{
  v1->x=v2->x*v3->x;
  v1->y=v2->y*v3->y;
  v1->z=v2->z*v3->z;
}


/**********************************************************
                   -    -    -
     Vector math:  V1 = V2 - V3

 **********************************************************/

VecSubtract(v1,v2,v3)                              /* 1=2-3 */
  VECT_PTR v1,v2,v3;
{
  v1->x=v2->x-v3->x;
  v1->y=v2->y-v3->y;
  v1->z=v2->z-v3->z;
}


/**********************************************************
                   -      -
     Vector math:  V1 = k V1

 **********************************************************/

VectScale(v1,k,v2)                               /* 1=2*1 */
  VECT_PTR v1;
  float k;
{
  v1->x *= k;
  v1->y *= k;
  v1->z *= k;
}


/**********************************************************

                Color vector assignment

 **********************************************************/

SVectEQ(v1,v2)                    /* short vector v1=v2 */
  SVECT_PTR v1,v2;
{
  v1->r=v2->r;
  v1->g=v2->g;
  v1->b=v2->b;
}


/**********************************************************

                    Vector assignment

 **********************************************************/

VectEQ(v1,v2)                     /* long vector v1=v2 */
  VECT_PTR v1,v2;
{
  v1->x=v2->x;
  v1->y=v2->y;
  v1->z=v2->z;
}


/**********************************************************

                  Normalize vector V

 **********************************************************/

Normalize(v)
  VECT_PTR v;
{
  register float l;
  l=sqrt(DotProd((*v),(*v)));

  v->x/=l;
  v->y/=l;
  v->z/=l;
}


/**********************************************************
                   -    -    -
     Vector math:  V1 = V2 x V3

 **********************************************************/

CrossProd(v1,v2,v3)
  VECT_PTR v1,v2,v3;
{
  v1->x=v2->y*v3->z-v2->z*v3->y;
  v1->y=v2->z*v3->x-v2->x*v3->z;
  v1->z=v2->x*v3->y-v2->y*v3->x;
}


/**********************************************************

      Returns position vector given line structure
      and parameter T

 **********************************************************/

FindPos(pos,line2,t)      /* find position on parametric line 2 */
  VECT_PTR pos;
  OBJ_PTR  line2;
  float t;
{
# ifdef ROBUST
    if (line2->type!=LINE) Error(INTERNAL_ERROR,401);
# endif

  pos->x=line2->loc.x+line2->vect1.x*t;
  pos->y=line2->loc.y+line2->vect1.y*t;
  pos->z=line2->loc.z+line2->vect1.z*t;

# ifdef MATHDEBUG
    printf("FINDPOS: t=%f, Xout=%f, Yout=%f, Zout=%f\n",
            t,pos->x,pos->y,pos->z);
# endif
}

/**********************************************************

        Reflects vector IN about NORM to produce OUT

 **********************************************************/

Reflect(out,in,norm)
  VECT_PTR out,in,norm;
{
  float dot;

  dot = -DotProd((*in),(*norm));

# ifdef ROBUST                           /* CHECK THIS OUT */
    /* if (dot<0) Error (INTERNAL_ERROR,402); */
# endif

  VectEQ(out,in);
  VectAddMult(out,dot,norm,dot,norm);

# ifdef MATHDEBUG
    printf("REFLECT: in   x,y,z = %f %f %f\n",in->x,in->y,in->z);
    printf("         norm x,y,z = %f %f %f\n",norm->x,norm->y,norm->z);
    printf("         out  x,y,z = %f %f %f\n",out->x,out->y,out->z);
# endif
}


/**********************************************************

   Arctan of 2 numbers.  This *should* exist in the
   compiler library, but it's not there.

 **********************************************************/

float atan2w(x,y)
  float x,y;
{
  if (x==0) {
    if (y>0) return(PI2);
    return(-PI2);
  }

  if (x>0) return(atan(y/x));

  if (y>0) return(PI-atan(y/(-x)));

  return(-PI+atan(y/x));
}


/**********************************************************

                    DOUBLE ROTATION

   This is a really two multiplied transformation
   matricies, but this form is faster. The if statements
   rotate only if necessary.

 **********************************************************/

Rot12(invect,outvect,cos1,sin1,cos2,sin2)
  VECT_PTR invect, outvect;
  register float cos1, sin1, cos2, sin2;
{
#ifdef ROTATEFINISH

  VECTOR tempdir;

  /** Rotate once to YZ plane **/

  if ((cos1!=0) || (sin1!=0)) {

    tempdir.x = invect->x *  cos1 +
                invect->z * -sin1;

    tempdir.y = invect->y;

    tempdir.z = invect->x *  sin1 +
                invect->z *  cos1;
  } else {
    VectEQ(&tempdir,invect);
  }

  /** Rotate again to positive Y **/

  if ((cos2!=0) || (sin2!=0)) {

    outvect->x = tempdir.x;

    outvect->y = tempdir.y * -cos2 +
                 tempdir.z *  sin2;


    outvect->z = tempdir.y * -sin2 +
                 tempdir.z * -cos2;

  } else {
    VectEQ(outvect,&tempdir);
  }
#endif
}


/**********************************************************

                    DOUBLE ROTATION

       Same as above, but in reverse direction

 **********************************************************/

Rot21(invect,outvect,cos1,sin1,cos2,sin2)
  VECT_PTR invect, outvect;
  float cos1, sin1, cos2, sin2;
{
#ifdef ROTATEFINISH

  VECTOR tempdir;

  /** Rotate once from Y up direction **/

  if ((cos2!=0) || (sin2!=0)) {

    tempdir.x = invect->x;

    tempdir.y = invect->y *  cos2 +
                invect->z * -sin2;


    tempdir.z = invect->y *  sin2 +
                invect->z *  cos2;

  } else {
    VectEQ(&tempdir,invect);
  }

  /** Rotate again to arbitrary direction **/

  if ((cos1!=0) || (sin1!=0)) {

    outvect->x = tempdir.x * -cos1 +
                 tempdir.z *  sin1;

    outvect->y = tempdir.y;

    outvect->z = tempdir.x * -sin1 +
                 tempdir.z * -cos1;
  } else {
    VectEQ(outvect,&tempdir);
  }
#endif
}


/**********************************************************

      Main for mth.c - used ONLY to test functions.

 **********************************************************/

# ifdef MATHMAIN

Error() { }

main() {

  VECTOR in,out;
  float sin1, sin2, cos1, cos2;

  printf("in: ");
  scanf("%f %f %f",&(in.x),&(in.y),&(in.z));

  printf("sin1 cos1 sin2 cos2: ");
  scanf("%f %f %f %f",&sin1, &cos1, &sin2, &cos2);

  Rot12(&in,&out,cos1,sin1,cos2,sin2);

  printf("out12: %f %f %f\n",out.x,out.y,out.z);

  Rot21(&in,&out,cos1,sin1,cos2,sin2);
  printf("out21: %f %f %f\n",out.x,out.y,out.z);
}

# endif

