#include <math.h>
#include "libsx.h"
#include "crosshair.h"
#include "geodata.h"
#include "globals.h"
#include "kraftwerk.h"
#include "graph.h"
#include "naca.h"

#include "circle.bm"
#include "ellips.bm"
#include "wing.bm"
#include "square.bm"
#include "poly.bm"
#include "move.bm"
#include "kill.bm"
#include "zoom.bm"
#include "unzoom.bm"

#define SYMMETRIC 0
#define NON_SYMMETRIC 1
#define TO_SCALE 0
#define STRECHED 1


typedef struct {
  char *text;
  Widget label;
  Widget toggle;
} geoObjectUI;



typedef struct {
  int n;
  int type;
  int drawmode;
  float x[100];
  float y[100];
} geoObject;

geoObject *thing;
Widget outBNDR, innBNDR, intBNDR;
Widget closeB;

geoObjectUI objectsUI[] = {
                           {"outer"}, 
                           {"inner"}, 
                           {"internal"}, 
			   {"Square"},
			   {"Circle"},
			   {"Ellips"},
                           {"NACA0012"}, 
			   {"Polygon"},
			   {"Move"},
			   {"Kill"},
			   {"Zoom"},
			   {"UnZoom"}};
int nObj = 12;

geoObject naca0012 = {18, SYMMETRIC, TO_SCALE,
			{ 0.0,
			 .00351381,
			 .01346558,
                         .03066379,
                         .05517089,
                         .08673215,
                         .12514615,
                         .17041743,
                         .22262233,
                         .28171957,
                         .34769243,
                         .42050737,
                         .50013381,
                         .58655041,
                         .67974794,
                         .77972806,
                         .88648617,
                          1.0 },
                        { 0.0,
  		         .00919038,  
			 .01914215,
                         .02881318,
                         .03721619,
                         .04423213,
                         .05026549,
                         .05524749,
                         .05855709,
                         .06009519,
                         .05966640,
                         .05719906,
                         .05277705,
                         .04655302,
                         .03855282,
                         .02845609,
                         .01568145,
                          0.0}   
		};
geoObject square = {4, NON_SYMMETRIC, STRECHED,
		      {0., 1., 1., 0.},
		      {0., 0., 1., 1.} };
geoObject circle;
geoObject ellips;
geoObject move;
geoObject kill;

int first = 0;
int xlead, ylead;
int xtrail, ytrail;
Widget geowindow;

void killBoundary();
void getBoundaryScale(Widget w, void *data);
int clickedOnBoundary(int x, int y, int *segment, int *offset, int *nseg, int *this);
GEO_NODE *new_clickedOnBoundary(int x, int y);
void setAction(int doThis);



