/*===========================================================================
  Copyright (C) 1995-2009 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*
 * HEADER : aglinit.c      - Vers 3.6.004  - Sep 1994 -  L. Fini, OAA
 *                         - Vers 3.6.003  - Aug 1994 -  L. Fini, OAA
 *                         - Vers 3.6.002  - Feb 1994 -  L. Fini, OAA
 *                         - Vers 3.6.001  - Sep 1993 -  L. Fini, OAA
 *                         - Vers 3.6.000  - Oct 1991 -  L. Fini, OAA

 090902		last modif (KB)

*/




/*                       AGL INITIALIZATIONS ROUTINES                        */
/*                       PLUS SOME TIME CRITICAL FUNCTIONS                   */




#include <midas_def.h>

#include <aglenvr.h>


/*                       AGL STATUS DEFINITION                              */



int AGL_wasinit=0x00;			/* AGL initialization status         */

struct AGL_STATUS AGL_status;

FILE *AGL_err=NULL;			/* Error output file (or stderr)     */

					/**************************************/
					/* MISCELLANEOUS VARIABLES            */

int AGL_DEBUG = FALSE;			/* Debugging flag                     */

#ifndef NO_METAFILE_SUPPORT

char *AGL_mfhead = MFHEAD;

#endif



static char *err_stack[ERRSTACKLNG];	/* Routine names stack               */
static int  stack_pointer;		/* Stack pointer                     */
static int  scan_pointer;


void AGL_push(name)			/* Push a routine name into stack    */
					/* N.B.: Only the pointer is pushed, */
					/* So the string name must be static */
char *name;
{
if(stack_pointer<ERRSTACKLNG)
	err_stack[stack_pointer++]=name;
scan_pointer=stack_pointer;
}


void AGL_pop()				/* Pops a name from stack            */
{
if(stack_pointer>0)
	stack_pointer--;
scan_pointer=stack_pointer;
}


char *AGL_top()				/* Returns topmost name from stack   */
					/* Stack is not modified             */
{
scan_pointer=stack_pointer;
if(stack_pointer>0)
	return err_stack[stack_pointer-1];
else
	return NULL;
}


char *AGL_scan()			/* returns names from stack in       */
					/* reverse order, one for each call  */
					/* The routine is reset with a call  */
					/* to any stack manipulation routine */
{
if(scan_pointer>0)
	return err_stack[--scan_pointer];
else {
	scan_pointer=stack_pointer;
	return NULL;
}
}

/****************************************************************************/
/*                          setdev (Internal AGL use)                       */

/* set up the driver entry point table for a single device                  */


static void setdev(dvnam,curs,eras,escp,init,send,term,poly)
char *dvnam;                           /* Driver name                      */
int (*curs)(),(*eras)(),(*escp)();     /* Driver entry points              */
int (*init)(),(*send)();
int (*term)(),(*poly)();
{

if (AGL_status.ndevs < NDRIVERS) {

	strcpy(AGL_status.drvname[AGL_status.ndevs],dvnam);
	AGL_status.drvtab[AGL_status.ndevs][0] = curs;
	AGL_status.drvtab[AGL_status.ndevs][1] = eras;
	AGL_status.drvtab[AGL_status.ndevs][2] = escp;
	AGL_status.drvtab[AGL_status.ndevs][3] = init;
	AGL_status.drvtab[AGL_status.ndevs][4] = send;
	AGL_status.drvtab[AGL_status.ndevs][5] = term;
	AGL_status.drvtab[AGL_status.ndevs][6] = poly;
	AGL_status.ndevs++;
	AGL_status.errstat=AGLNOERR;
} else
	AGL_status.errstat= DEVOVFSEV;
}



#define DEF(e1) extern void e1()

#include "aglddef.c"


/*****************************************************************************/
/*                        AGL_term (AGL internal use)                        */

/* Reset AGL status                                                          */

void AGL_term()
{
int i;
void AGL_fvwp();

AGL_vflsh();				/* Empty viewport buffer           */

for(i = 0;i<MAXVWPTS;i++)
	if(AGL_status.vwpts[i] != NULL) {	/* For all viewports...     */

#ifndef NO_METAFILE_SUPPORT
		if((AGL_status.vwpts[i])->metafile!=NULL)/* Close metafile  */
			fclose((AGL_status.vwpts[i])->metafile);
#endif
      
		AGL_fvwp(i);		/* Free viewport dynamic block     */
}

for(i = 0; i<MAXACTIVE; i++)		/* For all active devices.....    */
	if(ACTREQST(i) > 0) 
		AGL_dstop(i);		/* stop device                    */

if ( AGL_err != stderr ) 
	fclose(AGL_err);		/* Close error stream             */
}
   


