/****************************************************************
 *                                                              *
 *                        I C A O   M a p  -                    *
 *                                                              *
 *             A n   A v i a t i o n   U t i l i t y            *
 *                                                              *
 *                                                              *
 *            Copyright (C) 1993, 1994  Martin Pauly            *
 *                                                              *
 *                   N e x t   V e r s i o n                    *
 *                                                              *
 *       Copyright (C) 1994  Stefan Leuker & Oliver Meyer       *
 *                                                              *
 *   This file may be freely distributed only if it includes    *
 *                the above copyright notice.                   *
 *                                                              *
 ****************************************************************/

#import "mapobjects.h"
#import "geometry.h"
#import <dpsclient/dpsNeXT.h>
#import <appkit/appkit.h>


/*
   this is where the display of currently visible objects is handled
*/

/* current route to be drawn */

int drawroutenumpoints = 0;
LOCATION drawroutepoints[100];

int visiblelist[2000];
int visiblenumber;
static int px[10000], py[10000];   /* global because of size */

#define max(a,b) (a>b)?a:b

OBJECT *saveobj;


/* flags for objects to be visible (1) or not (0) */

int vis_com = 1;         /* communications */
int vis_roads = 1;       /* roads */
int vis_airspace = 1;    /* airspace structure */
int vis_cities = 1;      /* cities */
int vis_waypoints = 1;   /* waypoints */
int vis_airfield = 1;    /* smaller airfields */
int vis_water = 1;       /* rivers, lakes */
int vis_villages = 1;    /* villages */


char *visstring[] = {"Intl. Airports", "Airports", "Public Airfields",
  		       "Special Airfields", "Glider Sites", "Heliports",
  		       "Ballon Sites", "VORs", "NDBs", "Obstacles",
  		       "Reporting Points", "CTRs", "CVFRs", "Rivers", "Lakes",
	 		       "Highways", "Roads", "Towns", "Villages", "Waypoints",
	 		       "Intl. Borders", "State Borders", "Islands"};
int  visobj[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 
                 1, 1, 1};
int  numvis = sizeof (visstring) / sizeof (char*);




/* init pieces */

void initmapobjects()
{
  /* do nothing at the moment... */
}


/* make integer window coordinates from LOCATION */

void internal2window (LOCATION point, int *x, int *y)
{
  double xcm, ycm;

  internal2cm (point, &xcm, &ycm);

  *x = (int) (xcm*mapWidth/mapWidthcm+mapWidth/2);
  *y = (int) -(ycm*mapHeight/mapHeightcm-mapHeight/2);
}


/* make internal format from integer window coordinates */

LOCATION window2internal (int x, int y)
{
  double xcm, ycm;

  xcm = ((double)x-mapWidth/2)/mapWidth*mapWidthcm;
  ycm = ((double)mapHeight/2-y)/mapHeight*mapHeightcm;

  return cm2internal (xcm, ycm);
}


/* get distance in km between two window coordinates */

double dist (int x1, int y1, int x2, int y2)
{
  LOCATION a, b;

  a = window2internal (x1, y1);
  b = window2internal (x2, y2);

  return distance (a, b);
}


/* check if a point is inside the diplayed area (1) or not (0) */

int isvisible (LOCATION point)
{
  return (point.latitude > bottom) 
      && (point.latitude < top) 
      && (point.longitude > left) 
      && (point.longitude < right);
}



/*
  return piece number in which location appears
*/

int piecenumber (LOCATION loc)
{
  int x, y, pn;
  
  x = (int) ((double) (loc.longitude - left) * HOR_SLICES / (right - left));
  y = (int) ((double) (loc.latitude - top) * VER_SLICES / (bottom - top));

  pn = x + HOR_SLICES * y;

  return pn;
}


/*
   go through object list and check which objects are currently
   visible. put these objects into a list.
*/

