plt - Software for 2D Plots 2.5

File: <base>/plt/classic/figure.c (6,489 bytes)
/*	plt/figure.c		Paul Albrecht		Feb 1988

	Copyright (C) Paul Albrecht 1988.  All rights reserved.

	Last Update:	May 21, 1989
	EMACS_MODES:	tabstop=4
*/


#include	"plt.h"
#include	"figs.h"
#include	"plot.h"
#include	"axis.h"



void	FigureInit( mode )
Mode	mode;
{
	Figure.xlPos = Figure.ylPos = FDEFAULT;
	Figure.xlDel = Figure.xlBoxScl = FDEFAULT;
}


/***************************************************************************/


FigureDef( type, coord, x0, y0, x1, y1, fgName )
char	type, *fgName;
double	x0, y0, x1, y1;
Const	coord;
{
FigPtr	f;

	if( Figure.nFigs == Figure.maxFigs )
		Figure.figs = (FigPtr)azmem(Figure.figs,&Figure.maxFigs,5,sizeof(*Figure.figs));

	f = &Figure.figs[Figure.nFigs++];

	f->type = type;
	f->coord = coord;
	f->x0 = x0;
	f->y0 = y0;
	f->x1 = x1;
	f->y1 = y1;
	f->fgName = fgName;

	if( f->coord == DATAC ) {
		minmax( x0, y0 );
		minmax( x1, y1 );
	}
}


FigureDraw( f )
FigPtr	f;
{
double	x, y, scl;
Ptype	x0, y0, x1, y1, dx, dy;

	x0 = f->x0;
	y0 = f->y0;
	x1 = f->x1;
	y1 = f->y1;

	transform( &x0, &y0, f->x0, f->y0, 0.0, f->coord );
	transform( &x1, &y1, f->x1, f->y1, 1.0, f->coord );
	FontGroupSelect( "f", f->fgName );

	switch( f->type ) {
		case ARROW:
			move( x1, y1 );
			cont( x0, y0 );
			x = (double)(x1-x0)/xinch;
			y = (double)(y1-y0)/yinch;
			scl = (old_ps == -1) ? 1 : old_ps/DEFAULT_PS;
			scl *= 0.08/sqrt(x*x+y*y) * (p->xinches+p->yinches)/14.0;
			x1 = x0 + scl*(x1-x0);
			y1 = y0 + scl*(y1-y0);
			dx = 0.4*scl*y*xinch + 0.5;
			dy = 0.4*scl*x*yinch + 0.5;
			move( x1+dx, y1-dy );
			cont( x0, y0 );
			cont( x1-dx, y1+dy );
			break;
		case BOX:
			move( x0, y0 );
			cont( x0, y1 );
			cont( x1, y1 );
			cont( x1, y0 );
			cont( x0, y0 );
			break;
		case DARKBOX:
			PolyDef( x0, y0, CMOVE );
			PolyDef( x0, y1, CCONT );
			PolyDef( x1, y1, CCONT );
			PolyDef( x1, y0, CCONT );
			PolyDef( x0, y0, CFILL );
			break;
		case CONNECT:
			move( x0, y0 );
			cont( x1, y1 );
			break;
	}
}

minmax( x, y )
double	x, y;
{
	if( x != DEFAULT ) {
		if( x < xmin )
			xmin = x;
		else
			if( x > xmax )
				xmax = x;
	}
	if( y != DEFAULT ) {	
		if( y < ymin )
			ymin = y;
		else
			if( y > ymax )
				ymax = y;
	}
}


transform( xp, yp, xdbl, ydbl, dflt, coord )
Ptype	*xp, *yp;
double	xdbl, ydbl, dflt;
Const	coord;
{
	switch( coord ) {
		case DATAC:
			if( xdbl == DEFAULT )
				*xp = dflt*(xwmax-xwmin)+xwmin+0.5;
			else
				*xp = X(xdbl) + 0.5;
			if( ydbl == DEFAULT )
				*yp = dflt*(ywmax-ywmin)+ywmin+0.5;
			else
				*yp = Y(ydbl) + 0.5;
			break;
		case WINC:
			*xp = ((xdbl == DEFAULT) ? dflt : xdbl)*(xwmax-xwmin) + xwmin+0.5;
			*yp = ((ydbl == DEFAULT) ? dflt : ydbl)*(ywmax-ywmin) + ywmin+0.5;
			break;
		case PDEVC:
			*xp = xdbl + 0.5;
			*yp = ydbl + 0.5;
		break;
	}
}


LegendDef( lineNum, pltNum, name )
long	lineNum, pltNum;
char	*name;
{
LegPtr	l;

	if( Figure.nLegs == Figure.maxLegs )
		Figure.legs = (LegPtr)azmem(Figure.legs,&Figure.maxLegs,5,sizeof(*Figure.legs) );

	l = &Figure.legs[Figure.nLegs++];
	l->lineNum = lineNum;
	l->pltNum = pltNum;
	l->text = name;
}


