
/* Generated by Interface Builder */

#import <math.h>
#import <dpsclient/psops.h>
#import <dpsclient/wraps.h>
#import <objc/Storage.h>
#import <appkit/NXImage.h>
#import <appkit/TextField.h>
#import "DataView.h"
@implementation DataView

- initFrame:(const NXRect *)frameRect
{
NXSize cacheSize;

    [super initFrame:frameRect];
    data = [[Storage alloc] initCount:0
			    elementSize:sizeof(struct plotData)
                            description:PLOTDATA_DESCRIPTION];
    curve = [[Storage alloc] initCount:0
                             elementSize:sizeof(float)
                             description:"f"];
    xscale = 1;
    yscale = 1;
    scaleOnTop = YES;
    scaleOnBottom = YES;
    scaleOnLeft = YES;
    scaleOnRight = YES;

// Initialize an NXImage to draw in so we can flush it in drawself
    cacheSize.width = frameRect->size.width;
    cacheSize.height = frameRect->size.height;
    cache = [[NXImage alloc] initSize:&cacheSize];
    cacheUpToDate = NO;

    [self notifyAncestorWhenFrameChanged:YES];

    zeroLines = YES;  

    return self;
}

- drawSelf:(NXRect *)rects :(int)rectCount
{
    if ( !cacheUpToDate && [self window] )
        [self drawInCache];
    [cache composite:NX_SOVER
           toPoint:&bounds.origin];

    return self;
}

- free
{
    [data free];
    return [super free];
}

- setFrame:(NXRect *)frameRect
{
    [super setFrame:frameRect];
    cacheUpToDate = NO;
    return self;
}

- moveTo:(NXCoord)x :(NXCoord)y
{
    [super moveTo:x :y];
    [topScale moveTo:x :0];
    [bottomScale moveTo:x :0];
    [leftScale moveTo:0 :y];
    [rightScale moveTo:0 :y];
    return self;
}

- sizeTo:(NXCoord)width :(NXCoord)height
{
    [super sizeTo:width :height];
    cacheUpToDate = NO;
    return self;
}

- addData:(struct plotData *)datum
{
// If there has been no previous data, initialize the min and max values
    if ( ![data count] )
        {
        xmax = datum->x;
        xmin = datum->x;
        ymax = datum->y;
        ymin = datum->y;
        }
// If the min and max values have been initialized then adjust them accordingly.
    else
        {
        if ( datum->x > xmax )
            xmax = datum->x;
        else if (datum->x < xmin )
            xmin = datum->x;
        if ( datum->y > ymax )
            ymax = datum->y;
        else if (datum->y < ymin )
            ymin = datum->y;
        }
    [data addElement:datum];

    return self;
}

- drawInCache
{
struct plotData *datum;
int count;
int i;
float x;
float interval;

// We have to resize the cache first.
    [cache setSize:&(bounds.size)];

    [cache lockFocus];
// Wipe out the background
    PSsetgray(NX_WHITE);
    PSsetalpha(0.0);
    NXRectFill(&bounds);

// Calculate the x and y scales so that the plot fills up the view.
    if ( xmax - xmin != 0 )
        xscale = bounds.size.width/(xmax - xmin);
    if ( ymax - ymin != 0 )
        yscale = bounds.size.height/(ymax - ymin);
  
 
// Try to plot the data only if there is any
    
    count = [data count];
    if ( !count && ![curve count] )
        {
        [cache unlockFocus];
        return self;
        }

    PSsetgray(NX_BLACK);
    PSsetalpha(1.0);
    PSsetlinewidth(1/50);
    PSscale(xscale,yscale);
    PStranslate(-xmin,-ymin);
    if ( plotMode == DATA_ONLY || plotMode == DATA_AND_CURVE )
        {
        datum = [data elementAt:0];
        PSmoveto(datum->x,datum->y);
        for ( i = 1 ; i < count ; i++ )
            {
            datum = [data elementAt:i];
            PSlineto(datum->x,datum->y);
            }
        }
    if ( plotMode == CURVE_ONLY || plotMode == DATA_AND_CURVE )
        {
        PSmoveto(xmin,evaluatePolynomial(curve->dataPtr,[curve count],xmin));
        interval = ( xmax - xmin ) / ( frame.size.width );
        if ( interval <= 0 )
            {
            [cache unlockFocus];
            return self;
            }
        for ( x  = xmin ; x <= xmax ; x+= interval )
            PSlineto(x,evaluatePolynomial(curve->dataPtr,[curve count],x)); 
        }
    if ( zeroLines )
        {
        PSmoveto(xmin,0);
        PSlineto(xmax,0);
        PSmoveto(0,ymin);
        PSlineto(0,ymax);
        }
    PSstroke();

    [cache unlockFocus];

    return self;
}