void findvisibleobjects()
{
  int i, j, flag, pn, visible, t;

  visiblenumber = 0;


  for (i=0; i<=objectno; i++)
    {
      objectlist[i]->piece = -1;   /* default: in no piece */

      /* check if user wants to see that type of object */



/*      if ((objectlist[i]->type < O_VOR) ||    
	  ((objectlist[i]->type / 100 == 1) && (vis_com)) ||
	  ((objectlist[i]->type / 100 == 2) && (1)) ||  
	  ((objectlist[i]->type / 100 == 3) && (vis_airspace)) ||
	  ((objectlist[i]->type / 100 == 4) && (vis_waypoints)) ||
	  ((objectlist[i]->type / 100 == 10) && (vis_roads)) ||
	  ((objectlist[i]->type / 100 == 20) && (1)))    */

      visible = 0;
      t = objectlist[i]->type;
      
      if ((t == O_INTLAIRPORT) && visobj[0])
	visible = 1;
      if ((t >= O_AIRPORT) && (t <= O_AIRPORT_MIL) && visobj[1])
	visible = 1;
      if ((t == O_AIRFIELD) && visobj[2])
	visible = 1;
      if ((t == O_SPECIAL_AIRFIELD) && visobj[3])
	visible = 1;
      if ((t >= O_HELIPORT) && (t <= O_HELIPORT_AMB) && visobj[5])
	visible = 1;
      if ((t >= O_GLIDER_SITE) && (t <= O_HANG_GLIDER_SITE) && visobj[4])
	visible = 1;
      if ((t >= O_PARACHUTE_JUMPING_SITE) && (t <= O_FREE_BALLON_SITE) && visobj[6])
	visible = 1;
      if ((t >= O_VOR) && (t <= O_TACAN) && visobj[7])
	visible = 1;
      if ((t >= O_NDB) && (t <= O_BASIC_RADIO_FACILITY) && visobj[8])
	visible = 1;
      if ((t >= O_OBSTRUCTION) && (t <= O_AERO_GROUND_LIGHT) && visobj[9])
	visible = 1;
      if ((t == O_REPORTING_POINT) && visobj[10])
	visible = 1;
      if ((t == O_CTR) && visobj[11])
	visible = 1;
      if ((t == O_CVFR) && visobj[12])
	visible = 1;
      if ((t == O_RIVER) && visobj[13])
	visible = 1;
      if ((t == O_LAKE) && visobj[14])
	visible = 1;
      if ((t == O_HIGHWAY) && visobj[15])
	visible = 1;
      if ((t == O_ROAD) && visobj[16])
	visible = 1;
      if ((t == O_TOWN) && visobj[17])
	visible = 1;
      if ((t == O_VILLAGE) && visobj[18])
	visible = 1;
      if ((t == O_WAYPOINT) && visobj[19])
	visible = 1;
      if ((t == O_BORDER) && visobj[20])
	visible = 1;
      if ((t == O_STATE_BORDER) && visobj[21])
	visible = 1;
      if ((t == O_ISLAND) && visobj[22])
	visible = 1;

      if ((t == O_ISOGONE))
	visible = 1;

      if (visible)
	{
	  if (isvisible (objectlist[i]->location))
	    {
	      visiblelist[visiblenumber] = i;
	      visiblenumber++;
	      
	      /* save piece number of objects */
	      
	      pn = piecenumber (objectlist[i]->location);
	      objectlist[i]->piece = pn;
	    }
	  else    /* check for polygon or point list */
	    {
	      flag = 1;
	      if (objectlist[i]->numpoints)
		for (j=0; flag && (j<objectlist[i]->numpoints); j++)
		  if (isvisible (objectlist[i]->points[j]))
		    {
		      visiblelist[visiblenumber] = i;
		      visiblenumber++;
		      flag = 0;   /* don't add a single object more than once */
		    }
	    }
	}
    }

  db_visible = visiblenumber;
}



int nearpiece (int p1, int p2)
{
  if (p1 == p2) return 1;
  if (p1-1 == p2) return 1;
  if (p1+1 == p2) return 1;
  if (p1-HOR_SLICES == p2) return 1;
  if (p1+HOR_SLICES == p2) return 1;
  if (p1-HOR_SLICES+1 == p2) return 1;
  if (p1+HOR_SLICES+1 == p2) return 1;
  if (p1-HOR_SLICES-1 == p2) return 1;
  if (p1+HOR_SLICES-1 == p2) return 1;
  return 0;
}



/* find object that is 'close' to a cursor position */

