
/* Generated by Interface Builder */

#import "NeuronView.h"
#import "NeuronCntrl.h"		// needed for extern variables
#import <dpsclient/psops.h>	// for postscript functions
#import <math.h>		// for sqrt function

// global variables found in NeuronCntrl.m
extern int NUM_NODES;
extern int NUM_INPUTS;
extern int NUM_OUTPUTS;
extern NXPoint *NeuronLoc;
extern float *NeuronValues;
extern float **Network;

#define defaultsize 10

@implementation NeuronView

// initialize the new NeuronView object...
- initFrame:(const NXRect *)frameRect
{  
    [super initFrame:frameRect];		// standard init for View
    [self setOpaque:YES];			// set background mode
    [self notifyAncestorWhenFrameChanged:YES];	// for resizing scrollview
    newRadius = defaultsize;			// init size for newRadius
    return self;
}

/* at the location determined in initNetworkDisplay, fill in a circle with color for the activity rate (output value) within neuron
*/
- displayActivity
{
    int i,j;
    float thickness;
            
    [self lockFocus];			// get access to screen for drawing    
    // erase previous neurons and lines
    PSsetgray(2./3.);	// set gray color of rect to follow
    // draw a filled rectangle over view (erase anything before)
    PSrectfill(0, 0, bounds.size.width, bounds.size.height);

    // draw connecting lines (thickness & color varies)...
    for (j=0; j < (NUM_NODES - NUM_OUTPUTS); j++)
      for (i=j+1; i < NUM_NODES; i++)
      {
          if ((thickness = Network[i][j]) != 0.0)
	  {
	    if (thickness > 0.0)
      		NXSetColor(NXConvertRGBToColor(1.0,0.0,0.0)); // red +
	    else
      		NXSetColor(NXConvertRGBToColor(0.0,0.0,1.0)); // blue - 
	    PSsetlinewidth(sqrt(thickness*thickness)*5); // abs of thickness
	    PSmoveto(NeuronLoc[j].x, NeuronLoc[j].y);
	    PSlineto(NeuronLoc[i].x, NeuronLoc[i].y);
	    PSstroke();
	  }     
      }

    // draw circles (color shows activity level)
    for (i = 0; i < NUM_NODES; i++)
    {
      NXSetColor(NXConvertRGBToColor(NeuronValues[i],0.0,(1-NeuronValues[i])));
      PSarc(NeuronLoc[i].x, NeuronLoc[i].y,newRadius,0,360);
      PSfill();
      PSstroke();
	  // draw histogram rectangles to better identify activity pattern...
      PSsetgray(NX_BLACK);	// set bars to black
      PSrectfill(NeuronLoc[i].x, NeuronLoc[i].y-6,NeuronValues[i]*newRadius*2 ,12);
      PSfill();
      PSstroke();

    }
    
    [self unlockFocus];			// release access to screen
    [window flushWindow];		// flush results to screen
    return self;
}

/* find the layers within the network matrix, determine a location within the view for each neuron (circle), draw lines to represent the network with color and thickness varying according to + & - values and the size of the value.
*/
- initNetworkDisplay
{
    int NeuronLayer[NUM_NODES];		// array to store neurons in layers
    NXPoint theLoc;
    NXCoord viewX = bounds.size.width;	// get X & Y size of view
    NXCoord viewY = bounds.size.height;
    int i,oldi,j,layer,count;
    float Xspacing, Yspacing, Xoffset, Yoffset;

    i=oldi=j=layer=count=0;
    // find layers within network matrix.
    while (i < NUM_NODES)
    {
      for (; i < NUM_NODES; i++)
      {
        for (j=oldi; j < i; j++)
	  if (Network[i][j] != 0)
	    break; //exit this for loop...
	if (Network[i][j] != 0)
	  break; //exit this for loop...
      }
      NeuronLayer[layer] = i - oldi; // # of neurons in layer.
      layer++;
      oldi = i;
    }

    // determine a location for each neuron within window (view)
    Xspacing = viewX/layer;	Xoffset = Xspacing/2;
    oldi =0;
    for (i=0; i < layer; i++)
    {
      Yspacing = viewY/NeuronLayer[i]; Yoffset = Yspacing/2;
      count=0;
      theLoc.x = i*Xspacing + Xoffset;
      for (j =oldi; j < (oldi + NeuronLayer[i]); j++)
      {
        theLoc.y = count*Yspacing + Yoffset;
	NeuronLoc[j] = theLoc;
	count++;
      }
      oldi = j;
    }
    return self;
}

// responds when Neuron size slider is adjusted more than 1 pixel in size
- adjustNeuronSize:sender
{
    newRadius = [sender floatValue];
    [self displayActivity];
    return self;
}

// standard method to draw the view (responds everytime view needs display)
- drawSelf:(const NXRect*)r :(int)c
{
    PSsetgray(2./3.);	// set gray color of rect to follow
    // draw a filled rectangle over view (erase anything before)
    PSrectfill(0, 0, bounds.size.width, bounds.size.height);
    [self initNetworkDisplay];		// initNetworkdisplay and draw
    [self displayActivity];		// display the neuron activity
    return self;
}

@end