void donefcn( Widget w, void *nulldata)
{
  int hh=0, ww=0;

  SetButtonUpCB(drawWindow, NULL);
  SetButtonDownCB(drawWindow, NULL);
  SetMouseMotionCB(drawWindow, NULL);    
  deleteCrossHair();
  setAction(NORMAL);
  SetCurrentWindow(geowindow);
  CloseWindow();
  redisplay(w, hh, ww, nulldata);
}
void togglefcn(Widget w, void *data)
{
  int i, j, what[2];
  int hh=0, ww=0;
  j = 0;
  for( i = 0; i < nObj; i++){
    if( GetToggleState( objectsUI[i].toggle))
      what[j++] = i;
  }
  SetButtonDownCB(drawWindow, nacaDown);
  SetButtonUpCB(drawWindow, NULL);
  SetMouseMotionCB(drawWindow, nacaMotion);   
  first = 0;
  switch(what[0])
    {
    case 0:
      boundaryType = OUTER;
      break;
    case 1:
      boundaryType = INNER;
      break;
    case 2:
      boundaryType = INTERNAL;
      break;
    }
  switch(what[1])
    {
    case 3:
      thing = &square;
      setAction(DRAWING);
      break;
    case 4:
      thing = &circle;
      setAction(DRAWING);
      break;
    case 5:
      thing = &ellips;
      setAction(DRAWING);
      break;
    case 6:
      thing = &naca0012;
      setAction(DRAWING);
      break;
    case 7:
      inputBoundary(w, data);
      setAction(DRAWING);
      break;
    case 8:
      moveBoundary( w, data);
      setAction(MOVING);
      break;
    case 9:
      killBoundary();
      break;
    case 10:
      deleteCrossHair();
      SetMouseMotionCB(drawWindow, NULL);   
      setAction(ZOOMING);
      zoom(w, data);
      break;
    case 11:
      deleteCrossHair();
      SetMouseMotionCB(drawWindow, NULL);   
      SetButtonUpCB(drawWindow, NULL);
      SetButtonDownCB(drawWindow, NULL);
      unzoom(w, data);
      setAction(NORMAL);
      break;
    }
  redisplay(w, hh, ww, data);
}
void putUpGeoWindow()
{
  int i;
  geowindow = MakeWindow("Geometry", SAME_DISPLAY,  NONEXCLUSIVE_WINDOW);
  
  i = 0;
  objectsUI[i++].toggle = MakeToggle("  Outer  "   , TRUE , NULL, togglefcn, NULL); 
  objectsUI[i++].toggle = MakeToggle("  Inner  "   , FALSE,objectsUI[0].toggle , togglefcn, NULL);
  objectsUI[i++].toggle = MakeToggle(" Internal", FALSE, objectsUI[0].toggle, togglefcn, NULL); 

  for(i = 3; i < nObj; i++){
    if(i == 3)
      objectsUI[i].toggle = MakeToggle(NULL, TRUE, NULL, togglefcn, NULL);
    else
      objectsUI[i].toggle = MakeToggle(NULL, FALSE, objectsUI[3].toggle,
				       togglefcn, NULL);
  }
  closeB   = MakeButton("Close", donefcn, NULL);

  i = 3;
  SetWidgetBitmap(objectsUI[i++].toggle, square_bits, square_width, square_height);
  SetWidgetBitmap(objectsUI[i++].toggle, circle_bits, circle_width, circle_height);
  SetWidgetBitmap(objectsUI[i++].toggle, ellips_bits, ellips_width, ellips_height);
  SetWidgetBitmap(objectsUI[i++].toggle, wing_bits,   wing_width,   wing_height);
  SetWidgetBitmap(objectsUI[i++].toggle, poly_bits,   poly_width,   poly_height);
  SetWidgetBitmap(objectsUI[i++].toggle, move_bits,   move_width,   move_height);
  SetWidgetBitmap(objectsUI[i++].toggle, kill_bits,   kill_width,   kill_height);
  SetWidgetBitmap(objectsUI[i++].toggle, zoom_bits,   zoom_width,   zoom_height);
  SetWidgetBitmap(objectsUI[i++].toggle, unzoom_bits,   unzoom_width,   unzoom_height);

  for(i = 1; i < nObj; i++){
    SetWidgetPos(objectsUI[i].toggle, PLACE_UNDER, objectsUI[i-1].toggle, 
		 NO_CARE, NULL);
  }
  SetWidgetPos(closeB, PLACE_UNDER, objectsUI[nObj-1].toggle, NO_CARE, NULL);

  togglefcn(drawWindow, NULL);
  ShowDisplay();
}

void initCircle(geoObject *circle, int n, int id)
{
  int i;
  double fi;

  for(i = 0; i < n ; i++){
    fi = (double) 2 * 3.141592 * i / n;
    circle->x[i] = (float) cos(fi);
    circle->y[i] = (float) sin(fi);
  }
  circle->n = n ;
  circle->type = NON_SYMMETRIC;
  if(id == 0)
    circle->drawmode = STRECHED;
  else
    circle->drawmode = TO_SCALE;
}