char *nearobject (int x, int y)
{
  static char line[60];
  LOCATION cursor;
  double dist, mindist;
  OBJECT *closeobj = NULL; /* Initilization just to supress Warnings */
  int i;
  double snapdist;

  cursor = window2internal (x, y);

  /* find visible object with minimum distance */

  mindist = -1;
  for (i=0; i<visiblenumber; i++)

#ifdef USE_PIECES
    if (nearpiece (objectlist[visiblelist[i]]->piece, piecenumber (cursor)))
#endif
      if (objectlist[visiblelist[i]]->type / 10 != 35) /* don't snap to areas */
	{
	  dist = distance (objectlist[visiblelist[i]]->location, cursor);
	  if ((dist <= mindist) || (mindist < 0))
	    {
	      closeobj = objectlist[visiblelist[i]];
	      mindist = dist;
	    }
	}
  
  /* calculate distance between cursor and object, about 1cm */
  
  snapdist = (double) max (map_scale / 200000, 2.5);
  

  if ((mindist < snapdist) && (mindist != -1))
    {
      if (closeobj->type == O_WAYPOINT)
	{
	  if (closeobj->alias)
	    sprintf (line, "%s %s", closeobj->alias, closeobj->name);
	  else
	    sprintf (line, "%s", closeobj->name);
	}
      else
	sprintf (line, "%s (%s)", closeobj->name, objecttypestring(closeobj->type));

      saveobj = closeobj;
      return line;
    }

#define CU objectlist[visiblelist[i]]

  /* check if cursor is inside a CTRs */

  if (vis_airspace)
    for (i=0; i<visiblenumber; i++)
      if (objectlist[visiblelist[i]]->type == O_CTR)
	{
	  /* rough check with bounding box */
	  
	  if ((CU->topleft.latitude > cursor.latitude) && 
	      (CU->bottomright.latitude < cursor.latitude) && 
	      (CU->topleft.longitude < cursor.longitude) && 
	      (CU->bottomright.longitude > cursor.longitude))
	    {
	      POINT polygon[2+objectlist[visiblelist[i]]->numpoints], loc;
	      int j;
	      
	      for (j=0; j<objectlist[visiblelist[i]]->numpoints; j++)
		internal2window (objectlist[visiblelist[i]]->points[j],
				 &(polygon[j+1].x), &(polygon[j+1].y));
	      
	      loc.x = x;   loc.y = y;   
	      
	      if (ppcontains (loc, polygon, objectlist[visiblelist[i]]->numpoints))
		{
		  sprintf (line, "CTR %s", objectlist[visiblelist[i]]->name);
		  saveobj = objectlist[visiblelist[i]];
		  return line;
		}
	    }
	}
  
  /* check if cursor is inside a CVFRs */
  
  if (vis_airspace)
    for (i=0; i<visiblenumber; i++)
      if (objectlist[visiblelist[i]]->type == O_CVFR)
	{
	  /* rough check with bounding box */
	  
	  if ((CU->topleft.latitude > cursor.latitude) && 
	      (CU->bottomright.latitude < cursor.latitude) && 
	      (CU->topleft.longitude < cursor.longitude) && 
	      (CU->bottomright.longitude > cursor.longitude))
	    {
	      POINT polygon[2+objectlist[visiblelist[i]]->numpoints], loc;
	      int j;
	      
	      for (j=0; j<objectlist[visiblelist[i]]->numpoints; j++)
		internal2window (objectlist[visiblelist[i]]->points[j],
				 &(polygon[j+1].x), &(polygon[j+1].y));
	      
	      loc.x = x;   loc.y = y;   
	      
	      if (ppcontains (loc, polygon, objectlist[visiblelist[i]]->numpoints))
		{
		  sprintf (line, "CVFR %s", objectlist[visiblelist[i]]->name);
		  saveobj = objectlist[visiblelist[i]];
		  return line;
		}
	    }
	}
  
  saveobj = NULL;
  return 0;
}




/*
   physically draw visible objects when requested by an expose event,
   called from within map.c

   if polygons is 1, draw only polygons. otherwise, only other objects
*/

