 /*
  * Khoros: $Id: draw_2D.c,v 1.4 1992/03/20 22:46:22 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: draw_2D.c,v 1.4 1992/03/20 22:46:22 dkhoros Exp $";
#endif

 /*
  * $Log: draw_2D.c,v $
 * Revision 1.4  1992/03/20  22:46:22  dkhoros
 * VirtualPatch5
 *
  */ 


/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 *
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "X3D.h"	
static void draw_colorline();
static int  find_level();


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	    file name: draw_2D.c 
   >>>>               
   >>>>   description: 2D Drawing  Utilities
   >>>>              
   >>>>      routines:
   >>>>			X2D_draw_polyline()		      <<<<
   >>>>			X2D_draw_discrete()		      <<<<
   >>>>			X2D_draw_bargraph()		      <<<<
   >>>>			X2D_draw_histogram()		      <<<<
   >>>>			X2D_draw_polymarker()		      <<<<
   >>>>			X2D_draw_linemarker()		      <<<<
   >>>>			X2D_draw_polygon()		      <<<<
   >>>>			X2D_draw_segments()		      <<<<
   >>>>			X2D_draw_line()		      	      <<<<
   >>>>			X2D_draw_rectangle()	      	      <<<<
   >>>>			X2D_draw_colorline()	      	      <<<<
   >>>>              
   >>>> modifications:
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */


/************************************************************
*
*  MODULE NAME:  X2D_draw_polyline
*
*      PURPOSE:  Uses X11 graphics routines to connect a series of points
*
*        INPUT: id        - X3D graphics structure ID
*		coords    - array of world coordinate points
*		size      - number of points
*
*       OUTPUT: displays a line (or a set of lines) to graphics workstation
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young
*
*************************************************************/

X2D_draw_polyline (id, coords, size, fg)

int	id, size;
Coord	*coords;
XColor  *fg;
{
	X3DGraphics	*graphics;
	XSegment	*segments;
	static char	ps_comment[] = "%\n% Start of Polyline Plot\n%\n";
	static char	hpgl_comment[] = "%\n! Start of Polyline Plot\n";
	int seg_num;

	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X2D_draw_polyline:\n");
	   fprintf (stderr,"\t unknown graphics id\n");
	   return;
	}

	seg_num = size -1; /* if there are n pts there are n-1 segments */
	if (!(segments = (XSegment *) malloc ((unsigned) seg_num * 
			sizeof (XSegment))))
	{
	   fprintf (stderr,"X2D_draw_polyline:\n");
	   fprintf (stderr,"\t not enough memory\n");
	   return;
	}

	if(graphics->clipping_2D)
	{
	   if(!(_X2D_clip_segs(coords,size,segments,&seg_num,graphics)))
	   {
		free(segments);
		return;
	   }
	}
	else if(!(_X2D_convert_wc_coord_to_dc_seg(graphics,coords,segments,size)))
	{
		free(segments);
		return;
	}

	if (graphics->device == POSTSCR)
	   fprintf(graphics->pfile,"%s\n", ps_comment);
/*
	if (graphics->device == HPGL)
	   fprintf(graphics->hfile,"%s\n", hpgl_comment);
*/

	X3D_draw[graphics->device].draw_color(graphics, fg, FALSE);
	X3D_draw[graphics->device].segments(graphics, segments, seg_num);
        free(segments);
}



/************************************************************
*
*  MODULE NAME:  X2D_draw_discrete
*
*      PURPOSE:  Uses X11 graphics routines to connect a series of points
*
*        INPUT: id        - X3D graphics structure ID
*		coords    - array of world coordinate points
*		size      - number of points
*
*       OUTPUT: displays a discrete line plot to the graphics workstation
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young
*
*************************************************************/

X2D_draw_discrete (id, coords, size, fg)