void naca(Widget w, void *data)
{
  int hh=0, ww=0;
  first = 0;
  boundaryType = INNER;
  initCircle(&circle, 30, 1);
  initCircle(&ellips, 30, 0);
  thing = &square;
  thing = &naca0012; 
  putUpGeoWindow();
  SetButtonDownCB(drawWindow, nacaDown);
  SetMouseMotionCB(drawWindow, nacaMotion);   
  setAction(DRAWING);
  state = HAVE_BOUNDARY;
  redisplay(w, hh, ww, data);
}

void nacaMotion(Widget w, int xp, int yp, void *data)
{
  crossHair(xp,yp);
  if(state == HAVE_NOTHING){
    getBoundaryScale(w, data);
  }
  state = HAVE_BOUNDARY;
  if(first == 1){
    SetDrawMode(SANE_XOR);
    drawNaca(xlead, ylead, xtrail, ytrail);
    drawNaca(xlead, ylead, xp, yp);
    SetDrawMode(GXcopy);
    xtrail = xp;
    ytrail = yp;
  }
}
double maxsize(int comp)
{
  double max, cmp;
  int i;

  max = -1000;
  for( i = 0; i < thing->n; i++){
    if(comp == 0)
      cmp = thing->x[i];
    else
      cmp = thing->y[i];
    cmp = sqrt(cmp*cmp);
    if( cmp > max)
      max = cmp;
  }
  return max;

}