void drawvisibleobjects(int polygons)
{
  OBJECT *current;
  int i, x, y, heading;

  for (i=0; i<visiblenumber; i++)
    {
      current = objectlist[visiblelist[i]];
      if (((current->type == O_CTR) && (polygons)) ||
	  ((current->type != O_CTR) && (!polygons)))
      {
	internal2window (current->location, &x, &y);
	
	/* let's see if this object has got a runway (default: no) */
	
	heading = -1;
	if (current->runways)
	  heading = current->runways->direction + 
	            truenorthoffset (objectlist[visiblelist[i]]->location); 
	
	switch (current->type) {
	case O_AIRPORT :
	case O_INTLAIRPORT :
	  draw_airport (x, y, heading, current->name, current->numpoints,
			current->points, current->runways);
	  break;
	case O_AIRPORT_CIV_MIL :
	  draw_airport_civ_mil (x, y, heading, current->name);  
	  break;
	case O_AIRPORT_MIL :
	  draw_airport_mil (x, y, heading, current->name);  
	  break;
	case O_AIRFIELD :
	  draw_airfield (x, y, heading, current->name);  
	  break;
	case O_SPECIAL_AIRFIELD :
	  draw_specialairfield (x, y, heading, current->name); 
	  break;
	case O_GLIDER_SITE :
	  draw_glider_site (x, y, current->name); 
	  break;
	case O_HELIPORT:
	case O_HELIPORT_AMB:
		draw_heliport (x, y, current->name);
		break;
	case O_NDB :
	  draw_ndb (x, y, current->name, current->frequency);
	  break;
	case O_VOR :
	  draw_vor (x, y, current->name, current->frequency,
		    truenorthoffset (current->location));
	  break;
	case O_VOR_DME :
	  draw_vor_dme (x, y, current->name, current->frequency,
			truenorthoffset (current->location));
	  break;
	case O_VORTAC :
	  draw_vortac (x, y, current->name, current->frequency,
		       truenorthoffset (current->location));
	  break;
	case O_TACAN :
	  draw_vortac (x, y, current->name, current->frequency, 
		       truenorthoffset (current->location));
	  break;
	case O_RIVER :
	  draw_river (x, y, current->name, current->numpoints, current->points);
	  break;
	case O_ISLAND :
	  draw_island (current->name, current->numpoints, current->points);
	  break;
	case O_BORDER :
	  draw_border (current->numpoints, current->points);
	  break;
	case O_STATE_BORDER :
	  draw_stateborder (current->numpoints, current->points);
	  break;
	case O_LAKE :
	  draw_lake (current->name, current->numpoints, current->points);
	  break;
	case O_HIGHWAY :
	  draw_highway (current->numpoints, current->points);
	  break;
	case O_CTR :
	  draw_ctr (x, y, current->name, current->numpoints, current->points);
	  break;
	case O_CVFR :
	  draw_cvfr (x, y, current->name, current->numpoints, current->points);
	  break;
	case O_WAYPOINT :
	  draw_waypoint (x, y, current->name, current->alias);
	  break;
	case O_VILLAGE :
	  draw_village (x, y, current->name);
	  break;
	case O_TOWN :
	  draw_town (current->name, current->numpoints, current->points);
	  break;
	}
      }
    }
}


void draw_airport (int x, int y, int heading, char *name, int numpoints,
		   LOCATION *points, RUNWAYDEF *runways)
{
  int i, x1, y1, x2, y2, numrwy;
  RUNWAYDEF *current;

  if (((map_scale > 550000) && (media == SCREEN)) || (numpoints == 0))
    {
      draw_airfield (x, y, heading, name);    /* use small symbol */

      gp_setlinestyle (1, SOLID);
      gp_setcolor (NAVYBLUE);

      gp_drawfilledrect (x-2, y-12, x+2, y-9);
      gp_drawfilledrect (x-2, y+9, x+2, y+12);
      gp_drawfilledrect (x-12, y-2, x-9, y+2);
      gp_drawfilledrect (x+9, y-2, x+12, y+2);  
    }
  else
    {
      /* use first points as runway ends, others as airport area 
         count runways: */

      numrwy = 0;
      current = runways;

      while (current)
	{
	  current = current->next;
	  numrwy++;
	}

      /* draw area */

      gp_setcolor (BLACK);

      for (i=2*numrwy; i<numpoints; i++)
	internal2window (points[i], &(px[i-2*numrwy]), &(py[i-2*numrwy]));
      gp_drawarea (px, py, numpoints - 2*numrwy);

      /* draw runways */

      gp_setlinestyle (map_scale < 280000 ? 3 : 2, SOLID);

      gp_setcolor (WHITE);

      for (i=0; i<numrwy; i++)
	{
	  internal2window (points[2*i], &x1, &y1);
	  internal2window (points[2*i+1], &x2, &y2);

	  gp_drawline (x1, y1, x2, y2);
	}

    }
}


void draw_ctr (int x, int y, char *name, int numpoints, LOCATION *points)
{
  int i, lastx, lasty;

  /* calculate window coordinates and store them in px/py */

  if (numpoints > 19999)
    numpoints = 19999;   /* just in case... */

  for (i=0; i<numpoints; i++)
    internal2window (points[i], &(px[i]), &(py[i]));


  /* draw area, distinguish between extended and normal color system */

	gp_setcolor (PINK);
	gp_drawarea (px, py, numpoints);


  /* draw bounding box */

  gp_setcolor (NAVYBLUE);
  gp_setlinestyle (1, DASH);
   gp_smalltext (x, y, name);


  lastx = px[numpoints-1];
  lasty = py[numpoints-1];

  for (i=0; i<numpoints; i++)
    {
      gp_drawline (lastx, lasty, px[i], py[i]);
      lastx = px[i];
      lasty = py[i];
    }

}


void draw_cvfr (int x, int y, char *name, int numpoints, LOCATION *points)
{
  int i, lastx, lasty;

  /* calculate window coordinates and store them in px/py */

  if (numpoints > 19999)
    numpoints = 19999;   /* just in case... */

  for (i=0; i<numpoints; i++)
    internal2window (points[i], &(px[i]), &(py[i]));


  /* draw bounding box */

  gp_setcolor (LIGHTGREEN);
  gp_setlinestyle (map_scale < 270000 ? 5 : 3, SOLID);

  lastx = px[numpoints-1];
  lasty = py[numpoints-1];

  for (i=0; i<numpoints; i++)
    {
      gp_drawline (lastx, lasty, px[i], py[i]);
      lastx = px[i];
      lasty = py[i];
    }

}