int	id, size;
Coord	*coords;
XColor  *fg;
{
	X3DGraphics	*graphics;
	XPoint		*points;

	int		i,zero_baseline=FALSE;
	short		baseline, top, right, left, bottom;
	Real		xmin, ymin, xmax, ymax, dc_yzero, dc_xzero;
	Coord		zero_coord;
	static char	ps_comment[] = "%\n% Start of Discrete Plot\n%\n";
	static char	hpgl_comment[] = "%\n! Start of Discrete Plot\n";
	
	zero_coord.x = 0.0;
	zero_coord.y = 0.0;

	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X2D_draw_discrete:\n");
	   fprintf (stderr,"\t unknown graphics id\n");
	   return;
	}

	if (!(points = (XPoint *) malloc ((unsigned) size * sizeof (XPoint))))
	{
	   fprintf (stderr,"X2D_draw_discrete:\n");
	   fprintf (stderr,"\t not enough memory\n");
	   return;
	}
	if(graphics->wc_min.y < 0  && graphics->wc_max.y >0)
	{
	   zero_baseline=TRUE;
	   if(!(X2D_convert_point_wc_to_dc (id, zero_coord, &dc_xzero, &dc_yzero)))
	   {
	      free(points);
	      return;
	   }
	}

	if (!(X2D_convert_point_wc_to_dc (id, graphics->wc_min, &xmin, &ymin)))
	{
	   free(points);
	   return;
	}

	if (!(X2D_convert_point_wc_to_dc (id, graphics->wc_max, &xmax, &ymax)))
	{
	   free(points);
	   return;
	}

	left = (short) xmin + 0.5;
	right = (short) xmax + 0.5;
	bottom = (short) ymin + 0.5;
	if(zero_baseline)
	   baseline = (short) dc_yzero + 0.5;
	else
	   baseline = bottom;

	top = (short) ymax + 0.5;
	if(!(_X2D_convert_wc_to_dc(graphics, coords, points, size)))
	{
	   free(points);
	   return;
	}

	if (graphics->device == POSTSCR)
	{
	   fprintf(graphics->pfile,"%s\n", ps_comment);
	   /* have to swap top and bottom for postscript */
	   bottom = (short) ymax + 0.5;
	   top = (short) ymin + 0.5;
	}
/*
	if (graphics->device == HPGL)
	   fprintf(graphics->hfile,"%s\n", hpgl_comment);
*/

	X3D_draw[graphics->device].draw_color(graphics, fg, FALSE);
	if (graphics->clipping_2D)
	{
	   for (i = 0; i < size; i++)
	   {
		if(points[i].x > left && points[i].x < right)
		{
		   if(points[i].y < top)	/* X is upsidedown */
			points[i].y = top;
		   if(points[i].y > bottom)	
			points[i].y = bottom;

		   X3D_draw[graphics->device].line(graphics,
			points[i].x, baseline, points[i].x, points[i].y);
		}
	   }
	}
	else
	{
	   for (i = 0; i < size; i++)
	   {
	      X3D_draw[graphics->device].line(graphics,
			points[i].x, baseline, points[i].x, points[i].y);
	   }
	}
        free(points);
}



/************************************************************
*
*  MODULE NAME:  X2D_draw_bargraph
*
*      PURPOSE:  Draws a two dimensional bargraph 
*
*        INPUT: id        - X3D graphics structure ID
*		coords    - array of world coordinate points
*		size      - number of points
*
*       OUTPUT: displays a line (or a set of lines) to graphics workstation
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young
*
*************************************************************/

X2D_draw_bargraph (id, coords, size, fg)