- setPlotMode:(int)mode
{
    plotMode = mode;
    return self;
}

- setZeroLines:(BOOL)mode
{
    zeroLines = mode;
    return self;
}

- (float)xscale
{
    return xscale;
}

- (float)yscale
{
    return yscale;
}

- (float)xmin
{
    return xmin;
}

- setxmin:(float)aNumber
{
    xmin = aNumber;
    return self;
}

- (float)xmax
{
    return xmax;
}

- setxmax:(float)aNumber
{
    xmax = aNumber;
    return self;
}

- (float)ymin
{
    return ymin;
}

- setymin:(float)aNumber
{
    ymin = aNumber;
    return self;
}

- (float)ymax
{
    return ymax;
}

- setymax:(float)aNumber
{
    ymax = aNumber;
    return self;
}

- data
{
    return data;
}

- setData:anObject
{
int count;
int i;
struct plotData *datum;

    if ( data != anObject )
        [data free];
    data = anObject;
        count = [data count];
    datum = [data elementAt:0];
    xmax = datum->x;
    xmin = datum->x;
    ymax = datum->y;
    ymin = datum->y;
  
    for ( i = 1 ; i < count ; i++ )
        {
        datum = [data elementAt:i];
        if ( datum->x > xmax )
            xmax = datum->x;
        else if (datum->x < xmin )
            xmin = datum->x;
        if ( datum->y > ymax )
            ymax = datum->y;
        else if (datum->y < ymin )
            ymin = datum->y;
        }
    return self;
}

- setCurve:anObject
{
    curve = anObject;
    return self;
}

- setCurveFromArray:(float *)coefficients count:(int)anInt
{
int i;

    [curve empty];
    for ( i = 0 ; i < anInt ; i++ )
        [curve addElement:&coefficients[i]];
    cacheUpToDate = NO;
    return self;
}

- rescaleForCurveWithRange:(float)newxmin :(float)newxmax checkInterval:(float)interval;
{
float i;
float y;

    if ( interval <= 0 || newxmin >= newxmax )
        return self;

    xmin = newxmin;
    xmax = newxmax;
    ymin = evaluatePolynomial(curve->dataPtr,[curve count],xmin);
    ymax = ymin;
    for ( i = newxmin ; i <= newxmax ; i+= interval )
        {
        y = evaluatePolynomial(curve->dataPtr,[curve count],i);
        if ( y < ymin )
            ymin = y;
        if ( y > ymax )
            ymax = y;
        }
    cacheUpToDate = NO;
    return self;
}

- drawLimits
{
    [xmintext setFloatValue:xmin];
    [xmaxtext setFloatValue:xmax];
    [ymintext setFloatValue:ymin];
    [ymaxtext setFloatValue:ymax];
    return self;
}

- (float)integral  // for now, this does a simple trapezoidal integration.  it will change later.
{
float integral;
int i;
int count;
struct plotData *points;

    count = [data count];
    points = data->dataPtr;
    integral = 0;

    for ( i = 1 ; i < count ; i++ )
        integral += ( points[i-1].y + points[i].y ) / 2 * ( points[i].x - points[i-1].x );

    return integral;
}

- (float)integrateWithLimits:(float)start :(float)end
{
float integral;

    return integral;
}

@end


float evaluatePolynomial(float *coefficients,int number,float x)
{
int i;
float y;    

    y = coefficients[0];
    for ( i = 1 ; i < number ; i++ )
        y += coefficients[i] * pow(x,i);
    return y;
}