void draw_river (int x, int y, char *name, int numpoints, LOCATION *points)
{
  int i, px, py, lastx, lasty;

  switch (media) {
  case SCREEN:
    gp_setcolor (SKYBLUE);
    gp_setlinestyle (2, SOLID);
    break;
  case POSTSCRIPT:
    gp_setcolor (BLACK);
    gp_setlinestyle (2, SOLID);
    break;
  }

  gp_smalltext (x, y, name);

  internal2window (points[0], &lastx, &lasty);

  for (i=1; i<numpoints; i++)
    {
      internal2window (points[i], &px, &py);
      gp_drawline (lastx, lasty, px, py);
      lastx = px;
      lasty = py;
    }
}

void draw_border (int numpoints, LOCATION *points)
{
  int i, px, py, lastx, lasty;

  switch (media) {
  case SCREEN:
  case POSTSCRIPT:
    gp_setcolor (BLACK);
    gp_setlinestyle (1, SOLID);
    break;
  }

  internal2window (points[0], &lastx, &lasty);

  for (i=1; i<numpoints; i++)
    {
      internal2window (points[i], &px, &py);
      gp_drawline (lastx, lasty, px, py);
      lastx = px;
      lasty = py;
    }
}






void draw_stateborder (int numpoints, LOCATION *points)
{
  int i, px, py, lastx, lasty;

  switch (media) {
  case SCREEN:
  case POSTSCRIPT:
    gp_setcolor (LIGHTGRAY);
    gp_setlinestyle (1, SOLID);
    break;
  }

  internal2window (points[0], &lastx, &lasty);

  for (i=1; i<numpoints; i++)
    {
      internal2window (points[i], &px, &py);
      gp_drawline (lastx, lasty, px, py);
      lastx = px;
      lasty = py;
    }
}


void draw_highway (int numpoints, LOCATION *points)
{
  int i, px, py, lastx, lasty;

  internal2window (points[0], &lastx, &lasty);
  gp_setlinestyle (3, SOLID);
  gp_setcolor (RED);
  for (i=1; i<numpoints; i++)
    {
      internal2window (points[i], &px, &py);
      gp_drawline (lastx, lasty, px, py);

      lastx = px;
      lasty = py;
    }

  internal2window (points[0], &lastx, &lasty);
  gp_setlinestyle (1, SOLID);
  gp_setcolor (WHITE);
  for (i=1; i<numpoints; i++)
    {
      internal2window (points[i], &px, &py);
      gp_drawline (lastx, lasty, px, py);

      lastx = px;
      lasty = py;
    }
}


void draw_airport_mil (int x, int y, int runwayheading, char *name)
{
  draw_airfield (x, y, runwayheading, name);
  gp_setcolor (NAVYBLUE);
  gp_setlinestyle (1, SOLID);
  gp_drawcircle (x, y, 10);
  gp_setlinestyle (1, SOLID);
}


void draw_airport_civ_mil (int x, int y, int runwayheading, char *name)
{
  draw_airport_mil (x, y, runwayheading, name);
  gp_setcolor (NAVYBLUE);
  gp_drawrect (x-2, y-12, x+2, y-9);
  gp_drawrect (x-2, y+9, x+2, y+12);
  gp_drawrect (x-12, y-2, x-9, y+2);
  gp_drawrect (x+9, y-2, x+12, y+2);
}


void draw_airfield (int x, int y, int runwayheading, char *name)
{
  int xrwy, yrwy;

  gp_setcolor (NAVYBLUE);
  gp_setlinestyle (3, SOLID);
  gp_drawcircle (x, y, 18);

  if (runwayheading != -1)
    {
      gp_setlinestyle (5, SOLID);
      xrwy = (int) (sin((double) runwayheading*PI/180)*16);
      yrwy = (int) (cos((double) runwayheading*PI/180)*16);
      gp_drawline (x+xrwy, y-yrwy, x-xrwy, y+yrwy);
    }

  gp_setcolor (BLACK);
  gp_smalltext (x, y+30, name);
}


