//This code is the work of Booker C. Bense (benseb@next.sdsc.edu)
// You are free to change/distribute this code provided this notice
// remains intact in all versions. 
#import "LorenzRotateViewPart.h"
#import "Thinker.h"
#import <appkit/NXImage.h>
#import <appkit/Panel.h>                // for NXRunAlertPanel()
#import <dpsclient/wraps.h>
#import <libc.h>
#import <math.h>


@implementation LorenzRotateView

- oneStep
{
    register int i;
    int rect_count; 
    float xx,yy,zz,ctheta,stheta; 
   
    // Cycle indices
    p=n; 
  
    points[0] = n; 

    theta += TWO_PI / NTHETA ; 
    if ( theta > TWO_PI ) theta -= TWO_PI; 

    ctheta = cos(theta);
    stheta = sin(theta); 
   
    for( i = 1 ; i < CHASERS ; i++ )
    {
	points[i] = (CHASELEN +points[i-1])%(NUMPOINTS); 
    }
 

    n=(n+1)%(NUMPOINTS);      
    
    // take an euler step   

    
    xdot = S * (Y[p] - X[p]);
    ydot = (R * X[p]) - Y[p] - (X[p] * Z[p]);
    zdot = (X[p] * Y[p]) - (B * Z[p]);
    X[n] = X[p] + xdot * delta_T;
    Y[n] = Y[p] + ydot * delta_T;
    Z[n] = Z[p] + zdot * delta_T;

    // Draw the black stuff 

    PSsetrgbcolor(0.0,0.0,0.0);
// This one's faster 
    NXRectFill(&curBounds); 
//     NXRectFillList( pixels,NUMPOINTS ); 
    //Convert to screen coordinates Update

	for ( i = 0 ;  i < NUMPOINTS ; i++) 
	{  
	    xx = (( X[i] - Xmin)/ Xrange) - 0.5; 
	    yy = (( Y[i] - Ymin )/ Yrange) -0.5; 
	    zz = (( Z[i] - Zmin )/ Zrange) -0.5;
       
	    pixels[i].origin.x = (xx)* urx + midx; 
	    pixels[i].origin.y = (ctheta*yy+stheta*zz )*ury + midy  ;
 	    pixels[i].size.width =
	    pixels[i].size.height = ceil(3*(-stheta*yy+ctheta*zz) + 1.5) ;

	} 

    if ( [self shouldDrawColor ] )
    {
	red_shift = (CHASERS*4)/3;
	blue_shift = (CHASERS*2)/3; 
	clut = cl_clut; 
    }
    else
    {
	red_shift = 0; 
	blue_shift = 0;
	clut = twobit_clut;  
    }

 
    for ( i = 0; i < CHASERS ; i++)
    {     
	pixelpoint = &pixels[points[i]]; 
	// worry about cycling indices 
	if( ( NUMPOINTS - points[i] ) < CHASELEN )
	    rect_count = (NUMPOINTS -points[i]);
	else 
	    rect_count = CHASELEN; 
       
	PSsetrgbcolor(
		     clut[(i+red_shift)%CHASERS],clut[i],
		     clut[(i+blue_shift)%CHASERS]);  
	NXRectFillList(pixelpoint,rect_count); 
	if ( rect_count < CHASELEN )
	    NXRectFillList(pixels,(CHASELEN-rect_count));
    }
 
  // Draw the White stuff
   
    // worry about cycling indices 
	if( ( n  - CHASELEN) < 0)
           {
	    rect_count = -(n-CHASELEN);
	    pixelpoint = &pixels[NUMPOINTS-rect_count]; 
	    }
	else 
           {
	    rect_count = CHASELEN; 
	    pixelpoint = &pixels[n-CHASELEN+1]; 
	    }
	PSsetrgbcolor(1.0, 1.0, 1.0);
	NXRectFillList(pixelpoint,rect_count); 
	if ( rect_count < CHASELEN )
	    NXRectFillList(pixels,n+1);
   
   

  return self;
}

- initFrame:(NXRect *)frameRect
{
	[super initFrame:frameRect];
	[self newSize];
	return self;
}

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

- newSize
{
    
    register int j,i; 
    curBounds = bounds; 
    urx=bounds.size.width;
    ury=bounds.size.height;

  midx=urx/2;
  midy=ury/2;
 // play with size clues later 
  for ( j = 0 ; j < NUMPOINTS; j++)
    {
	pixels[j].size.width = 1.0;
	pixels[j].size.height = 1.0;
    }

  // angle of rotation 
  theta = 0.0; 
  X[0] = 0.1;
  Y[0] = 0.1;
  Z[0] = 0.1; 
  xc[0] = midx;
  yc[0] = midy; 
  // Starting points 
  for(i=1; i< NUMPOINTS; i++)
  {
      xdot = S * (Y[i-1] - X[i-1]);
      ydot = (R * X[i-1]) - Y[i-1] - (X[i-1] * Z[i-1]);
      zdot = (X[i-1] * Y[i-1]) - (B * Z[i-1]);
      X[i] = X[i-1] + xdot * delta_T;
      Y[i] = Y[i-1] + ydot * delta_T;
      Z[i] = Z[i-1] + zdot * delta_T;
      pixels[i].origin.x = (( X[i] - Xmin)/ Xrange)*urx ;
      pixels[i].origin.y = (( Y[i] - Ymin )/ Yrange)*ury ; 
  }
 
   n = NUMPOINTS - 1;   
  //this will probably look really ugly in color ????
  for(i=0; i < CHASERS ; i++ )
     { cos_arg = ((float)i)/((float)CHASERS)*PI; 
       cl_clut[i] = (cos(cos_arg)+1.0)/2.0;
       twobit_clut[i] = (float)((i%3)+1)/3.0; 
      } 

  return self;
}

@end