void nacaDown(Widget w, int button, int x, int y, void *data)
{
  double l, lx, ly, ca, sa, xx, yy;
  float x1, y1, x2, y2;
  double lp, lpx, lpy;
  int  xp, yp;
  int nb, i;
  float xphys, yphys;

  PTS_NODE *p0, *p1, *p2;
  GEO_NODE *g;

  if( first == 0){
    first = 1;
    xlead = x;
    ylead = y;
    xtrail = x;
    ytrail = y;
  }
  else{
    first = 0;
    SetButtonDownCB(drawWindow, NULL);
    SetMouseMotionCB(drawWindow, NULL);   
    deleteCrossHair();

    g = new_bnd();
    g->type = boundaryType;

    pix2phys(xlead, ylead, &x1, &y1);
    pix2phys(x, y, &x2, &y2);

    if(thing->drawmode == TO_SCALE){
      l = sqrt((double) (xlead-x)*(xlead-x) + (ylead-y)*(ylead-y));
      l = l / maxsize(0);
      if(l == 0.0)
	l = .000001;
      lx = l;
      ly = l;
      lp = sqrt((double) (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
      lp = lp / maxsize(0);
      lpx = lp;
      lpy = lp;
      ca = (double) (x-xlead) / l;
      sa = (double) (y-ylead) / l;
    }
    else{
      lx = (double) (x - xlead )/maxsize(0);
      ly = (double) (y - ylead )/maxsize(1);
      ca = 1.;
      sa = 0.;
      lpx = (x2 - x1) / (double) maxsize(0);
      lpy = (y2 - y1) / (double) maxsize(1);
    }

    i = 0;
    xx =  lx * thing->x[i];
    yy =  ly * thing->y[i];
    x2 =  (float) lpx * thing->x[i];
    y2 =  -(float) lpy * thing->y[i];
    xp = (int) (xx*ca - yy*sa + xlead);
    yp = (int) (xx*sa + yy*ca + ylead);
    xphys = (float) (x2*ca - y2*sa + x1);
    yphys = (float) (-x2*sa - y2*ca + y1);
    p0 = add_pnt(xphys, yphys);
    p1 = p0;
    for(i = 1; i < thing->n; i++){
      xx =  lx * thing->x[i];
      yy =  ly * thing->y[i];
      x2 =  (float) lpx * thing->x[i];
      y2 =  -(float) lpy * thing->y[i];
      xp = (int) (xx*ca - yy*sa + xlead);
      yp = (int) (xx*sa + yy*ca + ylead);

      xphys = (float) (x2*ca - y2*sa + x1);
      yphys = (float) (-x2*sa - y2*ca + y1);
      p2 = add_pnt(xphys, yphys);
      add_seg(p1, p2, g);
      p1 = p2;
    }
    if(thing->type == SYMMETRIC){
      for(i = thing->n - 2; i > 0; i--){
	xx =   lx * thing->x[i];
	yy = - ly * thing->y[i];
	x2 =   (float) lpx * thing->x[i];
	y2 =  (float) lpy * thing->y[i];
	xp = (int) (xx*ca - yy*sa + xlead);
	yp = (int) (xx*sa + yy*ca + ylead);

	xphys = (float) (x2*ca - y2*sa + x1);
	yphys = (float) (-x2*sa - y2*ca + y1);
	p2 = add_pnt(xphys, yphys);
	add_seg(p1, p2, g);
	p1 = p2;

      }
    }    
    add_seg(p1, p0, g);

    state = HAVE_BOUNDARY;
    redisplay(w, xx, yy, data);
    SetButtonDownCB(drawWindow, nacaDown);
    SetMouseMotionCB(drawWindow, nacaMotion);   
  }
}



void drawNaca(int x1, int y1, int x2, int y2)
{
  double l, lx, ly, ca, sa;
  int xx1, yy1, xx2, yy2;
  int x, y;
  int i;

  x1++;
  y1++;
  x2--;
  y2--;

  if(thing->drawmode == TO_SCALE){
    l = sqrt((double) (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
    l = l / maxsize(0);
    lx = l;
    ly = l;
    ca = (double) (x2-x1) / l;
    sa = (double) (y2-y1) / l;
  }
  else{
    ca = 1.;
    sa = 0.;
    lx = (double) (x2 -x1)/maxsize(0);
    ly = (double) (y2 -y1)/maxsize(1);
  }
  x = (int) lx * thing->x[0] ;
  y = (int) ly * thing->y[0] ;
  xx1 = (int) (x*ca - y*sa + x1);
  yy1 = (int) (x*sa + y*ca + y1);

  for(i = 0; i < thing->n; i++){
    x = (int) lx * thing->x[i];
    y = (int) ly * thing->y[i];
    xx2 = (int) (x*ca - y*sa + x1);
    yy2 = (int) (x*sa + y*ca + y1);
    myDrawLine(xx1, yy1, xx2, yy2);
    xx1 = xx2;
    yy1 = yy2;
  }
  if(thing->type == SYMMETRIC){
    x = (int) lx * thing->x[0] ;
    y = - (int) ly * thing->y[0] ;
    xx1 = (int) (x*ca - y*sa + x1);
    yy1 = (int) (x*sa + y*ca + y1);

    for(i = 0; i < thing->n; i++){
      x = (int) lx * thing->x[i];
      y = - (int) ly * thing->y[i];
      xx2 = (int) (x*ca - y*sa + x1);
      yy2 = (int) (x*sa + y*ca + y1);
      myDrawLine(xx1, yy1, xx2, yy2);
      xx1 = xx2;
      yy1 = yy2;
    }
  }
  else{
    x = (int) lx * thing->x[0];
    y = (int) ly * thing->y[0];
    xx2 = (int) (x*ca - y*sa + x1);
    yy2 = (int) (x*sa + y*ca + y1);
    myDrawLine(xx1, yy1, xx2, yy2);
  }
}


void killMouseDown(Widget w, int button, int x, int y,  void *data)
{
  int n;
  int ioff;
  int segment, this;
  GEO_NODE *g;

  g = new_clickedOnBoundary(x, y);
  if(g  != NULL){
    rm_bnd(g);
    if(number_of_boundaries() == 0)
      state = HAVE_SCALE;
    redisplay(w, x, y, data);
  }


}
void killBoundary()
{
  first = 0;
  setAction(DELETING);
  SetButtonUpCB(drawWindow, NULL);
  SetButtonDownCB(drawWindow, killMouseDown);
  SetMouseMotionCB(drawWindow, nacaMotion);    
}


syntax highlighted by Code2HTML, v. 0.9.1