void draw_specialairfield (int x, int y, int runwayheading, char *name)
{
  int xrwy, yrwy;

  gp_setcolor (NAVYBLUE);
  gp_setlinestyle (3, SOLID);
  gp_drawcircle (x, y, 18);

  if (runwayheading != -1)
    {
      gp_setlinestyle (5, SOLID);
      xrwy = (int) (sin((double) runwayheading*PI/180)*16);
      yrwy = (int) (cos((double) runwayheading*PI/180)*16);
      gp_drawline (x+xrwy, y-yrwy, x-xrwy, y+yrwy);
      gp_setlinestyle (3, SOLID);
      xrwy = (int) (sin((double) runwayheading*PI/180)*14);
      yrwy = (int) (cos((double) runwayheading*PI/180)*14);
      gp_setcolor (WHITE);
      gp_drawline (x+xrwy, y-yrwy, x-xrwy, y+yrwy);
      gp_setcolor (BLACK);
    }

  gp_setcolor (BLACK);
  gp_smalltext (x, y+30, name);
}


void draw_glider_site (int x, int y, char *name)
{
	/* Must be 0 to become correctly set */
  static int glideUPath = 0;
	static float ptsGlide[]={
		  -16, -16, 16, 16, /* setbbox */ 
			0, 0, 8, 0, 360,  /* arc */
			-12, 3,           /* moveto */
			-3, -2,           /* lineto */
			0, 2,             /* lineto */
			3, -2,            /* lineto */
			12, 3,            /* lineto */
			0, 2,             /* moveto */
			-2, 4             /* lineto */	
			};
	static char opsGlide[]={ dps_ucache, dps_setbbox, dps_arc
			, dps_moveto, dps_lineto, dps_lineto, dps_lineto, dps_lineto
			, dps_moveto, dps_lineto};
	
	if (!glideUPath || (NXDrawingStatus != NX_DRAWING) )
	{
		/* If not drawing define the object again, and again.. */
		PSW_SetUpath(ptsGlide, sizeof(ptsGlide)/sizeof(float), opsGlide
				, sizeof(opsGlide)/sizeof(char));
		glideUPath = DPSDefineUserObject(glideUPath);
	}

  gp_setcolor (NAVYBLUE);
  gp_setlinestyle (2, SOLID);
	PSW_UpathStroke(x, y, glideUPath);

/*	gp_drawcircle (x, y, 16);

  gp_drawline (x-12, y+3, x-3, y-2);
  gp_drawline (x-3, y-2, x, y+2);
  gp_drawline (x, y+2, x+3, y-2);
  gp_drawline (x+12, y+3, x+3, y-2);
  gp_drawline (x, y+2, x-2, y+4);
*/
  gp_setcolor (BLACK);
  gp_smalltext (x, y+22, name);
}

void draw_heliport (int x, int y, char *name)
{
	/* Must be 0 to become correctly set */
  static int heliUPath = 0;
	static float ptsHeli[]={
		  -16, -16, 16, 16, /* setbbox */ 
			0, 0, 9, 0, 360,  /* arc */
			-3, 5,            /* moveto */
			-3, -5,           /* lineto */
			3, 5,             /* moveto */
			3, -5,            /* lineto */
			-3, 0,            /* moveto */
			3, 0              /* lineto */	
			};
	static char opsHeli[]={ dps_ucache, dps_setbbox, dps_arc
			, dps_moveto, dps_lineto, dps_moveto, dps_lineto, dps_moveto
			, dps_lineto};
	
	/* 1 == NX_DRAWING (or see View.h), but don't make this Objective-C */
	if (!heliUPath || (NXDrawingStatus != 1) )
	{
		/* If not drawing define the object again, and again.. */
		PSW_SetUpath(ptsHeli, sizeof(ptsHeli)/sizeof(float), opsHeli
				, sizeof(opsHeli)/sizeof(char));
		heliUPath = DPSDefineUserObject(heliUPath);
	}

  gp_setcolor (NAVYBLUE);
  gp_setlinestyle (2, SOLID);
	PSW_UpathStroke(x, y, heliUPath);

  gp_setcolor (BLACK);
  gp_smalltext (x, y+22, name);
}


void draw_vor (int x, int y, char *name, double freq, int northoffset)
{
  char label[40];
  int i;

  gp_setcolor (NAVYBLUE);
  gp_setlinestyle (1, SOLID);
  gp_drawcircle (x, y, 1);
  gp_drawline (x-3, y-5, x+3, y-5);
  gp_drawline (x+3, y-5, x+6, y);
  gp_drawline (x+6, y, x+3, y+5);
  gp_drawline (x+3, y+5, x-3, y+5);
  gp_drawline (x-3, y+5, x-6, y);
  gp_drawline (x-6, y, x-3, y-5);

  gp_drawcircle (x, y, 100);

  for (i = northoffset; i<360+northoffset; i+=10)
    gp_drawline (x+1+50*sin(i*PI/180), y+1-50*cos(i*PI/180),
		 x+1+((i-northoffset)%30?46:i!=northoffset?40:20)*sin(i*PI/180), 
		 y+1-((i-northoffset)%30?46:i!=northoffset?40:20)*cos(i*PI/180));

  gp_setcolor (BLACK);
  sprintf (label, "%s %6.2f", name, freq);
  gp_smalltext (x, y+62, label);
}


