
/* Generated by Interface Builder */

#import <appkit/appkit.h> 	
#import "CubeView.h"
#import "StoreData.h"
#import "dotAt.h"
#define MAXLINE 10000
#define MAXNUM  10000
#define rad_to_deg  (180./M_PI)
#define defRadius 0.01
extern id NXApp;

@implementation CubeView

- initFrame:(const NXRect *) frameRect
{
  self = [super initFrame: frameRect];
  [self initialize];
	[self setCube:YES];
	[self setAxes:NO];
  return self;
}

- initialize
{
  [self setDrawSize:(NXCoord) 2:(NXCoord) 2];
  [self setDrawOrigin:(NXCoord) -1:(NXCoord) -1];
  PSonly = NO;
  vm = [AzimuthMat new];
				// establish the ops array and
				// bounding box for DPSDoUserPath()
  ops[0] = dps_moveto; ops[1] = 32 + 15; ops[2] = dps_lineto;
  boundingBox[0] = bounds.origin.x;
  boundingBox[1] = bounds.origin.y;
  boundingBox[2] = bounds.origin.x + bounds.size.width;
  boundingBox[3] = bounds.origin.y + bounds.size.height;
/*
  [self setAutosizing:NX_WIDTHSIZABLE || NX_HEIGHTSIZABLE];
*/
/*
  [self reScale:self];
*/
  max_path = 4096;
  path = (float *) calloc(2*max_path, sizeof(float));
  return self;
}

- showError:(char *)errorMessage
{
  NXRunAlertPanel("Error", errorMessage, "OK", NULL, NULL);
  return self;
}

- clear:sender
{
  [self reScale:self];
  [self Reset:self];
  return self;

}

- Reset:sender
{
  [vm setTheta:0.];
  [vm setPhi:0.];
  [vm setdist:2.0];
//  [self display];
  return self;
}

- printPSCode:sender
{
  PSonly = YES;
  return self;
}

- setTheta:(float)floatValue
{
  [vm setTheta:floatValue];
//  [self display];
  return self;
}

- setPhi:(float)floatValue
{
  [vm setPhi:-floatValue];
//  [self display];
  return self;
}

- setdist:(float)floatValue
{
  [vm setdist:floatValue];
//  [self display];
  return self;
}

- setCube:(int)intValue
{
	showCube = intValue;
//  [self display];
	return self;
}

- setAxes:(int)intValue
{
	showAxes = intValue;
//  [self display];
	return self;
}

- toggleCube:sender
{
  showCube = showCube ? NO : YES;
//  [self display];
  return self;
}

- toggleAxes:sender
{
  showAxes = showAxes ? NO : YES;
//  [self display];
  return self;
}

- reScale:sender
{
  float maxval[3], minval[3], limits[6], **displayed;
  short int i, j, k, ntypes, count;

  if ([dataList count] == 0) { /* no data - set to defaults */
    limits[0] = limits[1] = limits[2] = 0.;
    limits[3] = limits[4] = limits[5] = 1.;
    [self setlimits:limits];
    return self;
  }
  ntypes = [dataList count];
  myStorage = [dataList objectAt:0];
  displayed = [myStorage displayed];
  for(i = 0; i < 3; i++)
    minval[i] = maxval[i] = *displayed[i];
  for (j=0;j<ntypes;j++) {
 	 	myStorage = [dataList objectAt:j];
  		displayed = [myStorage displayed];
		count = [myStorage howMany];
    for(i = 0; i < 3; i++)
		for (k=0;k<count/3;k++)	{
	if (displayed[i][k] < minval[i]) minval[i] = displayed[i][k];
	if (displayed[i][k] > maxval[i]) maxval[i] = displayed[i][k];
      }
  }
  for(i = 0; i < 3; i++) {
    if (minval[i] >= maxval[i]) minval[i] = maxval[i] - 1;
    limits[i] = minval[i] - 0.035*(maxval[i] - minval[i]);
    limits[i + 3] = maxval[i] + 0.035*(maxval[i] - minval[i]);
  }
  [self setlimits:limits];
  return self;
}



static int x_seq[] = {0,3,3,0,0,0,3,3,0,0,3,3,3,3,0,0};
static int y_seq[] = {1,1,4,4,1,1,1,4,4,1,1,1,4,4,4,4};
static int z_seq[] = {2,2,2,2,2,5,5,5,5,5,5,2,2,5,5,2};

