This is StereoView.m in view mode; [Download] [Up]
/* Generated by Interface Builder */
#import <appkit/appkit.h>
#import "StereoView.h"
#import "CubeView.h"
#import "StoreData.h"
#import "JoyStick.h"
#import "stdio.h"
#import <libc.h> // for chdir, getwd
#define equal(s,w) (strcmp(s,w) == 0)
#undef min
#define min(a,b) ((a) < (b) ? (a) : (b))
#undef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#define ctrl(c) ((c) - 'A' + 1) /* control character mapping */
#define plural(n) ((n) == 1 ? "" : "s")
#define thest(n) ((n) == 1 ? "-st" : ((n) == 2 ? "-nd" : ((n) == 3 ? "-rd" \
: "-th")))
#define lastch(s) s[strlen(s)-1]
#define no_ret(s) { register int xyz; /* varname is for lint */ \
for (xyz=strlen(s)-1; xyz >= 0 && \
(s[xyz] == '\r' || s[xyz] == '\n'); ) \
s[xyz--] = '\0'; \
}
#define first_word(s,w) (strncmp(s,w, strlen(w)) == 0)
#define whitespace(c) ((c) == ' ' || (c) == '\t')
#define ok_char(c) (isalnum(c) || (c) == '-' || (c) == '_' || (c) == '.')
#define quote(c) ((c) == '"' || (c) == '\'')
#define onoff(n) (n == 0 ? "OFF" : "ON")
/* find tab stops preceding or following a given column position 'a', where
* the column position starts counting from 1, NOT 0!
* The external integer "tabspacing" must be declared to use this. */
#define prev_tab(a,tb) (((((a-1)/(tb)))*(tb))+1)
#define next_tab(a,tb) (((((a-1)/(tb))+1)*(tb))+1)
#define EYE 2.9/57.3
#define rad_to_deg (180./M_PI)
#define MAXLINE 15000
#define MAXNUM 15000
#define MAXALLOC 200
/*
#define TRUE -1
#define FALSE !TRUE
*/
@implementation StereoView
- initFrame:(const NXRect *)frameRect
{
textDidChange = 0;
textNeedsSaving = 0;
dataList = [[List alloc] init];
max_path = 200;
path = (float *) calloc(2*max_path, sizeof(float));
eyeOffset = EYE;
openReq = [OpenPanel new];
saveReq = [SavePanel new];
[super initFrame:frameRect];
bcopy(frameRect,&left_Rect,sizeof(NXRect));
bcopy(frameRect,&right_Rect,sizeof(NXRect));
NXDivideRect(&left_Rect,&right_Rect,NX_WIDTH(frameRect)/2.,2);
leftView = [[CubeView alloc] initFrame:&left_Rect];
rightView = [[CubeView alloc] initFrame:&right_Rect];
[self setDrawOrigin:(NXCoord) NX_X(frameRect):(NXCoord) NX_Y(frameRect)];
[self addSubview:leftView];
[self addSubview:rightView];
[self addSubview:joyStick];
[self setAutoresizeSubviews:TRUE];
fileNAME = (char *) calloc(1,256);
strcpy(fileNAME,"Untitled");
[self S_Reset:self];
return self;
}
static char angle_buffer[20];
- setDelegate:anObject
{
delegate = anObject;
return self;
}
- copy:sender /* code contributed by Dan McCreary of NeXT */
{
id pb = [Pasteboard new]; /* global Pasteboard object */
NXStream *st; /* stream to collect data in */
char *data; /* actual data buffer */
int length; /* length of data */
int maxLength; /* (not used here) */
/* To see how to use the pasteboard */
/* see page 10-33 of the SysRefMan */
[self prtCopy];
/* declare that we will supply a */
/* single type of data: PostScript */
[pb declareTypes:&NXPostScriptPboard num:1 owner:self];
/* get a stream which writes to memory */
st = NXOpenMemory( NULL, 0, NX_WRITEONLY );
/* write PostScript code for this view into the stream */
[self copyPSCodeInside:NULL to:st];
/* get actual data buffer from stream */
NXGetMemoryBuffer( st, &data, &length, &maxLength );
/* write PostScript data to pasteboard */
[pb writeType:NXPostScriptPboard data:data length:length];
/* deallocate stream, including its buffer */
NXCloseMemory( st, NX_FREEBUFFER );
[self display];
return self;
}
-(BOOL)acceptsFirstResponder
{ /* make this view accept first */
return YES; /* responder so it will understand copy */
}
/*
-resignFirstResponder
{
return self;
}
*/
- showError:(char *)errorMessage
{
NXRunAlertPanel("Error", errorMessage, "OK", NULL, NULL);
return self;
}
- prtCopy
{
[leftView printPSCode:leftView];
[rightView printPSCode:rightView];
[self display];
return self;
}
- printPSCode:sender
{
[leftView printPSCode:leftView];
[rightView printPSCode:rightView];
[self display];
[super printPSCode:self];
[self display];
return self;
}
- textChanged:sender
{
textDidChange = 1;
return self;
}
- textEdited:sender
{
textNeedsSaving = 1;
return self;
}
- plot:sender
{
NXStream *stream;
if (textDidChange == 1) {
if (delegate && [delegate respondsTo:@selector(stereoView:providePoints:)])
[delegate stereoView:self providePoints:&stream];
textDidChange = 0;
[self readData:(NXStream *)stream];
[leftView getStruct:dataList];
[rightView getStruct:dataList];
[leftView reScale:self];
[rightView reScale:self];
}
[self set_Theta:self];
[self set_Phi:self];
[self set_dist:self];
[self display];
return self;
}
- clear:sender
{
/* release existing data */
if ([dataList count] != 0) [dataList freeObjects];
[leftView getStruct:dataList];
[rightView getStruct:dataList];
// [leftView clear:self];
// [rightView clear:self];
// [self set_Theta:self];
// [self set_Phi:self];
// [self set_dist:self];
[self S_Reset:self];
[self textChanged:self];
[self display];
return self;
}
- S_Reset:sender
{
float floatValue;
NXPoint theLocation;
[leftView getStruct:dataList];
[rightView getStruct:dataList];
theLocation.x = 0.;
theLocation.y = 0.;
[joyStick reSet];
[self setPhiTheta:self];
floatValue = 2.0;
[showDist setFloatValue:floatValue];
[DistanceSlider setFloatValue:floatValue];
[leftView Reset:leftView];
[rightView Reset:rightView];
[leftView setTheta:-eyeOffset];
[rightView setTheta:+eyeOffset];
[[self window] setTitle:fileNAME];
[self display];
return self;
}
- setPhiTheta:sender
{
float phi, theta;
phi = 2*[joyStick getYVal:self]*90.;
theta = 2*[joyStick getXVal:self]*180.;
[showPhi setFloatValue:phi];
[showTheta setFloatValue:theta];
[self set_Theta:self];
[self set_Phi:self];
return self;
}
- set_Theta:sender
{
float floatValue;
floatValue = [showTheta floatValue]/rad_to_deg;
[leftView setTheta:floatValue-eyeOffset];
[rightView setTheta:floatValue+eyeOffset];
[self display];
return self;
}
- set_Phi:sender
{
float floatValue;
floatValue = [showPhi floatValue]/rad_to_deg;
[leftView setPhi:floatValue];
[rightView setPhi:floatValue];
[self display];
return self;
}
- set_dist:sender
{
float floatValue;
floatValue = [DistanceSlider floatValue];
sprintf(angle_buffer, "%6.2f", floatValue);
[showDist setStringValue:angle_buffer];
[leftView setdist:floatValue];
[rightView setdist:floatValue];
[self display];
return self;
}
- setAxes:(int) intVal
{
[AxesButton setState:intVal];
[leftView setAxes:intVal];
[rightView setAxes:intVal];
[self display];
return self;
}
- (int)getAxes
{
return [AxesButton state];
}
- toggle_Axes:sender
{
[leftView toggleAxes:self];
[rightView toggleAxes:self];
[self display];
return self;
}
- setCube:(int) intVal
{
[CubeButton setState:intVal];
[leftView setCube:intVal];
[rightView setCube:intVal];
[self display];
return self;
}
- (int)getCube
{
return [CubeButton state];
}
- toggle_Cube:sender
{
[leftView toggleCube:self];
[rightView toggleCube:self];
[self display];
return self;
}
- setEyeOffset:(float) floatVal
{
int eye;
eyeOffset = floatVal;
if (floatVal < 0.)eye = NO;
else eye = YES;
[EyeButton setState:eye];
[self set_Theta:self];
[self display];
return self;
}
- (float) getEyeOffset
{
return eyeOffset;
}
- toggle_Eyes:sender
{
[self setEyeOffset: - eyeOffset];
return self;
}
- sizeTo:(NXCoord)width :(NXCoord)height
{
NXRect frameRect;
[super sizeTo:width :height];
[self getFrame:&frameRect];
bcopy(&frameRect,&left_Rect,sizeof(NXRect));
bcopy(&frameRect,&right_Rect,sizeof(NXRect));
NXDivideRect(&left_Rect,&right_Rect,NX_WIDTH(&frameRect)/2.,2);
[leftView setFrame:&left_Rect];
[leftView initialize];
[rightView setFrame:&right_Rect];
[rightView initialize];
[self setDrawOrigin:(NXCoord) NX_X(&frameRect):(NXCoord) NX_Y(&frameRect)];
[self S_Reset:self];
return self;
}
- windowDidResize:sender
{
/* This is not received since the controller handles it */
printf("windowDidResize for StereoView\n");
return self;
}
- windowWillResize:sender toSize:(NXSize *)aSize
{
/* This is not received since the controller handles it */
printf("windowWillResize for StereoView\n");
return self;
}
- openData:sender
{
const char *const ext[5] = {"dat", "data", "3d", "S3d", NULL};
if (textNeedsSaving)
[self saveInRequest:sender];
if([openReq runModalForTypes:ext] && (fileNAME = (char *)[openReq filename])) {
[self readSData:fileNAME];
}
else
[self showError:"No file chosen or could not open file"];
return self;
}
// saveRequest: saves the current window under its default name (found in
// the title bar). Note that if the title bar is empty or the default title
// is "Untitled" then saveRequest: will put up a save panel, giving the user
// a chance to specify a real title.
- saveRequest:sender
{
const char *fileName;
const char *const types[2] = {"S3d",
NULL};
id curWin = [self window];
if (textNeedsSaving)
[self saveInRequest:sender];
[saveReq setRequiredFileType:types[0]];
if (curWin == nil)
[self showError:"errorOnSaveRequest"];
else {
// Check to see if the current window is titled and the title is not
// "Untitled". If so, save the file, else put up a save panel...
fileName = [curWin title];
if (strcmp (fileName, "Untitled"))
[self saveText:curWin inPath:fileName];
else [self saveInRequest:sender];
}
textNeedsSaving = 0;
return self;
}
// saveInRequest: gives the user a chance to save the current window
// under a new name.
- saveInRequest:sender
{
const char *fileName;
const char *const types[2] = {"S3d",
NULL};
id curWin;
curWin = [self window];
[saveReq setRequiredFileType:types[0]];
if (curWin == nil)
[self showError:"errorOnSaveIn"];
else {
// Get a file name from the user; use title of the window as default.
if (([saveReq runModalForDirectory:"."
file:[curWin title]]) &&
(fileName = [saveReq filename]))
[self saveText:curWin inPath:fileName];
}
textNeedsSaving = 0;
return self;
}
// saveWindow writes a window out the archive file whose name is specified
// by the second argument. The title of the current window is also set
// accordingly.
- saveText:(id)win inPath:(const char *)name
{
FILE *output;
char thisline[MAXLINE];
NXStream *stream;
BOOL s_gets();
if((output = fopen(name, "w")) == NULL) {
sprintf(thisline, "Unable to open file %s", name);
[self showError:thisline];
return NULL;
}
if (delegate && [delegate respondsTo:@selector(stereoView:providePoints:)])
[delegate stereoView:self providePoints:&stream];
s_gets(thisline, MAXLINE, stream);
while (!NXAtEOS(stream)) {
fprintf(output,"%s",thisline);
s_gets(thisline, MAXLINE, stream);
}
fclose(output);
[win setTitle:name];
return self;
}
// closeRequest closes the current window by simulating a click on the
// closebutton. A check should probably be added to give the user the
// option of saving the window before closing
- closeRequest:sender
{
if (textNeedsSaving)
[self saveInRequest:sender];
if (delegate && [delegate respondsTo:@selector(stereoView:clearText:)])
[delegate stereoView:self clearText:fileNAME];
strcpy(fileNAME,"Untitled");
[self clear:self];
[self S_Reset:self];
textNeedsSaving = 0;
return self;
}
- readSData:(char *)fileName
{
if (!strcmp(fileName,"")) {
/* [self set_Theta:self];
[self set_Phi:self];
[self set_dist:self];
strcpy(fileNAME,"Untitled");
[[self window] setTitle:fileName];
[self display];
*/
[self clear:self];
} else {
if ([self readFile:fileName] != NULL) {
[self clear:self];
[[self window] setTitle:fileName];
[self textChanged:self];
[self plot:self];
}
}
return self;
}
- drawSelf:(const NXRect *)rects :(int)rectCount
{
NXDrawWhiteBezel(rects,rects);
return self;
}
- readFile:(char *)fileName
{
FILE *input;
char thisline[MAXLINE], *cpt, *trimmer;
if((input = fopen(fileName, "r")) == NULL) {
sprintf(thisline, "Unable to open file %s", fileName);
[self showError:thisline];
return NULL;
}
if (delegate && [delegate respondsTo:@selector(stereoView:clearText:)])
[delegate stereoView:self clearText:fileName];
fgets(thisline, MAXLINE, input);
while (!feof(input)) {
trimmer = cpt = &thisline[0];
while(*trimmer++ != '\n'); trimmer--;
while(*trimmer-- == ' '); trimmer++;
if (*trimmer != '\n') *trimmer++ = '\n'; *trimmer = '\0';
if (delegate && [delegate respondsTo:@selector(stereoView:pointDidChange:)])
[delegate stereoView:self pointDidChange:cpt];
fgets(thisline, MAXLINE, input);
}
fclose(input);
return self;
}
BOOL s_gets(thisline, max, stream)
char thisline[];
int max;
NXStream *stream;
{
int i;
i = 0;
while (!NXAtEOS(stream)) {
thisline[i++] = NXGetc(stream);
if (i > max) {
return FALSE;
}
if (thisline[i-1] == '\n') {
thisline[i] = '\0';
return TRUE;
}
}
return(FALSE);
}
- (BOOL) readData:(NXStream *)stream
{
char line[128], thisline[128], *aPtr, *word();
char cmd;
int nwords,i, words(), tolower(), isalpha();
float x[3], *fpt, argv[6];
long pts_read;
scratch = (float *) calloc(MAXNUM, sizeof(float));
/* release existing data */
if ([dataList count] != 0) [dataList freeObjects];
pts_read = 0;
cmd = 'p';
argv[0] = 0.;
argv[1] = NX_BLACK;
nwords = 0;
fpt = scratch;
pts_read = 0;
while(s_gets(line,128,stream)) {
if(lastch(line) == '\n') lastch(line) = '\0';
if(isalpha(line[0])) {
if (pts_read != 0) {
[self store_pts:cmd:argv];
[dataList addObject:myStorage];
}
cmd = tolower(line[0]);
nwords = min(words(line),5);
for(i=1;i<6;i++) argv[i] = 0;
for(i=1;i<=nwords;i++) {
if((aPtr = word(i,line)) != NULL) {
sscanf(aPtr,"%f",&argv[i]);
}
}
switch (cmd) {
case 'n':
break;
case 'l':
argv[1] = (nwords < 1)?0.:argv[1]; /* width */
argv[2] = (nwords < 2)?NX_BLACK:argv[2]; /* shade */
// Add rgb here and in p and implement in Cubeview.m and psfcns (dim argv)
for (i=3;i<6;i++)
argv[i] = (nwords < i)?0.:argv[i]; /* color */
break;
case 'p':
argv[1] = (nwords < 1 )?0.:argv[1]; /* radius */
argv[2] = (nwords < 2)?NX_BLACK:argv[2]; /* shade */
for (i=3;i<6;i++)
argv[i] = (nwords < i)?0.:argv[i]; /* color */
break;
case 'b':
break;
default:
sprintf(thisline, "Unknown Data Type");
[self showError:thisline];
return NO;
break;
}
fpt = scratch;
pts_read = 0;
nlines = 0;
continue;
}
sscanf(line,"%f %f %f",&x[0], &x[1], &x[2]);
nlines++;
if (pts_read + 3 > MAXNUM) {
sprintf(thisline, "Number of points exceeds %d\n", MAXNUM);
[self showError:thisline];
free(scratch);
return NO;
}
for(i=0;i<3;i++) {
*fpt++ = x[i];
}
pts_read += 3;
}
if (pts_read != 0) {
[self store_pts:cmd:argv];
[dataList addObject:myStorage];
}
// [self debug];
free(scratch);
// [self display];
return YES;
}
- debug
/* Debuggin output
*/
{
int i, j, k, nitems, type, ntypes;
float *xx, *gpt, **displayed;
// char thisline[128];
ntypes = [dataList count];
printf("There are %d types in dataList\n",ntypes);
for(j=0;j<ntypes;j++) {
myStorage = [dataList objectAt:j];
nitems = [myStorage howMany];
printf("Type # %d has %d points\n",j,nitems);
xx = [myStorage args];
type = [myStorage dataType];
gpt = [myStorage array];
printf("Type = %d, argv is %10.6f, %10.6f, %10.6f\n",
type,xx[1],xx[2],xx[3]);
for(i=0;i<nitems/3;i++) {
printf("%d) ",i);
for (k=0;k<3;k++)
printf(" %10.6f",gpt[i+k*nitems/3]);
printf("\n");
}
displayed = [myStorage displayed];
printf(" Show same 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;
}
- (BOOL)store_pts:(char)cmd:(float *)argv
{
int type = NEITHER;
/* create the datapoints structure and store the values */
switch(cmd) {
case 'n':
type = NEITHER;
break;
case 'l':
type = LINES;
break;
case 'p':
type = POINTS;
/*
* Store radius, shade, label here in thesedata->radius, etc.
*/
break;
case 'b':
type = BOTH;
break;
}
myStorage = [[StoreData alloc] init:type:3*nlines:scratch:argv];
return YES;
}
int words(str)
char *str;
{
int isalnum(), count=0;
while(*str != '\0') {
while(ok_char(*str)) str++; /* skip characters */
while(whitespace(*str)) str++; /* skip whitespace */
if(ok_char(*str)) count++;
}
return count;
}
char *word(i,str)
int i;
char *str;
{
int isalnum(), count=0;
if(i > words(str)) return NULL;
while(*str != '\0') {
while(ok_char(*str)) str++; /* skip characters */
while(whitespace(*str)) str++; /* skip whitespace */
if(ok_char(*str))
if(++count == i) return str;
}
return NULL;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.