void draw_vor_dme (int x, int y, char *name, double freq, int northoffset)
{
  draw_vor (x, y, name, freq, northoffset);

  gp_setcolor (NAVYBLUE);

  gp_drawline (x-7, y-5, x+7, y-5);
  gp_drawline (x+7, y-5, x+7, y+5);
  gp_drawline (x+7, y+5, x-7, y+5);
  gp_drawline (x-7, y+5, x-7, y-5);
}


void draw_vortac (int x, int y, char *name, double freq, int northoffset)
{
  int px[4], py[4];

  draw_vor (x, y, name, freq, northoffset);

  gp_setcolor (NAVYBLUE);
	
  px[0] = x-3; py[0] = y+5;
  px[1] = x+3; py[1] = y+5;
  px[2] = x+3; py[2] = y+11;
  px[3] = x-3; py[3] = y+11;
  gp_drawarea (px, py, 4); 
	/* gp_drawfilledrect(x-3, y+5, x+3, y+11); <= this is slower. why?*/

  px[0] = x-3; py[0] = y-5;
  px[1] = x-6; py[1] = y;
  px[2] = x-11; py[2] = y-3;
  px[3] = x-8; py[3] = y-8;
  gp_drawarea (px, py, 4);

  px[0] = x+3; py[0] = y-5;
  px[1] = x+6; py[1] = y;
  px[2] = x+11; py[2] = y-3;
  px[3] = x+8; py[3] = y-8;
  gp_drawarea (px, py, 4);
}



void draw_ndb (int x, int y, char *name, double freq)
{
  char label[40];

  gp_setcolor (NAVYBLUE);
  gp_setlinestyle (1, SOLID);
  gp_drawcircle (x, y, 5);

  gp_setlinestyle (1, DOT);

  switch (media) {
  case SCREEN:
    gp_drawcircle (x, y, 10);
    gp_drawcircle (x, y, 14);
    gp_drawcircle (x, y, 18);
    gp_drawcircle (x, y, 22);
    break;
  case POSTSCRIPT:
    gp_drawcircle (x, y, 10);
    gp_drawcircle (x, y, 16);
    gp_drawcircle (x, y, 22);
    gp_drawcircle (x, y, 28);
    break;
  }

  gp_setcolor (BLACK);
  if (freq - (int) freq)
    sprintf (label, "%s %5.1f", name, freq);
  else
    sprintf (label, "%s %3.0f", name, freq);

  switch (media) {
  case SCREEN:
    gp_smalltext (x, y-10, label);
    break;
  case POSTSCRIPT:
    gp_smalltext (x, y-17, label);
    break;
  }
}




void draw_waypoint (int x, int y, char *label, char *alias)
{
  gp_setlinestyle (1, SOLID);
  gp_setcolor (NAVYBLUE);
  gp_drawline (x, y, x+3, y+5);      /* draw a W */
  gp_drawline (x, y, x-3, y+5);
  gp_drawline (x+3, y+5, x+6, y-4);
  gp_drawline (x-3, y+5, x-6, y-4);

  gp_drawcircle (x, y, 17);

  if (alias)
    {
      gp_smalltext (x, y+22, alias);
      gp_smalltext (x, y+32, label);
    }
  else
      gp_smalltext (x, y+22, label);
}



void draw_village (int x, int y, char *label)
{
  gp_setlinestyle (1, SOLID);
  gp_setcolor (BLACK);
  
  gp_drawcircle (x, y, 7);
  
  if (label)
    gp_smalltext (x, y+14, label);
}



void draw_town (char *name, int numpoints, LOCATION *points)
{
  int i, y, lastx, lasty;
  long sx;

  /* calculate window coordinates and store them in px/py */

  if (numpoints > 19999)
    numpoints = 19999;   /* just in case... */

  for (i=0; i<numpoints; i++)
    internal2window (points[i], &(px[i]), &(py[i]));


  /* draw area */

  gp_setcolor (YELLOW);
  gp_drawarea (px, py, numpoints);


  /* draw bounding box */

  gp_setcolor (BLACK);
  gp_setlinestyle (1, SOLID);

  lastx = px[numpoints-1];
  lasty = py[numpoints-1];

  sx = 0;
  y = py[0];

  for (i=0; i<numpoints; i++)
    {
      if (py[i] < y) y = py[i];
      sx += px[i];

      gp_drawline (lastx, lasty, px[i], py[i]);
      lastx = px[i];
      lasty = py[i];
    }

  gp_smalltext ((int) sx/numpoints, y, name);

}