int	id, size;
Coord	*coords;
XColor  *fg;
{
	X3DGraphics	*graphics;
	XPoint		*points;

	int		i, x, y, xw;
	short		top, bottom, left, right;
	Real		xmin, ymin, xmax, ymax;
	unsigned int	width, height;
	static char	ps_comment[] = "%\n% Start of Histogram Plot\n%\n";
	static char	hpgl_comment[] = "%\n! Start of Histogram Plot\n";

	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X2D_draw_bargraph:\n");
	   fprintf (stderr,"\t unknown graphics id\n");
	   return;
	}

	if (!(points = (XPoint *) malloc ((unsigned) size*sizeof (XPoint))))
	{
	   fprintf (stderr,"X2D_draw_bargraph:\n");
	   fprintf (stderr,"\t not enough memory\n");
	   return;
	}

	if(!(X2D_convert_point_wc_to_dc (id, graphics->wc_min, &xmin, &ymin)))
	{
	   free(points);
	   return;
	}
	if(!(X2D_convert_point_wc_to_dc (id, graphics->wc_max, &xmax, &ymax)))
	{
	   free(points);
	   return;
	}
	left = (short) xmin + 0.5;
	right = (short) xmax + 0.5;
	bottom = (short) ymin + 0.5;
	top = (short) ymax + 0.5;

	if(!(_X2D_convert_wc_to_dc(graphics, coords, points, size)))
	{
	   free(points);
	   return;
	}

	if (graphics->device == POSTSCR)
	   fprintf(graphics->pfile,"%s\n", ps_comment);

	X3D_draw[graphics->device].draw_color(graphics, fg, FALSE);

	/*
	 *  Initialize the width and the first x position.
	 */
	if (size == 1)
	   width = ABS(right-left)/2;
	else width = ABS(points[0].x - points[1].x);

	x = points[0].x - (width/2.0 + 0.5);
	if (graphics->clipping_2D)
	{
	   for (i = 0; i < size; i++)
	   {
	      if (i+1 != size)
	      {
		 width = ABS(points[i].x - points[i+1].x);
	      }
	      xw = x + width;
	      if (!(x < left && xw < left) && !(x >= right && xw > right))
	      {
		 if (x < left)
		 {
		    width -= left-x;
		    x = left;
		 }
		 else if (x+width > right)
		 {
		    width -= (x+width) - right;
		    x = right - width;
		 }

		 if (points[i].y > bottom) 
		    y = bottom;
		 else if (points[i].y < top) 
		    y = top;
		 else y = points[i].y;

		 height = ABS(bottom - y);
		 X3D_draw[graphics->device].rectangle(graphics, x, y, width,
			height);
	      }
	      x += width;
	   }
	}
	else
	{
	    for (i = 0; i < size; i++)
	    {
	       if (i+1 != size)
	          width = ABS(points[i].x - points[i+1].x);

	       y = points[i].y;
	       height = ABS(bottom - y);
	       X3D_draw[graphics->device].rectangle(graphics, x, y, width,
			height);
	       x += width;
	    }
	}
        free(points);
}



/************************************************************
*
*  MODULE NAME:  X2D_draw_histogram
*
*      PURPOSE:  Uses X11 graphics routines to connect a series of points
*
*        INPUT: id        - X3D graphics structure ID
*		coords    - array of world coordinate points
*		size      - number of points
*
*       OUTPUT: displays a line (or a set of lines) to graphics workstation
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young
*
*************************************************************/

X2D_draw_histogram (id, coords, size, wcmin, wcmax, num, fg)

int	id, size, num;
Coord	*coords, wcmin, wcmax;
XColor  *fg;
{
	X3DGraphics	*graphics;
	XPoint		*points;

	int		i, x, y;
	short		baseline;
	Real		xmin, ymin, xmax, ymax;
	unsigned int	width, height;

	static char	comment[] = "%\n% Start of Histogram Plot\n%\n";

	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X2D_draw_bargraph:\n");
	   fprintf (stderr,"\t unknown graphics id\n");
	   return;
	}

	if (!(points = (XPoint *) malloc ((unsigned) size * sizeof (XPoint))))
	{
	   fprintf (stderr,"X2D_draw_histogram:\n");
	   fprintf (stderr,"\t not enough memory\n");
	   return;
	}

	if(!(X2D_convert_point_wc_to_dc (id, graphics->wc_min, &xmin, &ymin)))
	{
	   free(points);
	   return;
	}
	if(!(X2D_convert_point_wc_to_dc (id, graphics->wc_max, &xmax, &ymax)))
	{
	   free(points);
	   return;
	}
	baseline = (short) ymin;

	X3D_draw[graphics->device].draw_color(graphics, fg, FALSE);

	for (i = 1; i <= size; i++)
	{
	    width = (int) ABS(points[i].x - points[i+1].x);
	    x = points[i].x;
	    y = points[i].y;
	    height = ABS(baseline - y);
	    X3D_draw[graphics->device].rectangle(graphics, x, y, width, height);
	}
        free(points);
}



/************************************************************
*
*  MODULE NAME:  X2D_draw_polymarker
*
*      PURPOSE:  Uses X11 graphics routines to draw a series of points
*
*        INPUT: id        - X3D graphics structure ID
*		coords    - array of world coordinate points
*		size      - number of points
*
*       OUTPUT: displays a point (or a set of points) to graphics workstation
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young
*
*************************************************************/


X2D_draw_polymarker (id, coords, size, marker_type, fg)