/*****************************************************************************/
/*                        AGL_stop (AGL internal use)                         */

/* Reset AGL status and terminate process                                    */

void AGL_stop()
{
AGL_term();				/* Reset status                      */
exit(0);				/* Terminate process                 */
}




/*****************************************************************************/
/*                         AGL_init (Internal AGL use)                        */

/* This routine is called the first time a viewport is defined in order to   */
/* initialize static global parameters of the library                        */

void AGL_init()
{
int i;

AGL_status.errstat=AGLNOERR;

if(!(AGL_wasinit&AGL_INIT)) {
	AGL_status.curvwp = VWPEMPTY;
	AGL_status.vwpoint = NULL;
	stack_pointer=0;
	scan_pointer=0;

	for(i=0;i<MAXVWPTS;i++) 
		AGL_status.vwpts[i] = NULL;
	for(i=0;i<MAXACTIVE;i++) 
		ACTREQST(i) = 0;
	AGL_status.ersonst = TRUE;
	AGL_status.sevmsg = AG_WARNING;
	AGL_status.sevterm = AG_SEVERE;

	if(AGL_err==NULL) 
		AGL_err = stderr;

	AGL_cginit();		/* Init character generation support   */
	drvinit();		/* Init driver entry points table      */
	AGL_wasinit |= AGL_INIT;
}
}





/*****************************************************************************/
/*                          makecmd (Internal AGL Use)                       */

/* Builts the device close O.S. command (also store related filename)        */

static void makecmd(slot,cmd,fname)
int  slot;                     /* device slot                               */
char *cmd;                     /* Command string with % at file name place  */
char *fname;                   /* File name to insert into string           */
{
char *pos;
char *cmbuf = DEVCOMMND(slot);
char *dst = DEVCOMMND(slot);
char *src = cmd;
int prc = '%';

AGL_status.errstat = AGLNOERR;

strncpy(FILNAM(slot),fname,PHNAMLNG);

if(*cmd == '\0') 
	return;

if ((strlen(src)+strlen(fname)) >= (unsigned int) DEVCMDLNG ) {
	AGL_status.errstat = CMDBOVFWNG;
	return;
}

pos = strchr(src,prc);

if(pos != NULL) {
	while(src<pos) 
		*dst++ = *src++;	/* Copy first part of cmd        */
	*dst = '\0';
	strcat(cmbuf,fname);		/* Copy filename                 */
	src++;
	strcat(cmbuf,src);		/* Copy last part of cmd         */
} else
	strcpy(cmbuf,cmd);

src=cmbuf;
while(*src) { 				/* get rid of '\n'                */
	*src = (*src == '\n') ? '\0' : *src;
	src++;
}
}






/*****************************************************************************/
/*                          setdevpar (Internal AGL Use)                     */

/* Move device parameters into data structure                                */


static int setdevpar(combuf)
struct bufcom *combuf;
{
int device=DY(devidx);
                                          /* Integer parameters              */
FLAGS(device)   	= combuf->INTB[1];
NPLANS(device)  	= combuf->INTB[2];
DEFFOREGR(device) 	= combuf->INTB[8];

AGLBLACK(device) 	= combuf->INTB[9];
AGLRED(device) 		= combuf->INTB[10];
AGLGREEN(device) 	= combuf->INTB[11];
AGLBLUE(device) 	= combuf->INTB[12];
AGLYELLOW(device) 	= combuf->INTB[13];
AGLMAGENTA(device) 	= combuf->INTB[14];
AGLCYAN(device) 	= combuf->INTB[15];
AGLWHITE(device) 	= combuf->INTB[16];

if(AGL_wasinit&AGL_BKGPRESET) 
	DEFBACKGR(device)	= combuf->INTB[8+AGL_status.DefBkgr];
else 
	DEFBACKGR(device) 	= combuf->INTB[7];
  
MAXLWIDTH(device)= combuf->INTB[6];
                                          /* FLOAT  parameters               */
XLENG(device) = combuf->FLTB[6];
YLENG(device) = combuf->FLTB[7];
XMAXL(device) = combuf->FLTB[8];
YMAXL(device) = combuf->FLTB[9];
XCURL(device) = combuf->FLTB[0];
YCURL(device) = combuf->FLTB[1];
                                          /* Compute some more parameters    */
XPIXELS(device) = combuf->INTB[3];
YPIXELS(device) = combuf->INTB[4];
RSLX(device) = 1./(XPIXELS(device)-1);
RSLY(device) = 1./(YPIXELS(device)-1);
RATYX(device) =  combuf->FLTB[1]/combuf->FLTB[0] ;
RATXY(device) =  combuf->FLTB[0]/combuf->FLTB[1] ;
DOTLEN(device) = (XLENG(device)/XCURL(device))*0.002;

CHARMULT(device)=combuf->FLTB[2];

if(combuf->INTB[5] != CURRDRV_VERS) 		/* Check version of driver    */
	return ILLDRVSEV;
else
	return AGLNOERR;
}




