/*************************************************************
*  This file is part of the Surface Evolver source code.     *
*  Programmer:  Ken Brakke, brakke@geom.umn.edu              *
*************************************************************/

/* NeXT graphics module for evolver */

#include "include.h"
#import "evolverView.h"
#import <dpsclient/wraps.h>

NXRect theRect;  /* visible rectangle */
float xscale,yscale,maxx,maxy,xbase,ybase;

void next_init()
{
  maxx = theRect.size.width;
  maxy = theRect.size.height;
  if ( maxx > maxy ) xscale = yscale = maxy/3.0;
  else xscale = yscale = maxx/3.0;
  xbase = theRect.origin.x + maxx/2;
  ybase = theRect.origin.y+maxy/2;
  PSsetgray(1.0);
  PSrectfill(theRect.origin.x,theRect.origin.y,maxx,maxy);  /* clear */
}

void next_finish()
{
}

void nextgraph_edge(t)
struct tsort *t;
{
  PSnewpath();
  PSmoveto(t->x[0][0]*xscale+xbase,t->x[0][1]*yscale+ybase);
  PSlineto(t->x[1][0]*xscale+xbase,t->x[1][1]*yscale+ybase);
  PSsetgray(0.0);
  PSstroke();
}

void nextgraph_facet(t)
struct tsort *t;
{
  PSnewpath();
  PSmoveto(t->x[0][0]*xscale+xbase,t->x[0][1]*yscale+ybase);
  PSlineto(t->x[1][0]*xscale+xbase,t->x[1][1]*yscale+ybase);
  PSlineto(t->x[2][0]*xscale+xbase,t->x[2][1]*yscale+ybase);
    {
    double denom,cosine;
    denom = sqrt(dotf(t->normal,t->normal,3));
    if ( denom == 0.0 ) return;
    cosine = t->normal[1]/denom;
    if ( t->normal[2] < (float)0.0 ) cosine = -cosine;
    PSsetgray(.5 + .4*cosine);
    }
  PSfill();
  PSnewpath();
  PSmoveto(t->x[0][0]*xscale+xbase,t->x[0][1]*yscale+ybase);
  PSlineto(t->x[1][0]*xscale+xbase,t->x[1][1]*yscale+ybase);
  PSlineto(t->x[2][0]*xscale+xbase,t->x[2][1]*yscale+ybase);
  PSclosepath();
  PSsetgray(0.0);
  PSstroke();
}


void display()
{  init_graphics = next_init;
  finish_graphics = next_finish;
  if ( web.dimension == STRING )
    {
      graph_start = init_graphics;
      graph_edge  = painter_edge;
      display_edge = nextgraph_edge;
      graph_end   = null_function;
    }
  else
    { 
      graph_start = painter_start;
      graph_edge  = painter_edge;
      display_edge = nextgraph_edge;
      graph_facet = painter_facet;
      display_facet = nextgraph_facet;
      graph_end = painter_end;
    }
  
  graphgen();
}

/* rotates CTM according to how mouse dragged */
void fix_ctm(dx,dy)
double dx,dy;
{
  REAL **rot = dmatrix(0,4,0,4);
  double alpha;  /* angle around axis */
  double theta;   /* tilt of rotation axis */
  
  alpha = sqrt(dx*dx + dy*dy)/300;  /* one radian per 300 pixels */
  if ( dx == 0.0 ) 
    { if ( dy > 0.0 ) theta = M_PI/2;
      else if ( dy < 0.0 ) theta = -M_PI/2;
      else return;  /* no change */
    }
   else 
    { theta = atan(dy/dx);
      if ( dx < 0.0 ) alpha = - alpha;
    }
   rot[3][3] = 1.0;  /* homogeneous */
   
   /* tilt axis */
   rot[0][0] = 1;
   rot[1][1] = rot[2][2] = cos(theta);
   rot[1][2] = sin(theta);
   rot[2][1] = -sin(theta);
   mat_mult(rot,view,view,4,4,4);
   
   /* rotate */
   rot[0][0] = rot[1][1] = cos(alpha);
   rot[0][1] = -sin(alpha);
   rot[1][0] = sin(alpha);
   rot[2][2] = 1;
   rot[1][2] = rot[2][1] = 0;
   mat_mult(rot,view,view,4,4,4);
   
   /* untilt axis */
   rot[0][0] = 1;
   rot[1][1] = rot[2][2] = cos(theta);
   rot[1][2] = -sin(theta);
   rot[2][1] = sin(theta);
   rot[0][1] = rot[1][0] = 0.0;
   mat_mult(rot,view,view,4,4,4);
   
   free_matrix(rot);
}

   
/* finds closest vertex on screen */
vertex_id select_point(NXPoint *spot)
{
  vertex_id v_id=NULLID, v;
  double dx,dy,dist,mindist = 1e10;
  FOR_ALL_VERTICES(v)
   { int j;
     REAL a[MAXCOORD+1],b[MAXCOORD+1];
     REAL *x = get_coord(v);
     
     for ( j = 0 ; j < web.sdim ; j++ ) a[j] = x[j];
     a[web.sdim] = 1.0;
     matvec_mul(view,a,b,web.sdim+1,web.sdim+1);
     dx = spot->x+1 - (b[1]*xscale + xbase);
     dy = spot->y-7 - (b[2]*yscale + ybase);
     dist = dx*dx + dy*dy;
     if ( dist < mindist )
        { mindist = dist; 
	  v_id = v;
	}
   }
  return v_id;
}

   
/* plots one highlighted vertex */
void highlight_vertex(vertex_id v_id)
{
     REAL a[MAXCOORD+1],b[MAXCOORD+1];
     REAL *x = get_coord(v_id);
     NXPoint spot;
     int j;
     
     for ( j = 0 ; j < web.sdim ; j++ ) a[j] = x[j];
     a[web.sdim] = 1.0;
     matvec_mul(view,a,b,web.sdim+1,web.sdim+1);
     spot.x = (b[1]*xscale + xbase);
     spot.y = (b[2]*yscale + ybase);
     PSsetgray(0.0);
     PSrectfill(spot.x-2,spot.y-2,4.0,4.0);
}

/* finds edge from endpoints */
edge_id select_edge(vertex_id *v)
{ edge_id e_id;
  
  FOR_ALL_EDGES(e_id)
   { vertex_id tail,head;
     tail = get_edge_tailv(e_id);
     head = get_edge_headv(e_id);
     if ( (tail == v[0]) && (head == v[1]) ) return e_id;
     if ( (tail == v[1]) && (head == v[0]) ) return inverse_id(e_id);
   }
  return NULLID;  /* not found */
}

facet_id select_facet(vertex_id *v)
{ facet_id f_id;
  edge_id e_id;
  facetedge_id fe_start,fe;

   e_id = select_edge(v);  /* edge for two points */
   if ( !valid_id(e_id) ) return NULLID;
   fe_start = get_edge_fe(e_id);
   if ( !valid_id(fe_start) ) return NULLID;
   for ( fe = fe_start ; ; )
     { if ( v[2] == get_fe_headv(get_next_edge(fe)) ) return get_fe_facet(fe);
       fe = get_next_facet(fe);       
       if ( fe == fe_start ) break;
     }
   return NULLID;
}
 
  
