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

extern drawline(int, int, int, int);

/* Returns cosine of the angle between the vectors u and v. If it is
   negative then zero is returned. 
   Used for diffusion. */
angle cosangle(vector u, vector v)
{
	angle a;
	a=dot(u,v)/(norm(u)*norm(v));
	return a>=0.0 ? a : 0.0;
}

/* Returns the intersection point of the line 'li' and the plane 'pl'. */
vector planeintersect(line li, plane pl)
{
   return vadd(smul(dot(pl.n,vsub(pl.p,li.p))/dot(pl.n,li.k),li.k),li.p);
}

/* The reflection of the line 'li' in the plane 'pl' in the intersection
   point 'is' is returned. Make sure that 'is' really is the intersection
   of 'li' and 'pl'! */
line reflection(line li, plane pl, vector is)
{
  line ref;
  vector temp;
  temp=smul(2*dot(pl.n,vsub(li.p,pl.p))/dot(pl.n,pl.n),pl.n);
  ref.k=vadd(vsub(is,li.p),temp);
  ref.p=vsub(li.p,temp);
  return ref;
}

/* The point 'p' is first rotated 'spin' radians in the xy-plane, then
   'phi' radians in the xz-plane and last, but not least, 'theta' radians
   in the xy-plane (again). The rotated point 'p' is returned. */
vector rotatepoint(vector p, angle spin, angle phi, angle theta)
{
  vector m1,m2,m3;
  m1=vassign(cos(theta)*cos(spin)*sin(phi)-sin(theta)*sin(spin),
             -cos(theta)*sin(spin)*cos(phi)-sin(theta)*cos(spin),
             cos(theta)*sin(phi));
  m2=vassign(sin(theta)*cos(spin)*cos(phi)+cos(theta)*sin(spin),
             -sin(theta)*sin(spin)*cos(phi)+cos(theta)*cos(spin),
             sin(theta)*sin(phi));
  m3=vassign(-cos(spin)*sin(phi),
             sin(spin)*sin(phi),
             cos(phi));
  return vassign(dot(m1,p),dot(m2,p),dot(m3,p));
}

/* Returns the y value of the intersection between the line from (px,py) to
   (qx,qy) and the line x. By swapping x and y, it can be used to calculate
   the x value of the intersection between the same line and the line y.
   Used in 'clippedline'. */
int cllineis(int px, int py, int qx, int qy, int x)
{
  if (px==qx)
    return py;
  else
    return (qy-py)*(x-px)/(qx-px)+py;
}

/* This routine draws clipped lines. The line is drawn from (px,py) to
   (qx,qy). The 'max' and 'min' values describes the borders outside of which
   nothing is drawn. All values should be given in pixels.
   The function drawline() called in this routine must be defined somewhere
   else in the program, since line drawing is carried out in different ways
   on different systems... */
void clippedline(int px, int py, int qx, int qy, 
                 int minx, int miny, int maxx, int maxy)
{
  if ((px>maxx && qx>maxx) || (px<minx && qx<minx) ||
      (py>maxy && qy>maxy) || (py<miny && qy<miny))
    return;

  if (px>maxx) {
    py=cllineis(px,py,qx,qy,maxx);
    px=maxx;
  } else
  if (px<minx) {
    py=cllineis(px,py,qx,qy,minx);
    px=minx;
  }

  if (py>maxy) {
    px=cllineis(py,px,qy,qx,maxy);
    py=maxy;
  } else
  if (py<miny) {
    px=cllineis(py,px,qy,qx,miny);
    py=miny;
  }


  if (qx>maxx) {
    qy=cllineis(qx,qy,px,py,maxx);
    qx=maxx;
  } else
  if (qx<minx) {
    qy=cllineis(qx,qy,px,py,minx);
    qx=minx;
  }

  if (qy>maxy) {
    qx=cllineis(qy,qx,py,px,maxy);
    qy=maxy;
  } else
  if (qy<miny) {
    qx=cllineis(qy,qx,py,px,miny);
    qy=miny;
  }
  if (!(px>maxx || px<minx || py>maxy || py<miny ||
      qx>maxx || qx<minx || qy>maxy || qy<miny))
  drawline(px,py,qx,qy);
}