/*****************************************************************************/
/*                         AGL_sdrv (Internal AGL Use)                       */

/* Initializes driver entry points                                           */

/* This routine must be called every time a viewport is (re)activated        */

void AGL_sdrv()
{
int (*(*drvpnt))();			/* Device driver table pointer       */
drvpnt = DRVADDR(DY(devidx));

AGL_status.CURS_POINTER = *(drvpnt++);
AGL_status.ERAS_POINTER = *(drvpnt++);
AGL_status.ESCP_POINTER = *(drvpnt++);
AGL_status.INIT_POINTER = *(drvpnt++);
AGL_status.SEND_POINTER = *(drvpnt++);
AGL_status.TERM_POINTER = *(drvpnt++);
AGL_status.POLY_POINTER = *(drvpnt++);

AGL_status.CUsrTransf = DY(UsrTransf);
}





/****************************************************************************/
/*                        rdevfil (Internal AGL use)                        */

/* read specified file for device info                                      */

static int rdevfil(fil,dvnam,maxlng,driv,            /* return -1: no file,  */
                       sysaux,node,dcmd)            /*         0: no device */
                                                    /*         1: found     */

char *fil;                          /* Configuration file name             */
char *dvnam;                        /* device name                         */
int  maxlng;                        /* Max output string length            */
char *driv;                         /* Output device type (or driver name) */
char *sysaux;                       /* Auxiliary system info               */
char *node;                         /* Network node name                   */
char *dcmd;                         /* Device close command string         */
{
FILE *wrk;
char line[100], cbuf[PHNAMLNG];

char *ist, *pntr;
int is =(-1);
int i;

for(i=0;i<4;i=(i<<1)|0x1) {	/* Search standard directory hierarchy    */
	
	wrk = AG_STDO(fil,"",i);         /* search configuration file     */

	if ( wrk!=NULL ) {
		is=0;
		for(;;) {
			ist=AG_GETS(line,100,wrk);	/* get a line le  */
			if(ist==NULL) 
				break;
	
			pntr = AG_SCAN(ist,':',32,cbuf);
        
			if(AGL_scmp(cbuf,dvnam)) {
				AG_DMSG("From file:",line);
				pntr = AG_SCAN(pntr,':',maxlng,cbuf);
				pntr = AG_SCAN(pntr,':',maxlng,node);
				pntr = AG_SCAN(pntr,'\0',DEVCMDLNG,dcmd);
				pntr = AG_SCAN(cbuf,'.',maxlng,driv);
				pntr = AG_SCAN(pntr,':',maxlng,sysaux);
				if(*dcmd == '=') 
					strcpy(dcmd,(dcmd+1));
				is=1;
				break;
			}
		}
		fclose(wrk);
		if(is==1)
			break;
	} else 
		break;
}
return is;
}





/****************************************************************************/
/*                        getdvty (Internal AGL use)                        */

/* Get device type                                                          */
/* The routine gets from the AGLDEVS.DAT files the information about the    */
/* device.                                                                  */

static void getdvty(dvnam,maxlng,driv,sysaux,node,dcmd)
char *dvnam;			/* device identification (System dep)  */
int  maxlng;			/* Max output string length            */
char *driv;			/* Output device type (or driver name) */
char *sysaux;			/* Auxiliary system info               */
char *node;			/* Network node name                   */
char *dcmd;			/* Device close command string         */