-setlimits:(float *)newlimits
{
  int i, n, tickdir;
  float tick, width;

  for (n = 0; n < 16; n++) {	/* create cube */
    cube[0][n] = newlimits[x_seq[n]];
    cube[1][n] = newlimits[y_seq[n]];
    cube[2][n] = newlimits[z_seq[n]];
  }
  for (n = 0; n < 54; n++) {	/* create axes */
    axes[0][n] = newlimits[0];
    axes[1][n] = newlimits[1];
    axes[2][n] = newlimits[2];
  }
  for (i = 0; i < 3; i++) {
    tickdir = (i == 0) ? 1 : 0;
    tick = 0.03 * (newlimits[tickdir + 3] - newlimits[tickdir]);
    width = newlimits[i + 3] - newlimits[i];
    n = 18 * i;
    axes[i][n+1] = axes[i][n+2] = axes[i][n+3] = axes[i][n+4] =
      newlimits[i] + 0.25 * width;
    axes[i][n+5] = axes[i][n+6] = axes[i][n+7] = axes[i][n+8] =
      newlimits[i] + 0.5 * width;
    axes[i][n+9] = axes[i][n+10] = axes[i][n+11] = axes[i][n+12] =
      newlimits[i] + 0.75 * width;
    axes[i][n+13] = axes[i][n+17] = newlimits[i] + 0.87 * width;
    axes[i][n+14] = axes[i][n+16] = newlimits[i] + 0.84 * width;
    axes[i][n+15] = newlimits[i] + width;
    axes[tickdir][n+2] = axes[tickdir][n+6] = axes[tickdir][n+10] =
      axes[tickdir][n+14] = newlimits[tickdir] + tick;
    axes[tickdir][n+3] = axes[tickdir][n+7] = axes[tickdir][n+11] =
      axes[tickdir][n+16] = newlimits[tickdir] - tick;
  }
  [vm setlimits:newlimits];
/*  [self Reset:self];
*/
  return self;
}

- getStruct:(id)listptr
{

	dataList = listptr;
	[self reScale:self];
	return self;
}

- drawSelf:(NXRect*)r :(int)c
{
  int ntypes, j, count, type;
  float *argv;
  float radius = defRadius;
  float	shade = NX_BLACK;
  float **displayed;
  
  NXEraseRect(&bounds);
/*
 *	We would set defaults, but overide if data is not null;
 *
*/
  PSsetgray(NX_BLACK);
  PSsetlinewidth(0.0);
//	NXSetColor(NX_Whatever you'd do for the default);?
  if (showCube) {
    ops[1] = 32 + 16 - 1;
    DPSDoUserPath ([vm as_DPSpath :16 :cube[0] :cube[1] :cube[2] :path],
		   32, dps_float, ops, 3, boundingBox, dps_ustroke);
  }
  if (showAxes) {
    ops[1] = 32 + 54 - 1;
    DPSDoUserPath ([vm as_DPSpath :54 :axes[0] :axes[1] :axes[2] :path],
		   108, dps_float, ops, 3, boundingBox, dps_ustroke);
  }
  ntypes = [dataList count];
  if(ntypes > 0)
  	for (j=0;j<ntypes;j++) {
 	 	myStorage = [dataList objectAt:j];
		type = [myStorage dataType];
		count = [myStorage howMany];
		if(count/3*2 > max_path)	{
			[self showError:"max_path exceeded in CubeView"];
			return self;
		}
    if (type == NEITHER) continue;
	if (type & LINES) {	/* draw the line */
      ops[1] = count/3 + 32 - 1;
	argv = [myStorage args];
  	PSsetlinewidth(argv[1]);
  	PSsetgray(argv[2]);
//	if(argv[3] != 0) NXSetColor(NX_RED);?
  	displayed = [myStorage displayed];
	DPSDoUserPath([vm as_DPSpath :count/3
		     :displayed[0] :displayed[1]
		     :displayed[2] :path],
		    2*count/3, dps_float,
		    ops, 3, boundingBox, dps_ustroke);
    }
    if (type & POINTS) {	/* draw points */
/*
 *	Here we pull out thisline->radius and thisline->shade
 *  If they are not the default(?) then set them and pass
 *  Otherwise use default.
*/
	argv = [myStorage args];
//	if(argv[3] != 0) NXSetColor(NX_RED);?
  	displayed = [myStorage displayed];
	dotAtPSonly([vm as_DPSpath :count/3
		     :displayed[0] :displayed[1]
		     :displayed[2] :path],
		    2*count/3, argv[1], argv[2]);
    }
  }

  PSonly = NO;
  return self;
}

- debug:(id)storage
/*	Debuggin output
*/
{

		int i, k, nitems, type;
		float *xx, *gpt, **displayed;
		

	nitems = [storage howMany];
	printf("This storage item has %d points\n",nitems);
	xx = [storage args];
	type = [storage dataType];
	gpt = [storage array];
	printf("Type = %d, argv is %10.6f, %10.6f, %10.6f\n",
		 	type,xx[1],xx[2],xx[3]);
	displayed = [myStorage displayed];
	printf(" Data via displayed array\n");
	for(i=0;i<nitems/3;i++)	{
		printf("%d) ",i);
		for (k=0;k<3;k++)
			printf(" %10.6f",displayed[k][i]);
		printf("\n");
		}

	return self;
}

@end
