
/*	Program By Fred Richards, Copyright 1990.	*/
/*							*/
/*	This software is provided free of charge	*/
/*	and without warranty.  The source code may	*/
/*	be distributed freely provided this copyright	*/
/*	notice remains in tact.				*/


#import "PlotView.h"
#import "Plot.h"

#define SQRT3	1.73205

@implementation PlotView


- setPlotParam:anObject
{
    plotParam = anObject;
    return self;
}

- initPlot:sender
{
    PSsetlinewidth(0.0);
    [self setPointSize];
    [self setDrawColor:NX_BLACK];
    [self clear:sender];
    PSrectclip([plotParam xmin:self]-(pointSize.x/100.0),
	       [plotParam ymin:self]-(pointSize.y/100.0),
	       [plotParam xmax:self]-[plotParam xmin:self]+(pointSize.x/50.0),
	       [plotParam ymax:self]-[plotParam ymin:self]+(pointSize.y/50.0));
    return self;
}

- clear:sender
{
    NXEraseRect(&bounds);
    return self;
}

// Draw lines between all the data points given

- drawLines:sender
{
    int		i,
		count = [sender dSize];
    NXPoint	*data = [sender data];

    /* Buffer this so that a single path can */
    /* contain up to 512 points. */

    PSnewpath();
    PSmoveto(data[0].x, data[0].y);
    for (i = 1; i < count; i++)  {
      if ((i % 512) == 0)  {
	PSstroke();
	PSnewpath();
	PSmoveto(data[i-1].x, data[i-1].y);
      }
      PSlineto(data[i].x, data[i].y);
    }
    PSstroke();
    return self;
}


- drawPoints:sender
{
    int		i,
		count = [sender dSize];
    NXPoint	*data = [sender data];

    for (i = 0; i < count; i++)
      [self dotAt:data[i]];
    return self;
}

- drawCrosses:sender
{
    int		i,
		count = [sender dSize];
    NXPoint	*data = [sender data];

    for (i = 0; i < count; i++)
      [self crossAt:data[i]];
    return self;
}

- drawXs:sender
{
    int		i,
		count = [sender dSize];
    NXPoint	*data = [sender data];

    for (i = 0; i < count; i++)
      [self xAt:data[i]];
    return self;
}

- drawBoxes:sender
{
    int		i,
		count = [sender dSize];
    NXPoint	*data = [sender data];

    for (i = 0; i < count; i++)
      [self boxAt:data[i]];
    return self;
}

- drawTriangles:sender
{
    int		i,
		count = [sender dSize];
    NXPoint	*data = [sender data];

    for (i = 0; i < count; i++)
      [self triangleAt:data[i]];
    return self;
}


- setDrawColor:(float )color;
{
    PSsetgray(color);
    return self;
}

- setPointSize
{
    pointSize.x = bounds.size.width / 50.0;
    pointSize.y = bounds.size.height / 50.0;

    pointOffset.x = pointSize.x/2.0;
    pointOffset.y = pointSize.y/2.0;

    return self;
}

- dotAt:(NXPoint )place
{
    PSnewpath();
    PSmoveto(place.x, place.y);
    PSlineto(place.x, place.y);
    PSstroke();
    return self;
}

- crossAt:(NXPoint )place
{
    PSnewpath();
    PSmoveto(place.x-pointOffset.x, place.y);
    PSrlineto(pointSize.x, 0.0);
    PSmoveto(place.x, place.y-pointOffset.y);
    PSrlineto(0.0, pointSize.y);
    PSstroke();
    return self;
}

- xAt:(NXPoint )place
{
    PSnewpath();
    PSmoveto(place.x-pointOffset.x, place.y-pointOffset.y);
    PSrlineto(pointSize.x, pointSize.y);
    PSrmoveto(-pointSize.x, 0.0);
    PSrlineto(pointSize.x, -pointSize.y);
    PSstroke();
    return self;
}

- boxAt:(NXPoint )place
{
    PSnewpath();
    PSmoveto(place.x-pointOffset.x, place.y-pointOffset.y);
    PSrlineto(pointSize.x, 0.0);
    PSrlineto(0.0, pointSize.y);
    PSrlineto(-pointSize.x, 0.0);
    PSclosepath();
    PSstroke();
    return self;
}

- triangleAt:(NXPoint )place
{
    PSnewpath();
    PSmoveto(place.x-pointOffset.x, place.y-(pointOffset.y/SQRT3));
    PSrlineto(pointSize.x, 0.0);
    PSrlineto(-pointOffset.x, pointSize.y);
    PSclosepath();
    PSstroke();
    return self;
}

- border
{
    PSnewpath();
    PSsetgray(NX_BLACK);
    PSsetlinewidth(0.0);

    PSmoveto([plotParam xmin:self], [plotParam ymin:self]);
    PSlineto([plotParam xmax:self], [plotParam ymin:self]);
    PSlineto([plotParam xmax:self], [plotParam ymax:self]);
    PSlineto([plotParam xmin:self], [plotParam ymax:self]);
    PSclosepath();

    PSstroke();
    
    return self;
}

- axes
{
    PSnewpath();
    PSsetgray(NX_BLACK);
    PSsetlinewidth(0.0);

    PSmoveto([plotParam xmin:self], 0.0);
    PSlineto([plotParam xmax:self], 0.0);
    PSmoveto(0.0, [plotParam ymin:self]);
    PSlineto(0.0, [plotParam ymax:self]);

    PSstroke();

    return self;
}

- drawSelf:(const NXRect *)rects :(int )rectCount
{
    if (![plotParam data])
      return self;

    [self initPlot:self];

    if ([plotParam border:self])
      [self border];
    if ([plotParam axes:self])
      [self axes];

    [[self window] flushWindow];

    if ([plotParam lines:self])
      [self drawLines:plotParam];

    switch ([plotParam style:self])  {
    case 0:
      if (![plotParam lines:self])
	[self drawPoints:plotParam];
      break;
    case 1:
      [self drawCrosses:plotParam];
      break;
    case 2:
      [self drawXs:plotParam];
      break;
    case 3:
      [self drawBoxes:plotParam];
      break;
    case 4:
      [self drawTriangles:plotParam];
      break;      
    }

    return self;
}


- savePSCode:(char *)aFile
{
    NXStream	*psStream;

    psStream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
    if (!psStream)  {
      return self;
    }
    [self getBounds:&bounds];
    [self copyPSCodeInside:&bounds to:psStream];
	   
    NXFlush(psStream);
    NXSaveToFile(psStream, aFile);
    NXCloseMemory(psStream, NX_FREEBUFFER);

    return self;
}


@end