{
static char *cnfile = "agldevs.dat";
int is, kk;
/*
char cbuf[PHNAMLNG];
char *pntr;
*/
extern char *AG_SCAN();
extern void AG_DMSG();



AGL_status.errstat=AGLNOERR;

*driv='\0'; 
*sysaux='\0'; 
*node='\0'; 
*dcmd='\0';

is = rdevfil(cnfile,dvnam,maxlng,driv,sysaux,node,dcmd);

if (is <= 0) 
   {				/* Device not found            */
   *dcmd='\0';


/* use postscript as the default device driver - KB, 020228  

	AGL_trns(DEVGLOBAL,maxlng,cbuf);
	AG_DMSG("AGLDEV=",cbuf);
	if(cbuf[0]=='\0') { 		/. Device not in configuration ./
		AGL_status.errstat=ILLDEVERR;
		return;
	}
	pntr=AG_SCAN(cbuf,'.',maxlng,driv);
	pntr=AG_SCAN(pntr,':',maxlng,sysaux);
*/

   (void) strcpy(driv,"pscript");
   kk = CGN_INDEXC(dvnam,'.');
   if (kk > 0) (void) strcat(driv,dvnam+kk);
   }


AG_DMSG("Driver:",driv);
AG_DMSG("SYSAUX:",sysaux);
AG_DMSG("Nodenm:",node);
AG_DMSG("Commnd:",dcmd);
}





/*****************************************************************************/
/*                       AGL_gdev (Internal AGL use)                          */

/* Attach the viewport to a device                                           */

/* The device name is firstly checked against the active device table. If it */
/* is not in use the device is opened (through the interf. rout. AGLINxxx)   */
/* and assigned the channel. If it is already in use the related channel is  */
/* passed back                                                               */

void AGL_gdev(device,xlng,ylng)
char *device;				/* device name                        */
double xlng,ylng;			/* Dimension requests                 */
{
char dnam[PHNAMLNG];
char driv[DRVNAMLNG];
char sysaux[PHNAMLNG];
char nodnam[PHNAMLNG];
char dcmd[DEVCMDLNG];
char *pt;
int err,is;
int clearflg,slot,id;
DEFINE_AGLDVCOM;
extern void AG_DMSG();
extern char *AG_SCAN();

AGL_status.errstat = AGLNOERR;
clearflg=TRUE;

pt=AG_SCAN(device,'.',PHNAMLNG,dnam);

AG_DMSG("Dev.select: ",device);
AG_DMSG("Name:",dnam);

if(strcmp(dnam,"tt") != 0 )
	AGL_trns(dnam,PHNAMLNG,dnam);	/* Translate environment variables */

AG_DMSG("Translated:",dnam);
AG_DMSG("USRAUX:",pt);

strcpy(CHARBUF,dnam);                   /* put phys. name into buffer      */

is = FALSE;
for(slot=0;slot<MAXACTIVE;slot++)        /* search device among active ones */
	if(ACTREQST(slot) != 0)
		if(strcmp(DEVNAM(slot),dnam)==0) { 
			is=TRUE; 
			break; 
		}

if(is) {
	DY(devidx)=slot; 		/* Device already active           */
	clearflg=FALSE;			/* No need to erase the device     */
} else {
					/* Device Activation        */
	getdvty(dnam,DRVNAMLNG,driv,sysaux,
	nodnam,dcmd);				/* get device type          */

	if(AGL_status.errstat!=AGLNOERR) return;
	is = FALSE;

	for(slot=0;slot<MAXACTIVE;slot++)	/* search a free slot        */
	if(ACTREQST(slot) == 0) { 
		is=TRUE; 
		break; 
	}

	if(!is) { 
		AGL_status.errstat=DEVOVFSEV;	/* No free slots available   */
		return; 
	}

	is = FALSE;				/* Search dev. driver name   */
	for(id = 0;id<AGL_status.ndevs;id++)
		if(strcmp(driv,AGL_status.drvname[id])==0)  { 
			is = TRUE; 
			break; 
		}

	if(!is) { 
		AGL_status.errstat=UNDDRVSEV;	/* Driver not found          */
		return; 
	}

	DRVADDR(slot) = &AGL_status.drvtab[id][0];/* Get driver table address*/
	ACTREQST(slot)=0;			/* Initialize viewport count */
	clearflg=TRUE;				/* the device must be erased */
}

DY(devidx)=slot;

AGL_sdrv();

if(clearflg) {
	char *pt0;

	IBUFFR(0)=0;			/* Activate init function          */
	RBUFFR(0) = xlng;
	RBUFFR(1) = ylng;
	if(AGL_status.ersonst)
		IBUFFR(1)=1;
	else
		IBUFFR(1)=0;

	pt0=CHARBUF;			/* In CHARBUF there is device name    */
	pt0=pt0+strlen(pt0)+1;
	strcpy(pt0,sysaux);		/* Put system auxiliary info       */
	pt0=pt0+strlen(sysaux)+1;
	strcpy(pt0,pt);			/* Put user auxiliary info         */
	pt0=pt0+strlen(pt)+1;
	strcpy(pt0,nodnam);		/* Put network node name           */
	pt0=pt0+strlen(nodnam)+1;
	*pt0='\0';
    
	INITFUNCT(AGLDVCOM);		/* Init device                 */
	AGL_status.errstat=ERRCODE;
	if(AGL_status.errstat>=ERRTRSH) 
		return;			/* Error return                */
	GRCHAN(slot)=CHANNEL; 

	*(DEVCOMMND(slot)) = '\0';
	*(FILNAM(slot)) = '\0';

	if(AGL_status.errstat<=INFOTRSH) 
		makecmd(slot,dcmd,CHARBUF);
}

strcpy(DEVNAM(slot),dnam);		/* Put name into active table      */
DY(curchan)=GRCHAN(slot);

ACTREQST(slot)++;

err=AGL_status.errstat;			/* Remember error status           */

IBUFFR(0)=1; CHANNEL=DY(curchan);
IBUFFR(5)=0;				/* Due to compatibility with older */
					/* drivers                         */
*(CHARBUF) = '\0';
INITFUNCT(AGLDVCOM);			/* get device characteristics      */
AGL_status.errstat = ERRCODE;
if(AGL_status.errstat>=ERRTRSH) 
	return;				/* Error return                     */

AGL_status.errstat=setdevpar(AGLDVCOM);		/* put params into strucure */

if(AGL_status.errstat != AGLNOERR) 
	return;				/* Error return                     */

if(clearflg&&AGL_status.ersonst&&(FLAGS(slot)&ERASEIT)) {
	CHANNEL=DY(curchan);			/* Erase screen             */
	IBUFFR(0)=DEFBACKGR(AGL_status.devid);
	RBUFFR(0) = 0.0;  RBUFFR(1) = 1.0;
	RBUFFR(2) = 0.0;  RBUFFR(3) = 1.0;
	ERASFUNCT(AGLDVCOM);
}
AGL_status.errstat=MAX(err,ERRCODE);              /* Remember worst error   */
}
  