int	id, size, marker_type;
Coord	*coords;
XColor  *fg;
{
	X3DGraphics	*graphics;
	Coord		*tmp_coords;
	XPoint		*points;


	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X2D_draw_polymarker:\n");
	   fprintf (stderr,"\t unknown graphics id\n");
	   return;
	}
	if(graphics->clipping_2D)
	{
	   if (!(tmp_coords = (Coord *)malloc((unsigned)size*sizeof(Coord))))
	   {
		fprintf (stderr,"X2D_draw_polymarker:\n");
		fprintf (stderr,"\t not enough memory\n");
		return;
	   }
	   if(!(_X2D_clip_points(coords,&size,tmp_coords,graphics)))
	   {
		free(tmp_coords);
		return;
	   }
	}
	else tmp_coords = coords;

	if (!(points = (XPoint *) malloc ((unsigned) size * sizeof (XPoint))))
	{
	   fprintf (stderr,"X2D_draw_polymarker:\n");
	   fprintf (stderr,"\t not enough memory\n");
	   return;
	}
	if(!(_X2D_convert_wc_to_dc(graphics, tmp_coords, points, size)))
	{
	   free(points);
	   return;
	}

	X3D_draw[graphics->device].draw_color(graphics, fg, FALSE);
	draw_markers(id, points, NULL, size, marker_type, NULL, 0);
        free(points);
}



/************************************************************
*
*  MODULE NAME:  X2D_draw_colormarker
*
*      PURPOSE:  Uses X11 graphics routines to draw a series of points
*		 in different colors.
*
*		 The coord structure contains a "d" field which is generally
*		 unused by 2D routines.  It is taken advantage of in 
*		 X2D_draw_colormarker, to specify which points will be drawn
*		 in which colors.  Suppose you have an array of 10 points
*		 to be plotted, which you would like to appear in the 5 colors
*		 specified by the "colors" array.  If, for example, you wanted
*		 each consecutive pair of points to appear in a different 
*		 color, you would specify:
*			 coord[0].d = coord[1].d = 0
*			 coord[2].d = coord[3].d = 1
*			 coord[4].d = coord[5].d = 2
*			 coord[6].d = coord[7].d = 3
*			 coord[8].d = coord[9].d = 4
*
*        INPUT: id          - X3D graphics structure ID
*		coords      - array of world coordinate points
*		size        - number of points
*		marker_type - type of marker to be drawn
*		colors      - array of different colors to be used (see above)
*		num_colors  - the size of the color array (# different colors)
*
*       OUTPUT: displays a set of points in different colors 
*		to graphics workstation
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young & Danielle Argiro
*
*************************************************************/


X2D_draw_colormarker (id, coords, size, marker_type, colors, num_colors)

int	id, size, num_colors, marker_type;
Coord	*coords;
XColor  *colors;
{
	X3DGraphics	*graphics;
	Coord		*tmp_coords;
	XPoint		*points;


	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X2D_draw_colormarker:\n");
	   fprintf (stderr,"\t unknown graphics id\n");
	   return;
	}
	if(graphics->clipping_2D)
	{
	   if (!(tmp_coords = (Coord *)malloc((unsigned)size*sizeof(Coord))))
	   {
		fprintf (stderr,"X2D_draw_colormarker:\n");
		fprintf (stderr,"\t not enough memory\n");
		return;
	   }
	   if(!(_X2D_clip_points(coords,&size,tmp_coords,graphics)))
	   {
		free(tmp_coords);
		return;
	   }
	}
	else tmp_coords = coords;

	if (!(points = (XPoint *) malloc ((unsigned) size * sizeof (XPoint))))
	{
	   fprintf (stderr,"X2D_draw_colormarker:\n");
	   fprintf (stderr,"\t not enough memory\n");
	   return;
	}
	if(!(_X2D_convert_wc_to_dc(graphics, tmp_coords, points, size)))
	{
	   free(points);
	   return;

	}

	draw_markers(id, points, tmp_coords, size, marker_type, 
		     colors, num_colors);

	if (tmp_coords != coords)
            free(tmp_coords);
        free(points);
}




/************************************************************
*
*  MODULE NAME:  X2D_draw_linemarker
*
*      PURPOSE:  Uses X11 graphics routines to connect a series of points
*
*        INPUT: id        - X3D graphics structure ID
*		coords    - array of world coordinate points
*		size      - number of points
*
*       OUTPUT: displays a line (or a set of lines) to graphics workstation
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young
*
*************************************************************/

X2D_draw_linemarker (id, coords, size, marker_type, fg)

int	id, size, marker_type;
Coord	*coords;
XColor  *fg;
{
	X3DGraphics	*graphics;


	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X2D_draw_curve:\n");
	   fprintf (stderr,"\t unknown graphics id\n");
	   return;
	}
	X2D_draw_polymarker (id, coords, size, marker_type, fg);
	X2D_draw_polyline (id, coords, size, fg);
}