LegendDraw()
{
PltPtr	plt;
LegPtr	l;
double	gray;
Ptype	n, xb0, yb0, xba, xb1, yb1, xMargin, yMargin, textWidth,
		x, y, x0, x1, xsize, ysize;
Boolean	lineSeg, havePlts;

	if( Figure.xlPos == DEFAULT )
		Figure.xlPos = 0.7;
	if( Figure.ylPos == DEFAULT )
		Figure.ylPos = 0.85;
	if( Figure.xlDel == DEFAULT )
		Figure.xlDel = 1.0;

	Figure.xlPos = xa.min + Figure.xlPos*(xa.max-xa.min);
	Figure.ylPos = ya.min + Figure.ylPos*(ya.max-ya.min);
	if( Figure.xlDel < 0.25 )
		Figure.xlDel /= 0.05;

	havePlts = lineSeg = NO;

	xba = X(Figure.xlPos);
	yb0 = Y(Figure.ylPos);
	yb1 = p->yfull;
	textWidth = 0;

	FontGroupSelect( "f", Figure.legfg );
	xMargin = chwd;
	yMargin = chht/3;

	for( n=0;  n < Figure.nLegs;  n++ ) {
		l = &Figure.legs[n];
		if( l->lineNum == DEFAULT )
			l->lineNum = n;
		strsize( l->text, &xsize, &ysize, 0.0 );
		l->yPos = yb0 - ysize*(3*l->lineNum+2)/3 - yMargin;
		if( yb1 > l->yPos )
			yb1 = l->yPos;
		if( xsize > textWidth )
			textWidth = xsize;
		if( l->pltNum == DEFAULT )
			continue;
		if( l->pltNum < 0 || l->pltNum >= Plot.nPlts ) {
			err( YES, "Bad plot number %d for legend", l->pltNum );
			continue;
		}
		havePlts = YES;
		plt = &Plot.plts[l->pltNum];
		if( plt->pm != SCATTER && plt->pm != SCATTER_STD )
			lineSeg = YES;
	}
	if( (fixed_font && Figure.xlBoxScl != 0) || Figure.xlBoxScl == DEFAULT )
		Figure.xlBoxScl = 1;

	x1 = xba - xMargin;
	if( havePlts )
		x0 = x1 - (int)(lineSeg ? 2.5*Figure.xlDel*chwd : chwd);
	else
		x0 = x1;
	xb0  = x0 - xMargin;
	xb1  = xba + (int)(textWidth*Figure.xlBoxScl) + xMargin;
	yb1 -= yMargin;
	
	if( Figure.eStat == 0 )
		Figure.eStat = (omode & ERASE) ? "yes" : "no";

	if( *Figure.eStat == 'y' || *Figure.eStat == 'Y') {
		PtrUnion	arg0, arg1;
		gray = oldGrayLevel;
		oldGrayLevel = PS_WHITE;
		arg0.d = &oldGrayLevel;
		special( SETGRAY, arg0, arg1 );
		PolyDef( xb0, yb0, CMOVE );
		PolyDef( xb1, yb0, CCONT );
		PolyDef( xb1, yb1, CCONT );
		PolyDef( xb0, yb1, CFILL );
		oldGrayLevel = gray;
		special( SETGRAY, arg0, arg1 );
	}

	if( Figure.xlBoxScl > 0 ) {
		PolyDef( xb0, yb0, CMOVE );
		PolyDef( xb1, yb0, CCONT );
		PolyDef( xb1, yb1, CCONT );
		PolyDef( xb0, yb1, CCONT );
		PolyDef( xb0, yb0, CSTROKE );
	}

	for( n=0;  n < Figure.nLegs;  n++ ) {
		l = &Figure.legs[n];

		FontGroupSelect( "f", Figure.legfg );
		plabel( l->text, xba, l->yPos, "LB", 0.0 );
		x = (x0+x1)/2;
		y = l->yPos + chht/3;

		if( l->pltNum == DEFAULT )
			continue;
		plt = &Plot.plts[l->pltNum];
		FontGroupSelect( "p", plt->fgName );

		switch( plt->pm ) {
			case NORMAL:
			case NCOLZERO:
			case LINES:
				move( x0, y );
				cont( x1, y );
				break;
			case FILLED:
			case FILLBETWEEN:
			case OUTLINE:
				PolyDef( x0, y-chht/3, CMOVE );
				PolyDef( x0, y+chht/3, CCONT );
				PolyDef( x1, y+chht/3, CCONT );
				PolyDef( x1, y-chht/3, CCONT );
				if( plt->pm == OUTLINE )
					PolyDef( x0, y-chht/3, CSTROKE );
				else
					PolyDef( x0, y-chht/2, CFILL );
				break;
			case OUTLINEFILL:
				PolyDef( x0, y-chht/3, CMOVE );
				PolyDef( x0, y+chht/3, CBBCONT );
				PolyDef( x1, y+chht/3, CBBCONT );
				PolyDef( x1, y-chht/3, CBBCONT );
				PolyDef( x0, y-chht/3, CBBFILL );
				break;
			case SYMBOL:
			case SCATTER:
			case SYMBOL_STD:
			case SCATTER_STD:
				if( plt->pc == ' ' )
					SmallBox( x, y );
					else	scatterplot( plt, x, y, y, y );
				break;
			default:
				err( NO, "No legend for plot type `%c'", plt->pm );
		}
	}
}