/*****************************************************************************/
/*                   Clipping routines (Internal AGL use)                    */

/*    Two entry points are defined:                                          */

/*    aglclpi: for segments whose starting point is inside the clipping      */
/*             area                                                          */
/*    aglclpo: for segments whose starting point is outside the clipping     */
/*             area                                                          */

/*    Starting coordinates are held in global variables: x00,y00             */
/*    Starting status code is held in global variable:  stat0               */

/*    Both functions return next intersection point with the clipping area   */
/*    in the global variables: x01,y01                                       */

/*    The function return value is the cursor status of the point to reach   */

/*    Note: status codes define the position of a point with respect to the  */
/*          clipping area as showed in the following picture:                */

/*                   xlow       xup                                          */
/*                    |          |                                           */
/*           stat = 9 | stat = 8 | stat = 10                                 */
/*      yup ----------+----------+----------                                 */
/*           stat = 1 | stat = 0 | stat = 2                                  */
/*      ylow----------+----------+----------                                 */
/*           stat = 5 | stat = 4 | stat = 6                                  */
/*                    |          |                                           */

#define STATP(x,y) (((x<xlow)?1:((x>xup)?2:0))|((y<ylow)?4:((y>yup)?8:0)))

static double x00,y00;
static double auxdx,auxdy;
static double xlow,ylow,xup,yup;
static int stat0,stat1;



int aglclip(xv,yv,state,xc,yc)          /* returns TRUE if intersection      */
                                        /* Start coordinates and status are  */
                                        /* in global variables x00,y00,stat0 */