/************************************************************
*
*  MODULE NAME:  X2D_draw_polygon
*
*      PURPOSE:  Uses X11 graphics routines to draw a polygon
*
*        INPUT: id        - X3D graphics structure ID
*		coords    - array of world coordinate points
*		size      - number of points
*
*       OUTPUT: displays a polygon to graphics workstation
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young
*
*************************************************************/

X2D_draw_polygon (id, coords, size, fg)

int	id, size;
Coord	*coords;
XColor  *fg;
{
	X3DGraphics	*graphics;
	XPoint		*points;
	static char	ps_comment[] = "%\n% Start of Polygon Plot\n%\n";
	static char	hpgl_comment[] = "%\n! Start of Polygon Plot\n";

	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X2D_draw_polyline:\n");
	   fprintf (stderr,"\t unknown graphics id\n");
	   return;
	}

	if (!(points = (XPoint *) malloc ((unsigned)(size +1)*sizeof (XPoint))))
	{
	   fprintf (stderr,"X2D_draw_polygon:\n");
	   fprintf (stderr,"\t not enough memory\n");
	   return;
	}

	if(!(_X2D_convert_wc_to_dc(graphics, coords, points, size)))
	{
	   free(points);
	   return;
	}
	points[size] = points[0];

	if (graphics->device == POSTSCR)
	   fprintf(graphics->pfile,"%s\n",ps_comment);
/*
	if (graphics->device == HPGL)
	   fprintf(graphics->hfile,"%s\n",hpgl_comment);
*/

	X3D_draw[graphics->device].draw_color(graphics, fg, FALSE);
	X3D_draw[graphics->device].polygon(graphics, points, size, Convex, 
		        CoordModeOrigin, TRUE);
	X3D_draw[graphics->device].lines(graphics,points,++size, CoordModeOrigin);

        free(points);
}



/************************************************************
*
*  MODULE NAME:  X2D_draw_segments
*
*      PURPOSE:  Uses X11 graphics routines to draw a series of segments
*
*        INPUT: id        - X3D graphics structure ID
*		coords    - array of world coordinate points
*		size      - number of points
*
*       OUTPUT: displays a set of lines to the graphics workstation
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young
*
*************************************************************/

X2D_draw_segments (id, coords, size, fg)

int	id, size;
Coord	*coords;
XColor  *fg;
{
	int		seg_num;
	X3DGraphics	*graphics;
	XSegment	*segments;

	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X2D_draw_segments:\n");
	   fprintf (stderr,"\t unknown graphics id\n");
	   return;
	}

	seg_num = size/2;
	if (!(segments = (XSegment *) malloc ((unsigned) seg_num * 
			sizeof (XSegment))))
	{
	   fprintf (stderr,"X2D_draw_segments:\n");
	   fprintf (stderr,"\t not enough memory\n");
	   return;
	}

	if(!(_X2D_convert_wc_to_dc_seg(graphics, coords, segments, size)))
	{
	   free(segments);
	   return;
	}

	X3D_draw[graphics->device].draw_color(graphics, fg, FALSE);
	X3D_draw[graphics->device].segments(graphics, segments, seg_num);
        free(segments);
}



/************************************************************
*
*  MODULE NAME:  X2D_draw_line
*
*      PURPOSE:  Uses X11 graphics routine to create a single
*		 line.
*
*        INPUT: id        - X3D graphics structure ID
*		coord1    - the beginning world coordinate point
*		coord2    - the end world coordinate point
*
*       OUTPUT: displays a line (or a set of lines) to graphics workstation
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young
*
*************************************************************/


X2D_draw_line (id, coord1, coord2, fg)

int	id;
Coord	coord1,	coord2;
XColor  *fg;
{
	X3DGraphics	*graphics;
	XPoint		pt1, pt2;

	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X2D_draw_line:\n");
	   fprintf (stderr,"\t unknown graphics id\n");
	   return;
	}

	if(!(_X2D_convert_wc_to_dc(graphics, &coord1, &pt1, 1)))
	   return;

	if(!(_X2D_convert_wc_to_dc(graphics, &coord2, &pt2, 1)))
	   return;

	X3D_draw[graphics->device].draw_color(graphics, fg, FALSE);
	X3D_draw[graphics->device].line(graphics, pt1.x, pt1.y, pt2.x, pt2.y);
}