void draw_island (char *name, int numpoints, LOCATION *points)
{
  int i, y, lastx, lasty;
  long sx;

  /* calculate window coordinates and store them in px/py */

  if (numpoints > 19999)
    numpoints = 19999;   /* just in case... */

  for (i=0; i<numpoints; i++)
    internal2window (points[i], &(px[i]), &(py[i]));


  /* draw bounding box */

  gp_setcolor (BLACK);
  gp_setlinestyle (1, SOLID);

  lastx = px[numpoints-1];
  lasty = py[numpoints-1];

  sx = 0;
  y = py[0];

  for (i=0; i<numpoints; i++)
    {
      if (py[i] < y) y = py[i];
      sx += px[i];

      gp_drawline (lastx, lasty, px[i], py[i]);
      lastx = px[i];
      lasty = py[i];
    }

  gp_smalltext ((int) sx/numpoints, y, name);

}


void draw_lake (char *name, int numpoints, LOCATION *points)
{
  int i, y;
  long sx;

  /* calculate window coordinates and store them in px/py */

  if (numpoints > 19999)
    numpoints = 19999;   /* just in case... */

  for (i=0; i<numpoints; i++)
    internal2window (points[i], &(px[i]), &(py[i]));


  /* draw area */

  gp_setcolor (SKYBLUE);
  gp_drawarea (px, py, numpoints);

  gp_setcolor (BLACK);

  sx = 0;
  y = py[0];

  for (i=0; i<numpoints; i++)
    {
      if (py[i] < y) y = py[i];
      sx += px[i];
    }
  gp_smalltext ((int) sx/numpoints, y, name);
}









/* make text lines describing the object near to the cursor, numlines = 0 if none */

void objectdescription(char **lines, int *numlines, int x, int y, int *range)
{
  int count = 0;
  char *line;
  RUNWAYDEF *rwy;

  *range = 0;

  if (line = nearobject (x, y))
    {
      *range = saveobj->range;
      
      sprintf (lines[count++], "%s", line);
      
      switch (saveobj->type) {

      default:
	if (saveobj->type != O_WAYPOINT)
	  if (saveobj->alias)
	    sprintf (lines[count++], "ID: %s", saveobj->alias);
	    
	if (saveobj->frequency)
	  if (saveobj->type == O_NDB)
	    {
	      if (saveobj->frequency - (int) saveobj->frequency)
		sprintf (lines[count++], "Frequency: %5.1f", saveobj->frequency);
	      else
		sprintf (lines[count++], "Frequency: %3.0f", saveobj->frequency);
	    }
	  else
	    sprintf (lines[count++], "Frequency: %6.2f", saveobj->frequency);

	rwy = saveobj->runways;
	while (rwy)
	  {
	    if (rwy->length)
	      sprintf (lines[count], "Runway: %3d  LDG %4.1f %s  %s"
						, rwy->direction
						,(rwy->length)*UNIT_CHANGE(IPD_RUNWAYUNIT)/1852
						, UNIT_NAME(IPD_RUNWAYUNIT)
						, rwy->surface == 'G' ? "Gras"
								:	rwy->surface == 'A' ? "Asphalt":"Concrete");
	    else
	      sprintf (lines[count], "Runway: %3d   T/O only   %s",
		       rwy->direction,
		       rwy->surface == 'G' ? "Gras" : rwy->surface == 'A' ? "Asphalt"
		       : "Concrete");

	    /* leading zeros */

	    if (lines[count][8] == ' ') lines[count][8] = '0';
	    if (lines[count][9] == ' ') lines[count][9] = '0';
	    count++;

	    rwy = rwy->next;
	  }

	if (saveobj->type < O_CTR)
	  sprintf (lines[count++], "Location: %s"
				,internal2string(saveobj->location));

	if (saveobj->range != UNKNOWN)
	  sprintf (lines[count++], "Range: %1.0f %s"
				, saveobj->range*UNIT_CHANGE(IPD_RANGEUNIT), UNIT_NAME(IPD_RANGEUNIT));

	if (saveobj->msl != UNKNOWN)
	  sprintf (lines[count++], "Elev: %1.0f %s"
				, (saveobj->msl)*UNIT_CHANGE(IPD_ELEVATIONUNIT)/6076.115
				, UNIT_NAME(IPD_ELEVATIONUNIT));
      }

      *numlines = count;
    }
  else
    *numlines = 0;
}