double xv,yv;                           /* End coordinates                   */
int    state;                           /* End point status                  */
float *xc,*yc;                          /* Output clipped coordinates        */
{
int stat;



auxdx=xv-x00; auxdy=yv-y00;

if(stat0!=0)
   stat=stat0;
else
   stat=state;

switch(stat)
   {
   case 8:			/* Intersection with horizontal top side */
   case 9:
      if (auxdy!=0.0) 
         {
	 *xc = x00+(yup-y00)*auxdx/auxdy;
	 *yc = yup;
	 return (STATP(*xc,*yc)==0);
         }
      return(FALSE);
   case 1:			/* Intersection with vertical left side */
   case 5:
      if (auxdx!=0.0) 
         {
         *xc = xlow;
         *yc = y00+(xlow-x00)*auxdy/auxdx;
         return (STATP(*xc,*yc)==0);
         }
      else
         return(FALSE);
   case 4:			/* Intersection with horizontal bottom side */
   case 6:
      if (auxdy!=0.0) 
         {
	 *xc = x00+(ylow-y00)*auxdx/auxdy;
	 *yc = ylow;
	 return (STATP(*xc,*yc)==0);
         }
      return(FALSE);
   case 2:			/* Intersection with vertical right side */
   case 10:
      if (auxdx!=0.0) 
         {
	 *xc = xup;
	 *yc = y00+(xup-x00)*auxdy/auxdx;
	 return (STATP(*xc,*yc)==0);
         }
      return(FALSE);
   }

return(0);
}

/*****************************************************************************/
/*                       AGL_padj (Internal AGL Use)                         */

/* Divides the input polyline into smaller pieces fitting into an output     */
/* polyline. Also transforms coordinates into normalized mode (if required)  */
/* and clip the resulting polylines against either the viewport or the clip- */
/* ping area depending on the polyline mode.                                 */

/* The input polyline structure (but not coordinate data therein) is modifi- */
/* ed after the call (pointers and counters will point to the first point    */
/* not fitting into output polyline).                                        */



static float Xpolybuf[AUXPOLYBUFLNG];
static float Ypolybuf[AUXPOLYBUFLNG];

static struct polyline A0poly = {
				AUXPOLYBUFLNG, 0, (-1), 
				Xpolybuf,Ypolybuf,
				NORMAL, NORMAL, FALSE, NULL
				};


struct polyline *AGL_padj(inpoly)	/* Return either pointer to output   */
struct polyline *inpoly;		/* polyline or NULL                  */