/************************************************************
*
*  MODULE NAME:  X2D_draw_rectangle
*
*      PURPOSE:  Uses X11 graphics routines to create a
*		 rectangle
*
*        INPUT: id        - X3D graphics structure ID
*		coord1    - the beginning world coordinate point
*		width, height    - the end world coordinate point
*
*       OUTPUT: displays a line (or a set of lines) to graphics workstation
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young
*
*************************************************************/


X2D_draw_rectangle (id, coord1, width, height, fg)

int	id;
Coord	coord1;
Real	width, height;
XColor  *fg;
{
	X3DGraphics	*graphics;
	Coord		coord2;
	XPoint		pt1, pt2;

	int		x, y;
	unsigned int	w, h;


	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X2D_draw_rectangle:\n");
	   fprintf (stderr,"\t unknown graphics id\n");
	   return;
	}

	if(!(_X2D_convert_wc_to_dc(graphics, &coord1, &pt1, 1)))
	   return;

	coord2.x = coord1.x + width;
	coord2.y = coord1.y + height;
	if(!(_X2D_convert_wc_to_dc(graphics, &coord2, &pt2, 1)))
	   return;

	x = MIN(pt1.x, pt2.x);
	y = MIN(pt1.y, pt2.y);
	w = ABS(pt2.x - pt1.x);
	h = ABS(pt2.y - pt1.y);
	X3D_draw[graphics->device].draw_color(graphics, fg, FALSE);
	X3D_draw[graphics->device].rectangle(graphics, x, y, w, h);
}




/************************************************************
*
*  MODULE NAME:  X2D_draw_colorline
*		 static draw_colorline()
*
*      PURPOSE:  Draws a multi-colored line according to the
*		 different color levels.  X2D_draw_colorline()
*		 is a frontend for the real routine static 
*		 draw_colorline().
*
*		 X2D_draw_colorline gets the graphics structure,
*		 perpares the contour levels by making sure they
*		 are sorted in ascending order, converts the world
*		 coordinates to device coordinates, then calls
*		 draw_colorline to actually draw the multi-colored
*		 line.
*
*		 draw_colorline is the real routine that computes
*		 the different colored line segments and draws them.
*
*        INPUT:  id - the xvgraphics id
*		 coords - coordinates that make up the line
*		 size   - number of coordinates
*		 levels - level divisions at which each new color will begin
*		 pixels - pixel values (color) for each level
*		 num_levels - number of levels
*
*       OUTPUT:  a multi-colored line
*
*    CALLED BY:  application program
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/


X2D_draw_colorline(id, coords, size, levels, colors, num_levels)

int	 id;
Coord	 *coords;
int      size, num_levels;
Real     *levels;
XColor	 *colors;
{
	X3DGraphics	*graphics;
	XPoint		*points;

	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X2D_draw_colorline:\n");
	   fprintf (stderr,"\t unknown graphics id\n");
	   return;
	}

	if (!(points = (XPoint *) malloc ((unsigned) size * sizeof (XPoint))))
	{
	   fprintf (stderr,"X2D_draw_colorline:\n");
	   fprintf (stderr,"\t not enough memory\n");
	   return;
	}

	if(!(_X2D_convert_wc_to_dc(graphics, coords, points, size)))
	{
	   free(points);
	   return;
	}

	/*
	 *  Sort contours in ascending order.
	 *
	 sort_contour(levels, &contours, colors, &colors, num_levels);
	 */

	/*
	 *  Call draw_colorline() to compute the different colored line
	 *  segments and draw them.
	 */
	draw_colorline(graphics, coords, points, size, levels, colors,
		       num_levels);
	free(points);
}



