/*
 * Copyright 1988 Anant Agarwal
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation.  No representations about the suitability of this software
 * for any purpose.  It is provided "as is" without express or implied 
 * warranty.
 *
 * Author:  Anant Agarwal, MIT Laboratory for Computer Science
 */

#include <strings.h>	
#include <stdio.h>
#include <math.h>
#include "plotio.h"
#include "defs.h"
#include "structs.h"
#include "plot.h"

double getdegrees(), atan(), charheight(), charwidth();
double log10(), mylog(), fabs(), floor();

scaleobj(objptr)
LocalObjectType *objptr;
{
int z;
        objptr->scale = FALSE;
	for (z=0;z<=1;z++)
	{
	   /* from part */
	   switch (axis[z].scale.type)
	   {
		case linear:
 			objptr->from[z]=((objptr->from[z]-limits[z][minval])/
			   	(limits[z][maxval]-limits[z][minval]))
				 * graphsize[z];
		break;
		case logstype:
			if (objptr->from[z] <= 0)
			{
				fprintf(stderr,
				  "scaleobj error, negative value in log:\n");
			}
			else objptr->from[z]=
			   (
			    (
			      	mylog(objptr->from[z],axis[z].scale.base)-
			      	mylog(limits[z][minval],axis[z].scale.base)
			    )/
			    (
				mylog(limits[z][maxval],axis[z].scale.base)-
				mylog(limits[z][minval],axis[z].scale.base)
			    )
			   ) * graphsize[z];
		break;
		default:
			fprintf(stderr,
			   "****error::scaleobj: scale not implemented\n");
	   }

	   /* to part only for line type*/
	   if ((objptr->name == objline)||(objptr->name == objCurLine))
	   switch (axis[z].scale.type)
	   {
		case linear: objptr->un.line.to[z]=
			((objptr->un.line.to[z]-limits[z][minval])/
			(limits[z][maxval]-limits[z][minval])) * graphsize[z];
		break;
		case logstype:
			if (objptr->un.line.to[z] <= 0)
			{
				 fprintf(stderr,
				   "scaleobj error, negative value in log\n");
			}
			else objptr->un.line.to[z]=
			   (
			    (
				mylog(objptr->un.line.to[z],axis[z].scale.base)-
				mylog(limits[z][minval],axis[z].scale.base)
			    )/
			    (
				mylog(limits[z][maxval],axis[z].scale.base)-
				mylog(limits[z][minval],axis[z].scale.base)
			    )
		 	   ) * graphsize[z];
		break;
		default:
			fprintf(stderr,
			   "****error::scaleobj: scale not implemented\n");
	      }
    	}
	cmtopoints(objptr);
}


double mylog(num, base)
double num, base;
{
	if (num <= 0.0) 
	{
		fprintf(stderr,
		    "cannot take log of non-positive number, used a small number instead\n");
		num = SMALL;
	}
	return(log10(num) / log10(base));
}


double getdegrees(xlen, ylen)
double xlen , ylen;
{
double d;
	if (xlen == 0.0) d = BIG;
	else 	d = ylen / xlen;
	d = atan(fabs(d)) * 180.0 / 3.1415927;
	if ((ylen < 0)&&(xlen >= 0))  d= -d;
	else if ((ylen >= 0)&&(xlen < 0))  d= 180 - d;
	else if ((ylen < 0)&&(xlen < 0))  d = 180 + d;
	
	return(d);
}

double charwidth(f)
FontType f;
{
double a;
	a = FFwidth(f);
	a = a * 2.54 / 72;/* cms */
	return(a);
}

double charheight(f)/* returns cms */
FontType f;
{
double a;
	a = FFheight(f);
	a = a * 2.54 / 72 ;/* cms */
	return(a);
}