{
int ni = inpoly->nvects;
int convert=inpoly->grmode!=NORMAL;
int no =0;
int maxo = A0poly.maxvects-1;
int tstflaga = 0;

double xpn,ypn;

float *XI, *YI;
float *XO, *YO;





XI = inpoly->XV; 
YI = inpoly->YV;

XO = A0poly.XV; 
YO = A0poly.YV;
  
if (inpoly->clipmode!=NORMAL) 
   {
   xlow = XCLOW; 
   xup  = XCLUP;
   ylow = YCLOW; 
   yup  = YCLUP;
   } 
else
   {
   xlow = XVWLOW; 
   xup  = XVWUP;
   ylow = YVWLOW; 
   yup  = YVWUP;
   }

xpn = *XI++; ypn = *YI++; ni--;

if (convert) 				/* use `tstflaga' for flagging the */
   { 					/* AGL_status settings */
   if(AGL_status.xlogon)
      {                
      tstflaga = 1;
      if(xpn<=0.0)
         {
         AGL_status.errstat=NOLOGERR;
         stat0=(-1);
         goto second_point;
         }
      xpn=log(xpn);
      } 

   if(AGL_status.ylogon)
      {
      tstflaga = 2;
      if(ypn<=0.0)
         {
         AGL_status.errstat=NOLOGERR;
         stat0=(-1);
         goto second_point;
         }
      ypn=log(ypn);
      }

   if (ni > 5) tstflaga += 10;		/* use fast code only for many points */
 
   if(AGL_status.UTransf)
      {
      stat0=(*DY(UsrTransf))(&(xpn),&(ypn));
      xpn=(xpn*AGL_status.aglfcx)+AGL_status.aglofx;
      ypn=(ypn*AGL_status.aglfcy)+AGL_status.aglofy;

      if(stat0==(-1)) AGL_status.errstat=USRTRSERR;
      }
   else 
      {
      xpn=(xpn*AGL_status.aglfcx)+AGL_status.aglofx;
      ypn=(ypn*AGL_status.aglfcy)+AGL_status.aglofy;

      stat0=STATU(xpn,ypn);
      }
   }
else
   stat0 = STATP(xpn,ypn);


if (stat0==0) 
   {				/* Starting point is VISIBLE       */
   *XO++ = xpn; *YO++ = ypn;
   no++;
   }

second_point:
x00=xpn; y00=ypn;

if (tstflaga > 9) goto fast_section;


/* here the original code using macros */

for(;;) 
   { 
   xpn = *XI++; ypn = *YI++;
   if (convert) 
      { 
      CNVRT_BEGIN
      CNVRT_LOGX(stat1,xpn,ypn)
      CNVRT_LOGY(stat1,xpn,ypn)
      CNVRT_USRT0(stat1,xpn,ypn)
      CNVRT_USRT1(stat1,xpn,ypn)
      CNVRT_USER0(stat1,xpn,ypn)
      CNVRT_USER1(stat1,xpn,ypn)
      } 
   else
      stat1 = STATP(xpn,ypn);

   if (stat0==0) 
      {				/* last point was VISIBLE    */
      if (stat1!=0)  			/* current point not visible */
         aglclip(xpn,ypn,stat1,XO,YO);	/* Do clipping       */
      else 
         {
         *XO=xpn; *YO=ypn; 		/* Put coordinate    */
         }
      no++; XO++; YO++;
      } 
   else if (stat0==(-1)) 
      {				/* last point undefined      */
      if (stat1==0) 
         {			/* Current point VISIBLE     */
         *XO=xpn; *YO=ypn;	/* Put it as first of piece  */
         no++; XO++; YO++;
         }
      } 
   else 
      {				/* last point was NOT VISIBLE*/
      if ((stat1&stat0)==0) 
         { 		/* Clipping must be tested   */
         if (aglclip(xpn,ypn,stat1,XO,YO)) 
            {
            x00 = *XO++; y00 = *YO++; 
            no++; stat0=0;
            if (stat1==0) 
               {
               *XO=xpn; *YO=ypn;
               } 
            else 
               aglclip(xpn,ypn,stat1,XO,YO);

            no++; XO++; YO++;
            } 
         }
      }

   if(--ni<=0) break;

   x00=xpn; y00=ypn; stat0=stat1; 

   if ((no>=maxo)||((no>0)&&(stat0!=0))) 
      {
      XI--; YI--; ni++;
      break;
      }
   } 

inpoly->nvects=ni;
inpoly->XV = XI;
inpoly->YV = YI;

if ((A0poly.nvects=no)>0) 
   return &A0poly; 
else 
   return NULL;


/* here for (ni > 5) and (convert == 1) */

fast_section:
if(AGL_status.UTransf)
   {
   for(;;)
      {
      xpn = *XI++; ypn = *YI++;
      if(AGL_status.xlogon)
         {                
         if(xpn<=0.0)
            {
            AGL_status.errstat=NOLOGERR;
            stat1=(-1);
            goto next_a;
            }
         xpn=log(xpn);
         } 
      
      if(AGL_status.ylogon)
         {
         if(ypn<=0.0)
            {
            AGL_status.errstat=NOLOGERR;
            stat1=(-1);
            goto next_a;
            }
         ypn=log(ypn);
         }

      stat1=(*DY(UsrTransf))(&(xpn),&(ypn));
      xpn=(xpn*AGL_status.aglfcx)+AGL_status.aglofx;
      ypn=(ypn*AGL_status.aglfcy)+AGL_status.aglofy;

      if(stat1==(-1)) AGL_status.errstat=USRTRSERR;

     next_a:
      if (stat0==0)
         {                         /* last point was VISIBLE    */
         if (stat1!=0)                     /* current point not visible */
            aglclip(xpn,ypn,stat1,XO,YO);  /* Do clipping       */
         else
            {
            *XO=xpn; *YO=ypn;              /* Put coordinate    */
            }
         no++; XO++; YO++;
         }
      else if (stat0==(-1))
         {                         /* last point undefined      */
         if (stat1==0)
            {                      /* Current point VISIBLE     */
            *XO=xpn; *YO=ypn;      /* Put it as first of piece  */
            no++; XO++; YO++;
            }
         }
      else
         {                         /* last point was NOT VISIBLE*/
         if ((stat1&stat0)==0)
            {              /* Clipping must be tested   */
            if (aglclip(xpn,ypn,stat1,XO,YO))
               {
               x00 = *XO++; y00 = *YO++;
               no++; stat0=0;
               if (stat1==0)
                  {
                  *XO=xpn; *YO=ypn;
                  }
               else
                  aglclip(xpn,ypn,stat1,XO,YO);

               no++; XO++; YO++;
               }
            }
         }

      if(--ni<=0) break;

      x00=xpn; y00=ypn; stat0=stat1;

      if ((no>=maxo)||((no>0)&&(stat0!=0)))
         {
         XI--; YI--; ni++;
         break;
         }
      }
   }

else
   {
   register double xfc, xof, yfc, yof;

   xfc = AGL_status.aglfcx;
   xof = AGL_status.aglofx;
   yfc = AGL_status.aglfcy;
   yof = AGL_status.aglofy;

   if (tstflaga == 10) 
      {			/* printf("padj: inside the fastest section...\n"); */
      for(;;)
         {
         xpn = *XI++; 				/* keep data locally */
         xpn *= xfc;
         xpn += xof;

         ypn = *YI++;
         ypn *= yfc;
         ypn += yof;

         stat1=STATU(xpn,ypn);

         if (stat0==0)
            {                         /* last point was VISIBLE    */
            if (stat1!=0)                     /* current point not visible */
               aglclip(xpn,ypn,stat1,XO,YO);  /* Do clipping       */
            else
               {
               *XO=xpn; *YO=ypn;              /* Put coordinate    */
               }
            no++; XO++; YO++;
            }

         else if (stat0==(-1))
            {                         /* last point undefined      */
            if (stat1==0)
               {                      /* Current point VISIBLE     */
               *XO=xpn; *YO=ypn;      /* Put it as first of piece  */
               no++; XO++; YO++;
               }
            }

         else
            {                         /* last point was NOT VISIBLE*/
            if ((stat1&stat0)==0)
               {              /* Clipping must be tested   */
               if (aglclip(xpn,ypn,stat1,XO,YO))
                  {
                  x00 = *XO++; y00 = *YO++;
                  no++; stat0=0;
                  if (stat1==0)
                     {
                     *XO=xpn; *YO=ypn;
                     }
                  else
                     aglclip(xpn,ypn,stat1,XO,YO);
   
                  no++; XO++; YO++;
                  }
               }
            }
   
         if(--ni<=0) break;			/* exit loop */

         x00=xpn; y00=ypn; stat0=stat1;

         if ((no>=maxo) || ((no>0)&&(stat0!=0)))
            {
            XI--; YI--; ni++;
            break;
            }
         }
      }

   else
      {			/* printf("padj: inside the better section...\n");*/
      for(;;)
         {
         xpn = *XI++; ypn = *YI++;
         if(AGL_status.xlogon)
            {                
            if(xpn<=0.0)
               {
               AGL_status.errstat=NOLOGERR;
               stat1=(-1);
               goto next_b;
               }
            xpn=log(xpn);
            } 
         
         if(AGL_status.ylogon)
            {
            if(ypn<=0.0)
               {
               AGL_status.errstat=NOLOGERR;
               stat1=(-1);
               goto next_b;
               }
            ypn=log(ypn);
            }
   
         xpn=(xpn*xfc)+xof;
         ypn=(ypn*yfc)+yof;

         stat1=STATU(xpn,ypn);

        next_b:
         if (stat0==0)
            {                         /* last point was VISIBLE    */
            if (stat1!=0)                     /* current point not visible */
               aglclip(xpn,ypn,stat1,XO,YO);  /* Do clipping       */
            else
               {
               *XO=xpn; *YO=ypn;              /* Put coordinate    */
               }
            no++; XO++; YO++;
            }
         else if (stat0==(-1))
            {                         /* last point undefined      */
            if (stat1==0)
               {                      /* Current point VISIBLE     */
               *XO=xpn; *YO=ypn;      /* Put it as first of piece  */
               no++; XO++; YO++;
               }
            }
         else
            {                         /* last point was NOT VISIBLE*/
            if ((stat1&stat0)==0)
               {              /* Clipping must be tested   */
               if (aglclip(xpn,ypn,stat1,XO,YO))
                  {
                  x00 = *XO++; y00 = *YO++;
                  no++; stat0=0;
                  if (stat1==0)
                     {
                     *XO=xpn; *YO=ypn;
                     }
                  else
                     aglclip(xpn,ypn,stat1,XO,YO);
   
                  no++; XO++; YO++;
                  }
               }
            }

         if(--ni<=0) break;			/* exit loop */
   
         x00=xpn; y00=ypn; stat0=stat1;
   
         if ((no>=maxo)||((no>0)&&(stat0!=0)))
            {
            XI--; YI--; ni++;
            break;
            }
         }
      }
   }


inpoly->nvects=ni;
inpoly->XV = XI;
inpoly->YV = YI;

if ((A0poly.nvects=no)>0)
   return &A0poly;
else
   return NULL;

}