/************************************************************
*
*  MODULE NAME:  draw_colorline()
*
*      PURPOSE:  Draws a multi-colored line according to the
*		 different color levels.
*
*		 draw_colorline is the real routine that computes
*		 the different colored line segments and draws them.
*		 This is done in a seperate routine in order to speed
*		 up the graphics processing by avoiding the costly
*		 setup time required for X2D_draw_colorline().
*		 draw_colorline runs thru the coordinates finding
*		 the contour level indexes for a given line segment.
*		 If the levels are the same then the line is drawn
*		 with that color, otherwise the line is divided into
*		 segements for each contour level for the given line.
*
*        INPUT:
*
*       OUTPUT:  
*
*    CALLED BY:  internal graphics routines
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/


static void draw_colorline(graphics, coords, points, size, levels, colors, num)

X3DGraphics	*graphics;
Coord		*coords;
XPoint		*points;
int		size, num;
Real		*levels;
XColor		*colors;
{
	int	i, index1, index2;
	XPoint	start, end;
	Coord   point;

	index1 = find_level(coords[0].y, levels, num);
	X3D_draw[graphics->device].draw_color(graphics, &colors[index1], TRUE);

	for (i = 1; i < size; i++)
	{
	    index2 = find_level(coords[i].y, levels, num);

	    if (index1 == index2)
	    {
	       X3D_draw[graphics->device].line(graphics, points[i -1].x,
			points[i -1].y, points[i].x, points[i].y);
	    }
	    else
	    {
	       start = points[i -1];

	       if (index2 < index1)
	       {
	          while (index1 != index2)
	          {
		     /*
		      *  Compute the end point for 
		      */
		     point.x = CINTRP(coords[i-1].x, coords[i].x, coords[i-1].y,
				      coords[i].y, levels[index1]);
		     point.y = levels[index1];

		     if (_X2D_convert_wc_to_dc(graphics, &point, &end, 1))
		     {
			X3D_draw[graphics->device].draw_color(graphics,
				&colors[index1], TRUE);
	                X3D_draw[graphics->device].line(graphics, start.x,
			        start.y, end.x, end.y);
		     }

		     /*
		      *  Save the end of the segment as the start of the new
		      *  segment.
		      */
		     start = end;
		     index1--;
	          }
		  X3D_draw[graphics->device].draw_color(graphics,
				&colors[index2], TRUE);
	          X3D_draw[graphics->device].line(graphics, start.x,start.y,
			   points[i].x, points[i].y);
	       }
	       else
	       {
	          while (index1 != index2)
	          {
		     /*
		      *  Compute the end point for 
		      */
		     point.x = CINTRP(coords[i-1].x, coords[i].x, coords[i-1].y,
				      coords[i].y, levels[index1 +1]);
		     point.y = levels[index1 +1];

		     if (_X2D_convert_wc_to_dc(graphics, &point, &end, 1))
		     {
			X3D_draw[graphics->device].draw_color(graphics,
				&colors[index2], TRUE);
	                X3D_draw[graphics->device].line(graphics, start.x,
			         start.y, end.x, end.y);
		     }

		     /*
		      *  Save the end of the segment as the start of the new
		      *  segment.
		      */
		     start = end;
		     index1++;
	          }
		  X3D_draw[graphics->device].draw_color(graphics,
				&colors[index2].pixel, TRUE);
	          X3D_draw[graphics->device].line(graphics, start.x,start.y,
			   points[i].x, points[i].y);
	       }
	    }
	}
}

static int find_level(value, levels, num)

Real	value, *levels;
int	num;
{
	int	index = num -1;

	while (value < levels[index] && index > 0)
	   index--;

	return(index);
}



/************************************************************
*
*  MODULE NAME: _X2D_clip_segs
*
*      PURPOSE: use Cohen-Sutherland to clip 2D world coordinates to
*		the viewport.
*
*
*        INPUT:
*
*       OUTPUT: 
*
*    CALLED BY: application program
*
*   WRITTEN BY:	Mike Lang & Mark Young
*
*************************************************************/

int _X2D_clip_segs(coords,size,segments,seg_size,graphics)
X3DGraphics *graphics;
XSegment *segments;
Coord *coords;
int size, *seg_size;
{
Real x1,y1,x2,y2;
int i,new_size=0;
Coord tmp_coord[2];
	for(i=0;i<(size-1);i++)
	{
		x1 = coords[i].x;
		y1 = coords[i].y;
		x2 = coords[i+1].x;
		y2 = coords[i+1].y;
		if(Cohen_Sutherland(&x1,&y1,&x2,&y2,graphics) != -1)
		{ 
			/* its been clipped so convert it to dc and assign it */
			
			tmp_coord[0].x = x1;
			tmp_coord[0].y = y1;
			tmp_coord[1].x = x2;
			tmp_coord[1].y = y2;
			if(!(_X2D_convert_wc_to_dc_seg (graphics, tmp_coord, 
			     segments+new_size, (int)2)))
	   			return(0);
			new_size++;
		}
		
	}
	*seg_size = new_size;
	return(1);
}



#undef TOP
#define TOP    (unsigned char)8
#undef BOTTOM
#define BOTTOM (unsigned char)4
#undef RIGHT
#define RIGHT  (unsigned char)2
#undef LEFT
#define LEFT   (unsigned char)1

