This is Plot3DView.m in view mode; [Download] [Up]
/* Plot3DView.m Copyright 1992 Steve Ludtke */ /* This view allows the display of 3d functions with real time rotation */ #import "Plot3DView.h" #import "PlotShape.h" #import "PControl.h" #import <appkit/appkit.h> #import <3Dkit/3Dkit.h> #import <dpsclient/event.h> #import <dpsclient/psops.h> #import <stdio.h> #import <math.h> #include <libc.h> #import "Expression.h" #import "DensView.h" #define LRAD 10.0 extern id NXApp; float rnd0(float x) { if (x<0) return(ceil(x)); else return floor(x); } @implementation Plot3DView -initFrame:(NXRect *)myrect { int i,j,ddl; RtPoint fromP = {0,0,6.0}, toP = {0,0,0}; RtPoint lFromP = {5.0,10.0,5.0},lToP = {0,0,0}; RtMatrix mx = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1.0 }; id aShader; char home[60]; [super initFrame:(NXRect *)myrect]; [self setBackgroundColor:NX_COLORWHITE]; [self setDrawBackgroundColor:YES]; [self setEyeAt:fromP toward:toP roll:0.0]; mx[0][0]=mx[1][1]=mx[2][2]=3.0/fromP[2]; [self setPreTransformMatrix:mx]; aShader=[[N3DShader alloc] init]; [(N3DShader *)aShader setShader:"matte"]; shape=[[PlotShape alloc] init]; [(N3DShape *) shape setShader:aShader]; [shape scale:-1.0 :1.0 :1.0]; [[self setWorldShape:shape] free]; ambLight=[[N3DLight alloc] init]; [ambLight makeAmbientWithIntensity:0.2]; [self addLight:ambLight]; ambient=0.2; ltheta=.785; lchi=-.785; aLight=[[N3DLight alloc] init]; lFromP[0]= LRAD*sin(lchi)*cos(ltheta); lFromP[2]= LRAD*cos(lchi)*cos(ltheta); lFromP[1]= LRAD*sin(ltheta); [aLight makeDistantFrom:lFromP to:lToP intensity:0.8]; [self addLight:aLight]; Rmode=3; ddl=[Window defaultDepthLimit]; if (ddl==NX_TwoBitGrayDepth||ddl==NX_EightBitGrayDepth) ddl=0; else ddl=1; /* initialize preferences */ for (i=0; i<MAXSETS; i++) { pref[i].ndata=0; pref[i].sym= -1; pref[i].flag= F_EQN; pref[i].alpha=1.0; if (ddl) { pref[i].mapcol[0][0]=0.0; pref[i].mapcol[0][1]=0.0; pref[i].mapcol[0][2]=0.8; pref[i].mapcol[1][0]=0; pref[i].mapcol[1][1]=0.733; pref[i].mapcol[1][2]=0.8; pref[i].mapcol[2][0]=0.0; pref[i].mapcol[2][1]=0.8; pref[i].mapcol[2][2]=0.0; pref[i].mapcol[3][0]=0.6; pref[i].mapcol[3][1]=0.333; pref[i].mapcol[3][2]=0.067; pref[i].mapcol[4][0]=.867; pref[i].mapcol[4][1]=.867; pref[i].mapcol[4][2]=.867; } else { for (j=0; j<5; j++) { pref[i].mapcol[j][0]=pref[i].mapcol[j][1]=pref[i].mapcol[j][2]= .5+(float)j/10.0; } } for (j=0; j<5; j++) pref[i].mapsel[j]=1; pref[i].mapmode=1; pref[i].fileData=pref[i].Sdata=pref[i].demData=NULL; pref[i].expr=[[Expression alloc] init]; [pref[i].expr parse:"0"]; pref[i].nx=pref[i].ny=10; } /* initial function to display */ pref[0].sym=5; pref[0].nx=pref[0].ny=40; [pref[0].expr parse:"sin(sqrt(abs(x*y)))/sqrt(x^2+y^2)"]; pref[0].flag=F_EQN; /* start spinning, all angles in radians */ chi=.2; theta=.433; /*dchi=0.025;*/ dchi=0.0; initflag=1; Rflags=RF_axis+RF_persp; Omode=0; aspect=1.0; [shape setOver:Omode]; if (ddl) { flagcol[0][0]=flagcol[4][0]=0.0; flagcol[0][1]=flagcol[4][1]=0.0; flagcol[0][2]=flagcol[4][2]=1.0; flagcol[1][0]=flagcol[2][0]=1.0; flagcol[1][1]=flagcol[2][1]=1.0; flagcol[1][2]=flagcol[2][2]=1.0; flagcol[3][0]=0.0; flagcol[3][1]=1.0; flagcol[3][2]=0.0; } else { flagcol[0][0]=flagcol[4][0]=0.5; flagcol[0][1]=flagcol[4][1]=0.5; flagcol[0][2]=flagcol[4][2]=0.5; flagcol[1][0]=flagcol[2][0]=1.0; flagcol[1][1]=flagcol[2][1]=1.0; flagcol[1][2]=flagcol[2][2]=1.0; flagcol[3][0]=0.0; flagcol[3][1]=0.0; flagcol[3][2]=0.0; } [shape setFlagColors:flagcol]; [[[NXApp printInfo] setVertCentered:YES] setOrientation:NX_PORTRAIT andAdjust:YES]; [[NXApp printInfo] setMarginLeft:0.0 right:0.0 top:0.0 bottom:0.0]; [[NXApp printInfo] setHorizPagination:NX_FITPAGINATION]; [[NXApp printInfo] setVertPagination:NX_FITPAGINATION]; timer=(DPSTimedEntry)DPSAddTimedEntry(TIMESTEP,itstime,self,NX_RUNMODALTHRESHOLD); [self zoom:self]; if (getenv("USER")!=NULL) { sprintf(home,"/tmp/%s",getenv("USER")); mkdir(home,0777); } return self; } /* fix the scaling after being resized */ -superviewSizeChanged:(const NXSize *)oldsize { [super superviewSizeChanged:oldsize]; [self zoom:self]; return self; } -free { DPSRemoveTimedEntry(timer); [super free]; return self; } -drawPS:(NXRect *)myrect :(int)rectCount { char s[80],t[20]; int i,n,xyz[61]; float x,y,xpm,ypm,pv[61]; RtPoint pnt[61]; if (bounds.size.width<150) return self; /* display alt and az in upper right corner */ PSsetgray(0.0); PSselectfont("Helvetica",10.0); sprintf(s,"Alt:%6.2f Az:%6.2f",theta*57.295787,chi*57.295787); PSmoveto(bounds.size.width-100.0,bounds.size.height-15.0); PSshow(s); PSstroke(); if (Rflags&RF_labels && Rmode<4) { if (chi>(M_PI/2.0)&&chi<(M_PI*1.5)) ypm=1.1; else ypm=-1.1; if (chi<M_PI) xpm=1.1; else xpm=-1.1; for (n=0,y=Tick0[0],x=Tick00[0]; x<1; y+=Tick1[0],x+=Tick01[0],n++) { if (n>59) n=59; pnt[n][0]=x; pnt[n][1]=ypm; pnt[n][2]=-1.1; pv[n]=y; xyz[n]=0; } for (y=Tick0[1],x=Tick00[1]; x<1; y+=Tick1[1],x+=Tick01[1],n++) { if (n>59) n=59; pnt[n][1]=x; pnt[n][0]=xpm; pnt[n][2]=-1.1; pv[n]=y; xyz[n]=1; } for (y=Tick0[2],x=Tick00[2]; x<1; y+=Tick1[2],x+=Tick01[2],n++) { if (n>59) n=59; pv[n]=y; pnt[n][2]=x; if ((chi>M_PI/4.0&&chi<M_PI*.75)||(chi>M_PI*1.25&&chi<M_PI*1.75)) { pnt[n][1]=ypm; pnt[n][0]=-xpm; } else { pnt[n][1]=-ypm; pnt[n][0]=xpm; } xyz[n]=2; } pnt[n][0]=xpm/1.18; pnt[n][1]=ypm/1.18; pnt[n][2]=-1.0; [shape convertObjectPoints:pnt count:n+1 toCamera:self]; x=pnt[n][0]; for (i=0; i<n; i++) { if (i==0|| xyz[i]!=xyz[i-1]) strcpy(t,[[tickpos cellAt:2 :xyz[i]] stringValue]); sprintf(s,t,pv[i]); if (pnt[i][0]<x) PSmoveto(pnt[i][0]-20.0,pnt[i][1]-5.0); else PSmoveto(pnt[i][0],pnt[i][1]-5.0); PSshow(s); } PSstroke(); } return self; } /* recalculates and redisplays data */ -zoom:sender { float x0,x1,xs,y0,y1,ys,xf,yf,zf; float z0,z1,x,y,z,zz,dz0,dz1,T,A,B,C,D; int i,j=0,k,cm,nc,color[5],xi,yi; id tmp; T=[[varT cellAt:0 :0] floatValue]; A=[[varT cellAt:1 :0] floatValue]; B=[[varT cellAt:2 :0] floatValue]; C=[[varT cellAt:3 :0] floatValue]; D=[[varT cellAt:4 :0] floatValue]; /* calculate minima, maxima and step sizes */ x0=minX; x1=maxX; y0=minY; y1=maxY; xf=(x1-x0)/2.0; yf=(y1-y0)/2.0; /* make sure there's enough space in the data array */ for (i=0; i<NFN; i++) { if ((pref[i].sym==-1&&(i!=1||pref[0].mapmode!=3)) || (pref[i].fileData!=NULL)) continue; if (pref[i].ndata!=(pref[i].nx*pref[i].ny)) { if (pref[i].ndata!=0) { free(pref[i].data); free(pref[i].color); } pref[i].data=malloc(sizeof(Point)*(pref[i].nx*pref[i].ny+2)); pref[i].color=malloc(sizeof(RtColor)*(pref[i].nx*pref[i].ny+2)); pref[i].ndata=pref[i].nx*pref[i].ny; } } z0=MAXFLOAT; z1= -MAXFLOAT; /* calculate (function mode) or clip (file mode) the data */ /* also finds min/max Z */ for (i=NFN-1; i>=0; i--) { if (pref[i].sym==-1&&(i!=1||pref[0].mapmode!=3)) continue; tmp=pref[i].expr; [tmp setVar:"t" value:T]; [tmp setVar:"a" value:A]; [tmp setVar:"b" value:B]; [tmp setVar:"c" value:C]; [tmp setVar:"d" value:D]; switch (pref[i].flag) { /* DEM mode */ case F_DEM: xs=(maxX-x0)/(float)(pref[i].nx-1); ys=(maxY-y0)/(float)(pref[i].ny-1); x1=maxX+xs/2.0; y1=maxY+ys/2.0; j=0; for (y=y0; y<y1; y+=ys) { for (x=x0; x<x1; x+=xs) { pref[i].data[j].x=(x-x0)/xf-1.0; pref[i].data[j].y=(y-y0)/yf-1.0; xi=floor((x-pref[i].demx[0])/pref[i].demx[2]+.5); yi=floor((y-pref[i].demy[0])/pref[i].demy[2]+.5); if (xi<0||yi<0||xi>pref[i].demnx-1||yi>pref[i].demny-1) zz=pref[i].data[j].z=0; else zz=pref[i].data[j].z=pref[i].demData[xi*pref[i].demny+yi]; [tmp setVar:"x" value:x]; [tmp setVar:"y" value:y]; [tmp setVar:"z" value:zz]; zz=pref[i].data[j].z=[tmp resultValue]; if (zz!=zz || zz<-MAXFLOAT || zz>MAXFLOAT) zz=pref[i].data[j].z=0; if (zz>z1) z1=zz; if (zz<z0) z0=zz; j++; } } break; /* FILE MODE */ case F_DATA: case F_SDATA: k=0; for (j=0; j<pref[i].nfdata; j++) { if (pref[i].fileData[j].x>x1||pref[i].fileData[j].x<x0|| pref[i].fileData[j].y>y1||pref[i].fileData[j].y<y0) continue; pref[i].data[k].x=(pref[i].fileData[j].x-x0)/xf-1.0; [tmp setVar:"x" value:pref[i].data[k].x]; pref[i].data[k].y=(pref[i].fileData[j].y-y0)/yf-1.0; [tmp setVar:"y" value:pref[i].data[k].y]; [tmp setVar:"z" value:pref[i].fileData[j].z]; pref[i].data[k].z=[tmp resultValue]; if (pref[i].data[k].z>z1) z1=pref[i].data[k].z; if (pref[i].data[k].z<z0) z0=pref[i].data[k].z; k++; } pref[i].ndata=k; if ((pref[i].flag&3)==F_SDATA) ; else if (pref[i].data[0].y!=pref[i].data[1].y) { pref[i].nx=pref[i].ny=(int)floor(sqrt((float)k)); } else { for (j=1; j<k; j++) if (pref[i].data[j-1].y!=pref[i].data[j].y) break; pref[i].nx=j; pref[i].ny=k/j; } break; /* FUNCTION MODE */ case F_EQN: xs=(maxX-x0)/(float)(pref[i].nx-1); ys=(maxY-y0)/(float)(pref[i].ny-1); x1=maxX+xs/2.0; y1=maxY+ys/2.0; j=0; for (y=y0; y<y1; y+=ys) { for (x=x0; x<x1; x+=xs) { pref[i].data[j].x=(x-x0)/xf-1.0; pref[i].data[j].y=(y-y0)/yf-1.0; [tmp setVar:"x" value:x]; [tmp setVar:"y" value:y]; zz=pref[i].data[j].z=[tmp resultValue]; if (zz!=zz || zz<-MAXFLOAT || zz>MAXFLOAT) zz=pref[i].data[j].z=0; if (zz>z1) z1=zz; if (zz<z0) z0=zz; j++; } } break; } } if (z0==MAXFLOAT) return self; /* BOTH MODES */ if (z1<=z0) { z1=z0+.001; z0-=.001; } /* allow the controller to override min/max Z */ [controller minmaxZ:&z0 :&z1]; /* tick spacing calculations */ if ([autotick intValue]) { [self tickCalc:5.0 :x0 :x1 :&Tick0[0] :&Tick1[0]]; [[tickpos cellAt:0 :0] setFloatValue:Tick1[0]]; [[tickpos cellAt:1 :0] setFloatValue:Tick0[0]]; [self tickCalc:5.0 :y0 :y1 :&Tick0[1] :&Tick1[1]]; [[tickpos cellAt:0 :1] setFloatValue:Tick1[1]]; [[tickpos cellAt:1 :1] setFloatValue:Tick0[1]]; [self tickCalc:5.0 :z0 :z1 :&Tick0[2] :&Tick1[2]]; [[tickpos cellAt:0 :2] setFloatValue:Tick1[2]]; [[tickpos cellAt:1 :2] setFloatValue:Tick0[2]]; } else { Tick1[0]=[[tickpos cellAt:0 :0] floatValue]; Tick0[0]=[[tickpos cellAt:1 :0] floatValue]; Tick1[1]=[[tickpos cellAt:0 :1] floatValue]; Tick0[1]=[[tickpos cellAt:1 :1] floatValue]; Tick1[2]=[[tickpos cellAt:0 :2] floatValue]; Tick0[2]=[[tickpos cellAt:1 :2] floatValue]; } Tick00[0]=(Tick0[0]-minX)/(maxX-minX)*2.0-1.0; Tick01[0]=Tick1[0]/(maxX-minX)*2.0; Tick00[1]=(Tick0[1]-minY)/(maxY-minY)*2.0-1.0; Tick01[1]=Tick1[1]/(maxY-minY)*2.0; Tick00[2]=(Tick0[2]-z0)/(z1-z0)*2.0-1.0; Tick01[2]=Tick1[2]/(z1-z0)*2.0; [shape setTicks:Tick00 :Tick01]; zf=(z1-z0)/2.0; /* scale and clip Z */ for (i=NFN-1; i>=0; i--) { if (pref[i].sym==-1&&(i!=1||pref[0].mapmode!=3)) continue; /* Spherical coordinates */ if (pref[i].sym==6) { if (pref[i].Sdata!=NULL) free(pref[i].Sdata); pref[i].Sdata=malloc(sizeof(Point)*pref[i].ndata); for (k=0; k<pref[i].ndata; k++) { x=(pref[i].data[k].x+1.0)*xf+x0; y=(pref[i].data[k].y+1.0)*yf+y0; if (fabs(z0)>fabs(z1)) z=pref[i].data[k].z/fabs(z0); else z=pref[i].data[k].z/fabs(z1); if (z>1.0) z=1.0; if (z<-1.0) z=-1.0; pref[i].Sdata[k].x=z*cos(y)*sin(x); pref[i].Sdata[k].y=z*sin(y)*sin(x); pref[i].Sdata[k].z=z*cos(x); } } /* color info */ cm=pref[i].mapmode; if (cm==3&&(pref[i].nx!=pref[i+1].nx||pref[i].ny!=pref[i+1].ny)) cm=-1; for (j=k=0; j<5; j++) if (pref[i].mapsel[j]) { color[k]=j; k++; } nc=k; if (nc<2) cm=0; // gradient mode, calculate gradients if (cm==2 && pref[i].ndata==(pref[i].nx*pref[i].ny)) { dz0=MAXFLOAT; dz1=-MAXFLOAT; for (j=0; j<pref[i].ny; j++) { for (k=0; k<pref[i].nx; k++) { xi=pref[i].nx*j+k; yi=pref[i].nx; // df/dx if (k==0) x=(pref[i].data[xi+1].z-pref[i].data[xi].z)*2.0; else if (k==pref[i].nx-1) x=(pref[i].data[xi].z-pref[i].data[xi-1].z)*2.0; else x=pref[i].data[xi+1].z-pref[i].data[xi-1].z; // df/dy if (j==0) y=(pref[i].data[xi+yi].z-pref[i].data[xi].z)*2.0; else if (j==pref[i].ny-1) y=(pref[i].data[xi].z-pref[i].data[xi-yi].z)*2.0; else y=pref[i].data[xi+yi].z-pref[i].data[xi-yi].z; z=sqrt(x*x+y*y); if (z>dz1) dz1=z; if (z<dz0) dz0=z; pref[i].color[xi][0]=z; } } dz1-=dz0; } for (k=0; k<pref[i].ndata; k++) { // clip data in z if (pref[i].data[k].z>z1) pref[i].data[k].z=z1; if (pref[i].data[k].z<z0) pref[i].data[k].z=z0; z=pref[i].data[k].z=(pref[i].data[k].z-z0)/zf-1.0; // color mode 1 = altitude based color, 2 = grad based color, // 3 = color from next data set if (cm==2) z=(pref[i].color[k][0]-dz0)/dz1; else if (cm==3) z=(pref[i+1].data[k].z+1.0)/2.0; else if(cm==-1) z=0.0; else z=(z+1.0)/2.0; if (cm!=0) { j=floor(z*.9999*(float)(nc-1)); z=z*(float)(nc-1)-(float)j; pref[i].color[k][0]=z*pref[i].mapcol[color[j+1]][0]+ (1.0-z)*pref[i].mapcol[color[j]][0]; pref[i].color[k][1]=z*pref[i].mapcol[color[j+1]][1]+ (1.0-z)*pref[i].mapcol[color[j]][1]; pref[i].color[k][2]=z*pref[i].mapcol[color[j+1]][2]+ (1.0-z)*pref[i].mapcol[color[j]][2]; } } } /* display 3d plot */ [shape setData:pref :Rmode :Rflags]; [shape setAng:theta :chi :phi :aspect :ambient]; [self display]; /* display density plot */ [controller updDen:Tick00 :Tick01]; return self; } /* obvious */ -setAng:(float)alt :(float)az { theta=alt; chi=az; return self; } -setPhi:sender { phi=[sender floatValue]; [shape setAng:theta :chi :phi :aspect :ambient]; [self display]; return self; } /* allows spinning and zooming with the mouse */ -mouseDown:(NXEvent *)oevent { int oldMask,loop=1; float ix=0,iy=0,ix2=0,iy2=0; NXEvent *event,evs; long tm,tm2; evs=*oevent; oevent=&evs; [self convertPoint:&oevent->location fromView:nil]; oevent->location.x=oevent->location.x/bounds.size.width*2.0-1.0; oevent->location.y=oevent->location.y/bounds.size.height*2.0-1.0; ix2=ix=oevent->location.x; iy2=iy=oevent->location.y; tm2=tm=oevent->time; oldMask = [window addToEventMask:NX_LMOUSEDRAGGEDMASK]; while (loop) { event = [NXApp getNextEvent:(NX_LMOUSEUPMASK | NX_LMOUSEDRAGGEDMASK)]; [self convertPoint:&event->location fromView:nil]; event->location.x=event->location.x/bounds.size.width*2.0-1.0; event->location.y=event->location.y/bounds.size.height*2.0-1.0; switch (event->type) { case NX_LMOUSEUP: loop = 0; dchi=-(event->location.x-ix2)/(float)(event->time-tm2)*15.0; if (fabs(dchi)<.004) dchi=0.0; [shape setAng:theta :chi :phi :aspect :ambient]; [self display]; break; case NX_LMOUSEDRAGGED: theta-=(event->location.y-iy)*3.0; chi-=(event->location.x-ix)*4.0; if (theta>M_PI/2.0) theta=M_PI/2.0; if (theta<-M_PI/2.0) theta=-M_PI/2.0; while (chi>2.0*M_PI) chi-=2.0*M_PI; while (chi<0.0) chi+=2.0*M_PI; ix2=ix; iy2=iy; tm2=tm; ix=event->location.x; iy=event->location.y; tm=event->time; [shape setAng:theta :chi :phi :aspect :ambient]; [self display]; break; default: break; } } [window setEventMask:oldMask]; return self; } /* function called by timer */ void itstime(DPSTimedEntry entry,double now,id call) { [call step]; return; } /* do one time step */ -step { if (initflag) { /* first time, do initialization stuff */ if (controller==nil) return self; [controller startup:pref]; [self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES]; [self zoom:self]; initflag=0; } if (dchi==0.0) return self; chi+=dchi; while (chi>2.0*M_PI) chi-=2.0*M_PI; while (chi<0.0) chi+=2.0*M_PI; [shape setAng:theta :chi :phi :aspect :ambient]; [self display]; return self; } -tickCalc:(float)n :(float)x0 :(float)x1 :(float *)min :(float *)spa { float s,e; s=(x1-x0)/n; e=floor(log10(s)); if (s/pow(10.0,e)<3.0) s=floor(s/pow(10.0,e-1.0))*pow(10.0,e-1.0); else s=floor(s/pow(10.0,e))*pow(10.0,e); *min=(floor(x0/s)+1.0)*(s); *spa=s; return self; } /* new min/max values */ -zoomTo:(float)minx :(float)miny :(float)maxx :(float)maxy { minX=minx; minY=miny; maxX=maxx; maxY=maxy; return self; } -(int)acceptsFirstMouse { return (YES); } -setcontroller:con { controller=con; return self; } /* allow user to pause spinning */ -togFreeze:sender { static float Tdchi; if ([sender intValue]) { Tdchi=dchi; dchi=0.0; return self; } dchi=Tdchi; return self; } - renderSelf:(RtToken)context { return self; } -makeSMap:sender { FILE *out; char home[60],s[80]; id image,rep; NXSize size = { 400.0,400.0 }; NXStream *stream; float xs,ys,x,y,xpm,ypm,fs; int r; sprintf(home,"/tmp/%s",getenv("USER")); if (getenv("USER")==NULL) strcpy(home,"/tmp"); /* write maps for axis labels */ if (Rflags&RF_labels) { [window setTitle:"Generating Axis Label Maps"]; if (chi>(M_PI/2.0)&&chi<(M_PI*1.5)) ypm=1.0; else ypm=-1.0; if (chi<M_PI) xpm=1.0; else xpm=-1.0; r=floor(chi/M_PI*4.0); image=[[NXImage alloc] initSize:&size]; [image setCacheDepthBounded:NO]; [image useCacheWithDepth:NX_TwentyFourBitRGBDepth]; rep=[image lastRepresentation]; [rep setAlpha:NO]; [rep setNumColors:3]; [image lockFocus]; PSselectfont("Helvetica-Bold",fs=[fontSize floatValue]); PSsetrgbcolor(1.0,.95,1.0); PSmoveto(0,0); PSlineto(1.0,1.0); PSstroke(); PSsetrgbcolor(0,0,0); strcpy(s,[[axisTitle cellAt:0 :0] stringValue]); PSstringwidth(s,&xs,&ys); PSmoveto((size.width-xs)/2.0,size.height/4.0-fs*2.0-10.0); PSshow(s); for (y=Tick0[0],x=Tick00[0]; x<1; y+=Tick1[0],x+=Tick01[0]) { sprintf(s,[[tickpos cellAt:2 :0] stringValue],y); PSstringwidth(s,&xs,&ys); if (ypm<0) PSmoveto((x+1.0)*size.width/2.0-xs/2.0-1.0,size.height/4.0-fs-6.0); else PSmoveto(size.width*(1.0-x)/2.0-xs/2.0-1.0,size.height/4.0-fs-6.0); PSshow(s); } PSstroke(); strcpy(s,[[axisTitle cellAt:1 :0] stringValue]); PSstringwidth(s,&xs,&ys); PSmoveto((size.width-xs)/2.0,size.height/2.0-fs*2.0-10.0); PSshow(s); for (y=Tick0[1],x=Tick00[1]; x<1; y+=Tick1[1],x+=Tick01[1]) { sprintf(s,[[tickpos cellAt:2 :1] stringValue],y); PSstringwidth(s,&xs,&ys); if (xpm>0) PSmoveto((x+1.0)*size.width/2.0-xs/2.0-1.0,size.height/2.0-fs-6.0); else PSmoveto(size.width*(1.0-x)/2.0-xs/2.0-1.0,size.height/2.0-fs-6.0); PSshow(s); } PSstroke(); PSgsave(); strcpy(s,[[axisTitle cellAt:2 :0] stringValue]); PSstringwidth(s,&xs,&ys); PStranslate(size.width/2.0,size.height*3.0/4.0); if (r%2==1) PSrotate(180.0); PSmoveto(-xs/2.0,0.0); PSshow(s); PSstroke(); PSgrestore(); PSgsave(); PSrotate(90.0); PStranslate(size.height/2.0,-size.width); for (y=Tick0[2],x=Tick00[2]; x<1; y+=Tick1[2],x+=Tick01[2]) { sprintf(s,[[tickpos cellAt:2 :2] stringValue],y); PSstringwidth(s,&xs,&ys); if (r%2==1) PSmoveto(size.height/2.0-xs-2.0,(x+1.0)*(size.width)/2.0-8.0); else PSmoveto(8.0,(x+1.0)*(size.width)/2.0-8.0); PSshow(s); } PSstroke(); PSgrestore(); [image unlockFocus]; stream=NXOpenMemory(NULL,0,NX_WRITEONLY); [image writeTIFF:stream]; sprintf(s,"%s/plot3dxyz.tiff",home); NXSaveToFile(stream,s); NXClose(stream); [image free]; sprintf(s,"%s/plot3d.rib",home); out=fopen(s,"w"); fprintf(out,"MakeTexture \"%s/plot3dxyz.tiff\" \"%s/plot3dxyz.tx\" \"clamp\" \"black\" \"box\" 1 1\n",home,home); fclose(out); sprintf(s,"/usr/prman/prman %s/plot3d.rib",home); system(s); [window setTitle:"3D"]; } if (Omode==0||Omode==OVER_csurf) return self; [window setTitle:"Generating Surface Map"]; /* make map of contour/density plot */ [controller dumpContour]; sprintf(s,"%s/plot3d.rib",home); out=fopen(s,"w"); fprintf(out,"MakeTexture \"%s/plot3d.tiff\" \"%s/plot3d.tx\" \"black\" \"black\" \"gaussian\" 1.8 1.8\n",home,home); fclose(out); sprintf(s,"/usr/prman/prman %s/plot3d.rib",home); system(s); [window setTitle:"3D"]; return self; } - dumpRib:sender { static id savePanel=nil; NXStream *ts; char buf[MAXPATHLEN+1]; if (!savePanel) { savePanel=[SavePanel new]; [savePanel setRequiredFileType:"rib"]; } Rmode+=4; [shape setData:pref :Rmode :Rflags]; if([savePanel runModal]){ [self makeSMap:self]; ts=NXOpenMemory(NULL, 0, NX_WRITEONLY); strcpy(buf, [savePanel filename]); strrchr(buf,'.')[0]='\0'; NXPrintf(ts, "Display \"%s.tiff\" \"file\" \"rgba\"\n", buf); [self copyRIBCode:ts]; NXSaveToFile(ts, [savePanel filename]); NXCloseMemory(ts,NX_FREEBUFFER); } Rmode-=4; [shape setData:pref :Rmode :Rflags]; return self; } -PRTiff:sender { static id savePanel=nil; if (!savePanel) { savePanel=[SavePanel new]; [savePanel setRequiredFileType:"tiff"]; } if([savePanel runModal]) [self renderTIFF:[savePanel filename]]; return self; } - renderTIFF:(char *)fsp { NXStream *ts; char buf[MAXPATHLEN+1]; char home[60]; sprintf(home,"/tmp/%s",getenv("USER")); if (getenv("USER")==NULL) strcpy(home,"/tmp"); Rmode+=4; [shape setData:pref :Rmode :Rflags]; [self makeSMap:self]; [window setTitle:"Rendering TIFF"]; ts=NXOpenMemory(NULL, 0, NX_WRITEONLY); NXPrintf(ts, "Display \"%s\" \"file\" \"rgba\"\n", fsp); [self copyRIBCode:ts]; sprintf(buf,"%s/plot3dp.rib",home); NXSaveToFile(ts, buf); NXCloseMemory(ts,NX_FREEBUFFER); [shape setData:pref :Rmode :Rflags]; Rmode-=4; sprintf(buf,"/usr/prman/prman %s/plot3dp.rib",home); system(buf); [window setTitle:"3D"]; return self; } - setAmbLight:sender { [ambLight setIntensity:ambient=[sender floatValue]]; [self display]; return self; } - setLight:sender { [aLight setIntensity:[sender floatValue]]; [self display]; return self; } -setLightX:sender { RtPoint from; lchi= -[sender floatValue]; from[0]= LRAD*sin(lchi)*cos(ltheta); from[2]= LRAD*cos(lchi)*cos(ltheta); from[1]= LRAD*sin(ltheta); [aLight setFrom:from]; [self display]; return self; } -setLightY:sender { RtPoint from; ltheta=[sender floatValue]; from[0]= LRAD*sin(lchi)*cos(ltheta); from[2]= LRAD*cos(lchi)*cos(ltheta); from[1]= LRAD*sin(ltheta); [aLight setFrom:from]; [self display]; return self; } - setMode:sender { int i; Rmode=i=[sender selectedRow]; switch(i) { case 0: [self setSurfaceTypeForAll:N3D_PointCloud chooseHider:YES]; [window setDepthLimit:NX_TwoBitGrayDepth]; break; case 1: [self setSurfaceTypeForAll:N3D_WireFrame chooseHider:YES]; [window setDepthLimit:NX_TwoBitGrayDepth]; break; case 2: [self setSurfaceTypeForAll:N3D_FacetedSolids chooseHider:YES]; break; case 3: [self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES]; break; } [shape setData:pref :Rmode :Rflags]; [self display]; return self; } -setOverlay:sender { Omode=0; if ([[sender cellAt:0 :0] intValue]) Omode+=OVER_surf; if ([[sender cellAt:1 :0] intValue]) Omode+=OVER_csurf; if ([[sender cellAt:2 :0] intValue]) Omode+=OVER_base; [shape setOver:Omode]; return self; } -printPSCode:sender { [self makeSMap:self]; Rmode+=4; [shape setData:pref :Rmode :Rflags]; [super printPSCode:sender]; Rmode-=4; [shape setData:pref :Rmode :Rflags]; return self; } -setFlags:sender { Rflags=0; if ([[flagSel findCellWithTag:0] intValue]) Rflags+=RF_axis; if ([[flagSel findCellWithTag:1] intValue]) Rflags+=RF_backs; if ([[flagSel findCellWithTag:2] intValue]) Rflags+=RF_floor; if ([[flagSel findCellWithTag:3] intValue]) Rflags+=RF_ticks; if ([[flagSel findCellWithTag:4] intValue]) Rflags+=RF_planes; if ([[flagSel findCellWithTag:5] intValue]) Rflags+=RF_labels; [shape setData:pref :Rmode :Rflags]; [self display]; return self; } -setFlagColor:sender { int i; i=[sender tag]; NXConvertColorToRGB([sender color], &flagcol[i][0],&flagcol[i][1],&flagcol[i][2]); [shape setFlagColors:flagcol]; [self display]; return self; } -size320:sender { [[self window] sizeWindow:325 :204]; return self; } -setEye:sender { RtPoint fromP = {0,0,6.0},toP={0.0,0.0,0.0}; RtMatrix mx = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1.0 }; fromP[2]=[sender floatValue]; [self setEyeAt:fromP toward:toP roll:0.0]; mx[0][0]=mx[1][1]=mx[2][2]=3.0/fromP[2]; [self setPreTransformMatrix:mx]; [self display]; return self; } -setAsp:sender { aspect=[sender floatValue]; [shape setAng:theta :chi :phi :aspect :ambient]; [self display]; return self; } -setProj:sender { if ([sender intValue]) { [self setProjection:N3D_Perspective]; Rflags|=RF_persp; [self setUsePreTransformMatrix:NO]; } else { [self setProjection:N3D_Orthographic]; Rflags&=(~RF_persp); [self setUsePreTransformMatrix:YES]; } [self display]; return self; } -(float)getTheta { return(theta); } -(float)getChi { return(chi); } -aspect11:sender { [aspectS setFloatValue:1.0]; aspect=1.0; [shape setAng:theta :chi :phi :aspect :ambient]; [self display]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.