This is CubeView.m in view mode; [Download] [Up]
/* Generated by Interface Builder */
#import "CubeView.h"
#import "a3DViewerView.h"
#import "dotAt.h"
#import <stdlib.h>
#import <strings.h>
#import <stdio.h>
#import <dpsclient/wraps.h>
#import <dpsclient/dpsNeXT.h>
#import <appkit/graphics.h>
#import <appkit/Control.h>
#import <appkit/Form.h>
#import <appkit/OpenPanel.h>
#import <appkit/Pasteboard.h>
#import <appkit/Application.h>
#import <appkit/Font.h>
#import <appkit/Slider.h>
#import <soundkit/Sound.h>
#import <math.h>
#define MAXLINE 1000
#define MAXNUM 10000
#define rad_to_deg (180./M_PI)
@implementation CubeView
+ newFrame:(const NXRect *) frameRect
{
self = [super newFrame: frameRect];
[self initStatus];
return self;
}
+ new;
{
self = [super new];
[self initStatus];
return self;
}
- (id)class
{
return [myController class];
}
- (const char *)name
{
return [myController name];
}
- (int)tag
{
return tag;
}
- (id)controllerObj
{
return myController;
}
- setController:(id)ctrlr
{
myController = ctrlr;
[soundButton getFrame:&sndBtnRect];
[soundButton removeFromSuperview];
return self;
}
- setmachHeader:(struct mach_header *)mH
{
machHeader = mH;
return self;
}
static char angle_buffer[20];
- (void)showError:(char *)errorMessage
{
NXRunAlertPanel("Error", errorMessage, "OK", NULL, NULL);
}
- (void)initStatus
{
toshow = (datapoints **) calloc(2000, sizeof(datapoints *));
max_path = 4000;
path = (float *) calloc(2000, sizeof(float));
dot_offset[0] = 2.5 * 2 / bounds.size.width;
dot_offset[1] = 2.5 * 2 / bounds.size.height;
[self setDrawSize:(NXCoord) 2:(NXCoord) 2];
[self setDrawOrigin:(NXCoord) -1:(NXCoord) -1];
//showCube = YES;
showCube = NO;
showAxes = YES;
//PSonly = NO;
PSonly = YES;
vm = [AzimuthMat new];
openReq = [OpenPanel 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;
// create the template plotting dot
dot = [[NXImage alloc] initFromSection:"cubedot.tiff"];
// dot = [Bitmap newFromMachO:"cubedot.tiff"];
// dotgstate = [[dot window] gState];
// force a rescaling
[self reScale:self];
tag = 63757374; // hex ascii for "cust"
}
- (void)printPSCode:sender
{
PSonly = YES;
[self display];
[super printPSCode:self];
PSonly = NO;
[self display];
}
- copy:sender
{
id pb = [Pasteboard new];
NXStream *st;
char *data;
int length;
int maxLength;
PSonly = YES;
[self display];
[pb declareTypes:&NXPostScriptPboardType num:1 owner:self];
st = NXOpenMemory( NULL, 0, NX_WRITEONLY );
[self copyPSCodeInside:NULL to:st];
NXGetMemoryBuffer( st, &data, &length, &maxLength );
[pb writeType:NXPostScriptPboardType data:data length:length];
NXCloseMemory( st, NX_FREEBUFFER );
PSonly = NO;
[self display];
return self;
}
-(BOOL)acceptsFirstResponder
{ /* make this view accept first */
return YES; /* responder so it will understand copy */
}
-resignFirstResponder
{
return self;
}
- setAngleDisplay:anObject
{
AngleDisplay = anObject;
return self;
}
- setDistanceSlider:anObject
{
DistanceSlider = anObject;
return self;
}
- setThetaSlider:anObject
{
ThetaSlider = anObject;
return self;
}
- setPhiSlider:anObject
{
PhiSlider = anObject;
return self;
}
- setSoundButton:anObject
{
soundButton = anObject;
return self;
}
- Reset:sender
{
[vm setTheta:0.];
[ThetaSlider setFloatValue:0.];
[vm setPhi:0.];
[PhiSlider setFloatValue:0.];
[vm setdist:2.0];
[DistanceSlider setFloatValue:-1/2.];
[self ShowAngles:sender];
[self display];
return self;
}
- (void)ShowAngles:sender
{
sprintf(angle_buffer, "%6.2f", rad_to_deg*[vm getTheta:self]);
[AngleDisplay setStringValue:angle_buffer at:0];
sprintf(angle_buffer, "%6.2f", -rad_to_deg*[vm getPhi:self]);
[AngleDisplay setStringValue:angle_buffer at:1];
sprintf(angle_buffer, "%6.2f", [vm getdist:self]);
[AngleDisplay setStringValue:angle_buffer at:2];
}
- (float)readPhi
{
return -rad_to_deg*[vm getPhi:self];
}
- (float)readTheta
{
return rad_to_deg*[vm getTheta:self];
}
- (float)readInvdist
{
return [vm getdist:self];
}
- (BOOL)writePhi:(float)phi
{
float angle;
double min,max;
BOOL correct=NO;
angle = phi/rad_to_deg;
if( angle > (max = [PhiSlider maxValue]) ) {angle = max;correct=YES;}
if( angle < (min = [PhiSlider minValue]) ) {angle = min;correct=YES;}
[vm setPhi:-angle];
[PhiSlider setFloatValue:angle];
[self display];
return correct;
}
- (BOOL)writeTheta:(float)tht
{
float angle;
double min,max;
BOOL correct=NO;
angle = tht/rad_to_deg;
if( angle > (max = [ThetaSlider maxValue]) ) {angle = max;correct=YES;}
if( angle < (min = [ThetaSlider minValue]) ) {angle = min;correct=YES;}
[vm setTheta:angle];
[ThetaSlider setFloatValue:angle];
[self display];
return correct;
}
- (BOOL)writeInvdist:(float)invd
{
float id;
double min,max;
BOOL correct=NO;
id = -1./invd;
if( id > (max = [DistanceSlider maxValue]) ) {id = max;correct=YES;}
if( id < (min = [DistanceSlider minValue]) ) {id = min;correct=YES;}
id = -1./id;
[vm setdist:id];
[DistanceSlider setFloatValue:-1./id];
[self display];
return correct;
}
- (void)setViewParameters
{
[self writePhi:currentPhi];
[self writeTheta:currentTheta];
[self writeInvdist:currentDist];
}
- setTheta:sender
{
[vm setTheta:[sender floatValue]];
[self display];
[myController perform:@selector(resetFirstResponder:) with:self
afterDelay:1 cancelPrevious:YES];
return self;
}
- setPhi:sender
{
[vm setPhi:-[sender floatValue]];
[self display];
[myController perform:@selector(resetFirstResponder:) with:self
afterDelay:1 cancelPrevious:YES];
return self;
}
- setdist:sender
{
float dist;
dist = [sender floatValue];
if (dist < 1.8) {
[self showError: "Distance must be greater than 1.8"];
return self;
}
[vm setdist:dist];
[DistanceSlider setFloatValue:-1./dist];
[self display];
return self;
}
- setinvdist:sender
{
[vm setinvdist:-[sender floatValue]];
[self display];
[myController perform:@selector(resetFirstResponder:) with:self
afterDelay:1 cancelPrevious:YES];
return self;
}
- setTheta_degrees:sender
{
float angle = [sender floatValue]/rad_to_deg;
[vm setTheta:angle];
[ThetaSlider setFloatValue:angle];
[self display];
return self;
}
- setPhi_degrees:sender
{
float angle = [sender floatValue]/rad_to_deg;
[vm setPhi:-angle];
[PhiSlider setFloatValue:angle];
[self display];
return self;
}
- toggleCube:sender
{
showCube = showCube ? NO : YES;
[self display];
[myController perform:@selector(resetFirstResponder:) with:self
afterDelay:1 cancelPrevious:YES];
return self;
}
- toggleAxes:sender
{
showAxes = showAxes ? NO : YES;
[self display];
[myController perform:@selector(resetFirstResponder:) with:self
afterDelay:1 cancelPrevious:YES];
return self;
}
- reScale:sender
{
float maxval[3], minval[3], limits[6], *fpt;
datapoints **all_lines = toshow, *thisline;
short int i, count;
if (*all_lines == (datapoints *) NULL) { /* no data - set to defaults */
limits[0] = limits[1] = limits[2] = 0.;
limits[3] = limits[4] = limits[5] = 1.;
[self setlimits:limits];
return self;
}
for(i = 0; i < 3; i++)
minval[i] = maxval[i] = *((*all_lines)->displayed[i]);
while (thisline = *all_lines++) {
for(i = 0; i < 3; i++) {
count = thisline->npts;
fpt = thisline->displayed[i];
while (count--) {
if (*fpt < minval[i]) minval[i] = *fpt;
if (*fpt > maxval[i]) maxval[i] = *fpt;
fpt++;
}
}
}
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;
}
- (void)setViewSound:(id)sndObj
{
if( !viewSound ) viewSound = [Sound new];
[viewSound copySound:sndObj];
[self showSoundButton];
[myController perform:@selector(resetFirstResponder:) with:self
afterDelay:1 cancelPrevious:YES];
}
- (void)deleteViewSound
{
if( viewSound ) {
[viewSound free];
viewSound = 0x0;
[[self window] disableFlushWindow];
[soundButton removeFromSuperview];
[[self window] display];
[[self window] reenableFlushWindow];
[[self window] flushWindow];
[myController perform:@selector(resetFirstResponder:) with:self
afterDelay:1 cancelPrevious:YES];
}
}
- (void)showSoundButton
{
[[self window] disableFlushWindow];
[[self superview] addSubview:soundButton];
[soundButton moveTo:sndBtnRect.origin.x :sndBtnRect.origin.y];
[[self window] display];
[[self window] reenableFlushWindow];
[[self window] flushWindow];
}
- playSound:sender
{
[viewSound play];
return self;
}
- (char *)currentDataFile
{
return dataFileName;
}
- openData:sender
{
const char *fileName;
const char *const ext[2] = {"3d", NULL};
if([openReq runModalForTypes:ext] && (fileName = [openReq filename])) {
[self readData:fileName];
if( dataFileName ) free(dataFileName);
dataFileName = malloc(BUFSIZ);
strcpy(dataFileName,fileName);
}
else
[self showError:"No file chosen or could not open file"];
return self;
}
static void float_copy (register int n, register float * to, register int
to_inc, register float * from, register int from_inc)
{
if (n > 0)
while (n--) {
*to = *from;
to += to_inc;
from += from_inc;
}
}
- (BOOL) readData:(const char *)filename
{
FILE *input;
float *scratch, *fpt;
char thisline[MAXLINE], *cpt, c;
long int count, ncols, nchars, nlines, expected_cols;
datapoints **all_data = toshow, *thesedata;
scratch = (float *) calloc(MAXNUM, sizeof(float));
if((input = fopen(filename, "r")) == NULL) {
sprintf(thisline, "Unable to open file %s", filename);
[self showError:thisline];
return NO;
}
/* release existing data */
while ((thesedata = *all_data) != (datapoints *) NULL) {
free(thesedata->displayed);
count = 0;
while(thesedata->all[count] != (float *) NULL) {
free(thesedata->all[count]);
count++;
}
free(thesedata->all);
free(thesedata);
*all_data++ = (datapoints *) NULL;
}
all_data = toshow; /* read new data */
fgets(thisline, MAXLINE, input);
while (!feof(input)) {
if(!sscanf(thisline, " %1s ", &c)) {
sprintf(thisline, "Unable to read a specification from %s", filename);
[self showError:thisline];
return NO;
}
switch(c) {
case 'N': case 'n': case 'L': case 'l': case 'P': case 'p': case 'B':
case 'b':
fgets(thisline, MAXLINE, input); /* load a new line */
break;
case 'C': case 'c': /* next line contains an RGB color */
fgets(thisline, MAXLINE, input);
break;
default:
sprintf(thisline, "the beginning of %s doesn't look like a specification",
filename);
[self showError:thisline];
return NO;
}
cpt = thisline; fpt = scratch; ncols = 0;
while(sscanf(cpt, "%f%n", fpt, &nchars) == 1) { /* removed space bewteen %f %n */
cpt += nchars;
ncols++;
fpt++;
}
if (ncols == 0) {
sprintf(thisline, "First line of %s does not contain numeric data",
filename);
[self showError:thisline];
return NO;
}
/* digest the rest of the lines */
expected_cols = ncols; nlines = 1;
while(fgets(thisline, MAXLINE, input) != NULL) {
cpt = thisline; ncols = 0;
while(sscanf(cpt, "%f%n", fpt, &nchars) == 1) { /* removed space bewteen %f %n */
cpt += nchars;
ncols++;
fpt++;
}
if (!ncols) break;
nlines++;
if (ncols != expected_cols) {
sprintf(thisline,
"Expected %d values but got %d values at line %d\n",
expected_cols, ncols, nlines);
[self showError:thisline];
return NO;
}
} /* create the datapoints structure and */
/* store the values */
thesedata = *all_data++ = (datapoints *) malloc(sizeof(datapoints));
switch(c) {
case 'N': case 'n':
thesedata->type = NEITHER;
break;
case 'L': case 'l':
thesedata->type = LINES;
break;
case 'P': case 'p':
thesedata->type = POINTS;
break;
case 'B': case 'b':
thesedata->type = BOTH;
break;
case 'C': case 'c':
thesedata->type = COLOR;
break;
}
thesedata->all = (float **)calloc((size_t) expected_cols + 1,
(size_t) sizeof(float *));
for(ncols = 0; ncols < expected_cols; ncols++) {
thesedata->all[ncols] = (float *)calloc((size_t) nlines, sizeof(float));
float_copy(nlines, thesedata->all[ncols], 1, scratch + ncols,
expected_cols);
}
thesedata->all[expected_cols] = (float *)NULL;
/* make sure path is large enough */
if (2*nlines > max_path)
realloc(path, (2*nlines)*sizeof(float));
thesedata->npts = nlines;
memmove(thesedata->displayed = (float **) calloc(3, sizeof(float *)),
thesedata->all, 3 * sizeof(float *));
}
[self reScale:self];
free(scratch);
fclose(input);
[self display];
return YES;
}
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;
}
- drawSelf:(NXRect*)r :(int)c
{
NXColor lineColor;
datapoints **all_lines = toshow, *thisline;
NXEraseRect(&bounds);
PSsetgray(NX_BLACK);
PSsetlinewidth(0.0);
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);
}
while((thisline = *all_lines++) != (datapoints *) NULL) {
if (thisline->type & 0x4) { /* set the RGB color */
lineColor = NXConvertRGBToColor(*(thisline->displayed)[0],
*(thisline->displayed)[1],
*(thisline->displayed)[2]);
NXSetColor(lineColor);
continue;
}
if( thisline->type & 0x1 && thisline->npts > 1 ) { /* draw the line */
ops[1] = thisline->npts + 32 - 1;
DPSDoUserPath([vm as_DPSpath :thisline->npts
:(thisline->displayed)[0] :(thisline->displayed)[1]
:(thisline->displayed)[2] :path],
2*(thisline->npts), dps_float,
ops, 3, boundingBox, dps_ustroke);
}
if (thisline->type & 0x2) { /* draw points */
if (PSonly)
dotAtPSonly([vm as_DPSpath :thisline->npts
:(thisline->displayed)[0] :(thisline->displayed)[1]
:(thisline->displayed)[2] :path],
2 *(thisline->npts), *dot_offset);
else
dotAt([vm as_DPSpath :thisline->npts
:(thisline->displayed)[0] :(thisline->displayed)[1]
:(thisline->displayed)[2] :path offset:dot_offset],
2 * (thisline->npts), dotgstate);
}
}
return self;
}
- (BOOL)acceptsFirstMouse
{
return YES;
}
- mouseDown:(NXEvent *)e
{
if( e->data.mouse.click == 2 ) {
[myController inspectCustomComponent];
return self;
}
if( e->flags & NX_COMMANDMASK ) {
[self toggleCube:self];
}
else if (e->flags & NX_ALTERNATEMASK ) {
[self toggleAxes:self];
} else {
[myController refreshInspectorPanel];
}
return [super mouseDown:e];
}
- free
{
int count;
datapoints **all_data = toshow, *thesedata;
while ((thesedata = *all_data) != (datapoints *) NULL) {
free(thesedata->displayed);
count = 0;
while(thesedata->all[count] != (float *) NULL) {
free(thesedata->all[count]);
count++;
}
free(thesedata->all);
free(thesedata);
*all_data++ = (datapoints *) NULL;
}
free(toshow);
if( viewSound ) [viewSound free];
if( dataFileName ) free(dataFileName);
return [super free];
}
- write:(NXTypedStream *)stream
{
int cols, nstruct, ns;
datapoints **all_data = toshow, *thesedata;
[super write:stream];
NXWriteType(stream, "i", &max_path);
nstruct = 0;
while((thesedata = *all_data++) != (datapoints *) NULL) nstruct++;
NXWriteType(stream, "i", &nstruct);
all_data = toshow;
for( ns=0; ns<nstruct; ns++) {
thesedata = *all_data++;
NXWriteTypes(stream, "ii", &thesedata->npts, &thesedata->type);
cols = 0;
while( thesedata->all[cols] != (float *) NULL) {
NXWriteArray(stream, "f", thesedata->npts, *(&thesedata->all[cols]));
cols++;
}
}
NXWriteObject(stream, AngleDisplay);
NXWriteObject(stream, PhiSlider);
currentPhi = -rad_to_deg * [vm getPhi:self];
NXWriteObject(stream, ThetaSlider);
currentTheta = rad_to_deg * [vm getTheta:self];
NXWriteObject(stream, DistanceSlider);
currentDist = [vm getdist:self];
NXWriteTypes(stream, "fff", ¤tPhi, ¤tTheta, ¤tDist);
NXWriteObject(stream, soundButton);
NXWriteRect(stream, &sndBtnRect);
NXWriteObject(stream, viewSound);
NXWriteTypes(stream, "ccc", &showCube, &showAxes, &PSonly);
NXWriteType(stream, "*", &dataFileName);
NXWriteObject(stream, myController);
return self;
}
- read:(NXTypedStream *)stream
{
int cols, nstruct, ns;
datapoints **all_data, *thesedata;
int ncols = 3;
[super read:stream];
NXReadType(stream, "i", &max_path);
NXReadType(stream, "i", &nstruct);
toshow = (datapoints **) calloc(1000, sizeof(datapoints *));
all_data = toshow;
for( ns=0; ns<nstruct; ns++) {
thesedata = *all_data++ = (datapoints *) malloc(sizeof(datapoints));
NXReadTypes(stream, "ii", &thesedata->npts, &thesedata->type);
thesedata->all = (float **)calloc((size_t) ncols+1, (size_t) sizeof(float *));
for( cols=0; cols<ncols; cols++ ) {
thesedata->all[cols] = (float *)calloc((size_t) thesedata->npts, sizeof(float));
NXReadArray(stream, "f", thesedata->npts, *(&thesedata->all[cols]));
}
thesedata->all[ncols] = (float *)NULL;
memmove(thesedata->displayed = (float **) calloc(3, sizeof(float *)),
thesedata->all, 3 * sizeof(float *));
}
AngleDisplay = NXReadObject(stream);
PhiSlider = NXReadObject(stream);
ThetaSlider = NXReadObject(stream);
DistanceSlider = NXReadObject(stream);
NXReadTypes(stream, "fff", ¤tPhi, ¤tTheta, ¤tDist);
soundButton = NXReadObject(stream);
NXReadRect(stream, &sndBtnRect);
viewSound = NXReadObject(stream);
NXReadTypes(stream, "ccc", &showCube, &showAxes, &PSonly);
NXReadType(stream, "*", &dataFileName);
myController = NXReadObject(stream);
return self;
}
- awake
{
[super awake];
[myController setViews:self];
path = (float *) calloc(2000, sizeof(float));
dot_offset[0] = 2.5 * 2 / bounds.size.width;
dot_offset[1] = 2.5 * 2 / bounds.size.height;
[self setDrawSize:(NXCoord) 2:(NXCoord) 2];
[self setDrawOrigin:(NXCoord) -1:(NXCoord) -1];
showCube = NO;
showAxes = YES;
PSonly = YES;
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;
vm = [AzimuthMat new];
openReq = [OpenPanel new];
[self reScale:self];
tag = 63757374; // hex ascii for "cust"
[self setViewParameters];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.