unsigned char compute_outcode(x,y,graphics)
X3DGraphics *graphics;
Real x,y;
{
unsigned char outcode;

	outcode=0;
	if(x < graphics->wc_min.x)
		outcode = outcode | LEFT;
	if(x > graphics->wc_max.x)
		outcode = outcode | RIGHT;
	if(y < graphics->wc_min.y)
		outcode = outcode | BOTTOM;
	if(y > graphics->wc_max.y)
		outcode = outcode | TOP ;
	return(outcode);
	
}



/************************************************************
*
*  MODULE NAME: _X2D_clip_points
*
*      PURPOSE: use Cohen-Sutherland to clip 2D world coordinates to
*		the viewport.
*
*
*        INPUT:
*
*       OUTPUT: 
*
*    CALLED BY: application program
*
*   WRITTEN BY:	Mike Lang & Mark Young
*
*************************************************************/

int _X2D_clip_points(coords, size, new_coords, graphics)

X3DGraphics *graphics;
int	    *size;
Coord	    *coords, *new_coords;
{
	int i, new_size = 0;
	unsigned char outcode;

	for(i = 0; i < *size; i++)
	{
	   outcode = compute_outcode(coords[i].x, coords[i].y, graphics);
	   if (outcode == 0)
	   {
		new_coords[new_size].x = coords[i].x;
		new_coords[new_size].y = coords[i].y;
		new_coords[new_size].d = coords[i].d;
		new_size++;
	   }
	}
	*size = new_size;
	return(1);
}



int Cohen_Sutherland(x1,y1,x2,y2,graphics)
Real	*x1,*y1,*x2,*y2;
X3DGraphics *graphics;
{
	/* compute outcodes */
	unsigned char outcode1,outcode2;
	float temp;
	
	outcode1 = compute_outcode(*x1,*y1,graphics);
	outcode2 = compute_outcode(*x2,*y2,graphics);
	if(outcode1==0 && outcode2==0) return(0);	/* inside */
	if((outcode1&outcode2) != 0) return(-1);	/* outside */
	else
	 while((outcode1|outcode2) != 0) 		/* if one is outside */
	 {
	   if (outcode1 == 0)	/* swap p1 and p2 */
	   {
		outcode1=outcode2;
		temp = (*x1); (*x1)=(*x2); (*x2)=temp;
		temp = *y1; *y1= *y2; *y2=temp;
	   }
	   /* find intersection */
	   if((outcode1 & TOP) == TOP)
		intersect(x1,y1,*x2,*y2,graphics,TOP);
	   else if ((outcode1 & BOTTOM) == BOTTOM)
		intersect(x1,y1,*x2,*y2,graphics,BOTTOM);
	   else if ((outcode1 & RIGHT) == RIGHT)
		intersect(x1,y1,*x2,*y2,graphics,RIGHT);
	   else if ((outcode1 & LEFT) == LEFT)
		intersect(x1,y1,*x2,*y2,graphics,LEFT);
	   /* recompute the outcodes */
	   outcode1 = compute_outcode(*x1,*y1,graphics);
	   outcode2 = compute_outcode(*x2,*y2,graphics);
	   if((outcode1&outcode2) != 0) return(-1);	/* outside */
	  }
	  return(0);
}

intersect(x1,y1,x2,y2,graphics,side)
Real	*x1,*y1,x2,y2;
unsigned char side;
X3DGraphics *graphics;
{
Real inter_x,inter_y;

   
	if(side == TOP) {
	   inter_x = (*x1) + (((*x1) - x2)/((*y1) - y2))*
			  (graphics->wc_max.y - (*y1));
	   inter_y  = graphics->wc_max.y;
	}
  	else if(side == BOTTOM) {
	   inter_x = (*x1) + (((*x1) - x2)/((*y1) - y2))*
			  (graphics->wc_min.y - (*y1));
	   inter_y  = graphics->wc_min.y;
	}
	else if(side == RIGHT) {
	   inter_y  = (*y1) + (((*y1) - y2)/((*x1) - x2))*
			   (graphics->wc_max.x - (*x1));
	   inter_x  = graphics->wc_max.x;
	}
	else if(side == LEFT) {
	   inter_y  = (*y1) + (((*y1) - y2)/((*x1) - x2))*
			   (graphics->wc_min.x - (*x1));
	   inter_x  = graphics->wc_min.x;
   	}
	*x1 = inter_x;
	*y1 = inter_y;
}