cmtopoints(objptr) /* also add translate to both co-ordinates */
LocalObjectType *objptr;
{
/* change cm to point and also throw in a 72 point offset from both sides */
int z;	
	for (z=0;z<=1;z++)
	switch (objptr->name)
	{
		case objtext:
 			objptr->from[z] = 
				translate +  objptr->from[z] * 72.0 / 2.54;
			break;
		case objsymbol:
 			objptr->from[z] = 
				translate +  objptr->from[z] * 72.0 / 2.54;
			break;
		case objline:
 			objptr->from[z] = 
				translate +  objptr->from[z] * 72.0 / 2.54;
 			objptr->un.line.to[z] = 
				translate + objptr->un.line.to[z] * 72.0/2.54;
			break;
		case objCurLine:
 			objptr->from[z] = 
				translate +  objptr->from[z] * 72.0 / 2.54;
 			objptr->un.line.to[z] = 
				translate + objptr->un.line.to[z] * 72.0/2.54;
			break;
		case objLineStartFlag: 
 			objptr->from[z] = 
				translate +  objptr->from[z] * 72.0 / 2.54;
		break;
		default:
		break;
	}
}

calcmaxmin(z)
int z;
{
double pmax, pmin;
double pmaxp, pminp, pintp;
int c=0;
pointType *ptPtr;/* current point */
boolean firsttime = TRUE;
    	while ((curves[c] != nil) && ((curves[c])->validcurve))
	{
		ptPtr = (curves[c])->fstPtr;
		if (((curves[c])->include)&&(firsttime))
		{
			firsttime = FALSE;
			pmax = ptPtr->pt[z];
			pmin = ptPtr->pt[z];
		}
		if ((curves[c])->include)
		while (ptPtr != nil)
		{
			if (pmax < ptPtr->pt[z]) pmax = ptPtr->pt[z];
			if (pmin > ptPtr->pt[z]) pmin = ptPtr->pt[z];
			ptPtr = ptPtr->nxtPtr;
		}
		c++;
	}
	if (axis[z].axismin == BIG) pminp = pmin;
	else pminp = pmin = axis[z].axismin;

	if (axis[z].axismax == BIG) pmaxp = pmax;
	else pmaxp = pmax = axis[z].axismax;

	if (axis[z].scale.type == linear)
		CallDefLimits(pmax, pmin, &pmaxp, &pminp, &pintp);
	else if ((pmax <= 0.0)||(pmin <= 0.0))
	{
		   fprintf(stderr,
		   "splot error: Zero or negative limits on log axis\n");
		   exit(1);
	}

	if (axis[z].axismin == BIG)
	{
		axis[z].axismin = pminp;
		limits[z][minval] = pminp;
	}
	if (axis[z].axismax == BIG)
	{
		axis[z].axismax = pmaxp;
		limits[z][maxval] = pmaxp;
	}

	if (axis[z].interval == 0.0)
	{
	    if (axis[z].scale.type != linear) pintp = 1.0;
	    axis[z].interval = pintp;
	}
}

CallDefLimits(pmax, pmin, pmaxp, pminp, pintp)
double pmax, pmin, *pmaxp, *pminp, *pintp;
{
/* courtesy Scott McFarling */
double del, zdel, ntics;
double fudge = 1.0;
	if (pmax == pmin) return;
	del = ceil(
		   pow(10.0 , 
		         fudge * 
		         log10( 
			    fabs(
			    	 (pmax-pmin)/9.0
			        ) 
			      ) -
		         floor(
		           log10( 
			         fabs(
			    	      (pmax-pmin)/9.0
			             ) 
			       ) 
			      )
		     )
		  ) / fudge;
	*pintp = del * 
	      pow(10.0, 
			floor(
				log10(
					fabs(
						pmax - pmin
					    )
					    / 9.0
				     )
			     )
		  );
	
	*pminp = floor(pmin / *pintp) * *pintp;
	ntics = ceil((pmax - *pminp) / *pintp);
	*pmaxp = *pminp + *pintp * ntics;
	if (*pminp == *pmaxp)
	{
		fprintf(stderr, 
		   "splot warning: could not choose proper axis limits, please set them\n");
		*pmaxp = 1.0;
	}
	if (*pintp == 0)
	{
		fprintf(stderr, 
		   "splot warning: could not choose proper interval, please set it\n");
		*pintp = (*pmaxp - *pintp) / 10;
	}
}
