home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Graphics / Plotting / NXplot3d.3.2 / Source / Plot3DView.m < prev    next >
Encoding:
Text File  |  1994-09-26  |  24.0 KB  |  1,035 lines

  1. /* Plot3DView.m   Copyright 1992 Steve Ludtke */
  2. /* This view allows the display of 3d functions with real time rotation */
  3.  
  4. #import "Plot3DView.h"
  5. #import "PlotShape.h"
  6. #import "PControl.h"
  7. #import <appkit/appkit.h>
  8. #import <3Dkit/3Dkit.h>
  9. #import <dpsclient/event.h>
  10. #import <dpsclient/psops.h>
  11. #import <stdio.h>
  12. #import <math.h>
  13. #include <libc.h>
  14. #import "Expression.h"
  15. #import "DensView.h"
  16.  
  17. #define LRAD 10.0
  18.  
  19. extern id NXApp;
  20.  
  21. float rnd0(float x) { if (x<0) return(ceil(x)); else return floor(x); }
  22.  
  23. @implementation Plot3DView
  24. -initFrame:(NXRect *)myrect
  25. {
  26. int i,j,ddl;
  27. RtPoint fromP = {0,0,6.0}, toP = {0,0,0};
  28. RtPoint lFromP = {5.0,10.0,5.0},lToP = {0,0,0};
  29. RtMatrix mx = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1.0 };
  30. id aShader;
  31. char home[60];
  32.  
  33. [super initFrame:(NXRect *)myrect];
  34.  
  35. [self setBackgroundColor:NX_COLORWHITE];  
  36. [self setDrawBackgroundColor:YES];
  37.  
  38. [self setEyeAt:fromP toward:toP roll:0.0];
  39.  
  40. mx[0][0]=mx[1][1]=mx[2][2]=3.0/fromP[2];
  41. [self setPreTransformMatrix:mx];
  42.   
  43.   aShader=[[N3DShader alloc] init];
  44.   [(N3DShader *)aShader setShader:"matte"];
  45.  
  46.   shape=[[PlotShape alloc] init];
  47.   [(N3DShape *) shape  setShader:aShader];
  48.   [shape scale:-1.0 :1.0 :1.0];
  49.   [[self setWorldShape:shape] free];
  50.  
  51.   ambLight=[[N3DLight alloc] init];
  52.   [ambLight makeAmbientWithIntensity:0.2];
  53.   [self addLight:ambLight];
  54.   ambient=0.2;
  55.  
  56. ltheta=.785;
  57. lchi=-.785;
  58. aLight=[[N3DLight alloc] init];
  59. lFromP[0]= LRAD*sin(lchi)*cos(ltheta);
  60. lFromP[2]= LRAD*cos(lchi)*cos(ltheta);
  61. lFromP[1]= LRAD*sin(ltheta);
  62. [aLight makeDistantFrom:lFromP to:lToP intensity:0.8];
  63. [self addLight:aLight];
  64.  
  65.   Rmode=3;
  66.  
  67. ddl=[Window defaultDepthLimit];
  68. if (ddl==NX_TwoBitGrayDepth||ddl==NX_EightBitGrayDepth) ddl=0;
  69. else ddl=1;
  70.  
  71.  
  72. /* initialize preferences */
  73. for (i=0; i<MAXSETS; i++) {
  74.     pref[i].ndata=0; 
  75.     pref[i].sym= -1;
  76.     pref[i].flag= F_EQN;
  77.     pref[i].alpha=1.0;
  78.  
  79.     if (ddl) {
  80.         pref[i].mapcol[0][0]=0.0;
  81.         pref[i].mapcol[0][1]=0.0;
  82.         pref[i].mapcol[0][2]=0.8;
  83.  
  84.         pref[i].mapcol[1][0]=0;
  85.         pref[i].mapcol[1][1]=0.733;
  86.         pref[i].mapcol[1][2]=0.8;
  87.  
  88.         pref[i].mapcol[2][0]=0.0;
  89.         pref[i].mapcol[2][1]=0.8;
  90.         pref[i].mapcol[2][2]=0.0;
  91.  
  92.         pref[i].mapcol[3][0]=0.6;
  93.         pref[i].mapcol[3][1]=0.333;
  94.         pref[i].mapcol[3][2]=0.067;
  95.  
  96.         pref[i].mapcol[4][0]=.867;
  97.         pref[i].mapcol[4][1]=.867;
  98.         pref[i].mapcol[4][2]=.867;
  99.     }
  100.     else {
  101.         for (j=0; j<5; j++) {
  102.             pref[i].mapcol[j][0]=pref[i].mapcol[j][1]=pref[i].mapcol[j][2]= 
  103.                 .5+(float)j/10.0;
  104.         }
  105.     }
  106.  
  107.     for (j=0; j<5; j++) pref[i].mapsel[j]=1;
  108.     pref[i].mapmode=1;
  109.  
  110.     pref[i].fileData=pref[i].Sdata=pref[i].demData=NULL;
  111.     pref[i].expr=[[Expression alloc] init];
  112.     [pref[i].expr parse:"0"];
  113.     pref[i].nx=pref[i].ny=10;
  114. }
  115. /* initial function to display */
  116. pref[0].sym=5;
  117. pref[0].nx=pref[0].ny=40;
  118. [pref[0].expr parse:"sin(sqrt(abs(x*y)))/sqrt(x^2+y^2)"];
  119. pref[0].flag=F_EQN;
  120.  
  121. /* start spinning, all angles in radians */
  122. chi=.2;
  123. theta=.433;
  124. /*dchi=0.025;*/
  125. dchi=0.0;
  126. initflag=1;
  127. Rflags=RF_axis+RF_persp;
  128. Omode=0;
  129. aspect=1.0;
  130. [shape setOver:Omode];
  131.  
  132. if (ddl) {
  133.     flagcol[0][0]=flagcol[4][0]=0.0;
  134.     flagcol[0][1]=flagcol[4][1]=0.0;
  135.     flagcol[0][2]=flagcol[4][2]=1.0;
  136.     flagcol[1][0]=flagcol[2][0]=1.0;
  137.     flagcol[1][1]=flagcol[2][1]=1.0;
  138.     flagcol[1][2]=flagcol[2][2]=1.0;
  139.     flagcol[3][0]=0.0;
  140.     flagcol[3][1]=1.0;
  141.     flagcol[3][2]=0.0;
  142. }
  143. else {
  144.     flagcol[0][0]=flagcol[4][0]=0.5;
  145.     flagcol[0][1]=flagcol[4][1]=0.5;
  146.     flagcol[0][2]=flagcol[4][2]=0.5;
  147.     flagcol[1][0]=flagcol[2][0]=1.0;
  148.     flagcol[1][1]=flagcol[2][1]=1.0;
  149.     flagcol[1][2]=flagcol[2][2]=1.0;
  150.     flagcol[3][0]=0.0;
  151.     flagcol[3][1]=0.0;
  152.     flagcol[3][2]=0.0;
  153. }
  154. [shape setFlagColors:flagcol];
  155.  
  156. [[[NXApp printInfo] setVertCentered:YES] setOrientation:NX_PORTRAIT andAdjust:YES];
  157. [[NXApp printInfo] setMarginLeft:0.0 right:0.0 top:0.0 bottom:0.0];
  158. [[NXApp printInfo] setHorizPagination:NX_FITPAGINATION];
  159. [[NXApp printInfo] setVertPagination:NX_FITPAGINATION];
  160.  
  161. timer=(DPSTimedEntry)DPSAddTimedEntry(TIMESTEP,itstime,self,NX_RUNMODALTHRESHOLD);
  162. [self zoom:self];
  163.  
  164. if (getenv("USER")!=NULL) {
  165.     sprintf(home,"/tmp/%s",getenv("USER"));
  166.      mkdir(home,0777);
  167. }
  168.  
  169. return self;
  170. }
  171.  
  172. /* fix the scaling after being resized */
  173. -superviewSizeChanged:(const NXSize *)oldsize
  174. {
  175. [super superviewSizeChanged:oldsize];
  176. [self zoom:self];
  177. return self;
  178. }
  179.  
  180. -free
  181. {
  182. DPSRemoveTimedEntry(timer);
  183. [super free];
  184. return self;
  185. }
  186.  
  187. -drawPS:(NXRect *)myrect :(int)rectCount
  188. {
  189. char s[80],t[20];
  190. int i,n,xyz[61];
  191. float x,y,xpm,ypm,pv[61];
  192. RtPoint pnt[61];
  193.  
  194. if (bounds.size.width<150) return self;
  195. /* display alt and az in upper right corner */
  196. PSsetgray(0.0);
  197. PSselectfont("Helvetica",10.0);
  198. sprintf(s,"Alt:%6.2f  Az:%6.2f",theta*57.295787,chi*57.295787);
  199. PSmoveto(bounds.size.width-100.0,bounds.size.height-15.0);
  200. PSshow(s);
  201. PSstroke();
  202.  
  203. if (Rflags&RF_labels && Rmode<4) {
  204.     if (chi>(M_PI/2.0)&&chi<(M_PI*1.5)) ypm=1.1;
  205.     else ypm=-1.1;
  206.     if (chi<M_PI) xpm=1.1;
  207.     else xpm=-1.1;
  208.  
  209.     for (n=0,y=Tick0[0],x=Tick00[0]; x<1; y+=Tick1[0],x+=Tick01[0],n++) { 
  210.         if (n>59) n=59;
  211.         pnt[n][0]=x; 
  212.         pnt[n][1]=ypm;
  213.         pnt[n][2]=-1.1; 
  214.         pv[n]=y;
  215.         xyz[n]=0;
  216.     }
  217.     for (y=Tick0[1],x=Tick00[1]; x<1; y+=Tick1[1],x+=Tick01[1],n++) { 
  218.         if (n>59) n=59;
  219.         pnt[n][1]=x; 
  220.         pnt[n][0]=xpm;
  221.         pnt[n][2]=-1.1; 
  222.         pv[n]=y;
  223.         xyz[n]=1;
  224.     }
  225.     for (y=Tick0[2],x=Tick00[2]; x<1; y+=Tick1[2],x+=Tick01[2],n++) { 
  226.         if (n>59) n=59;
  227.         pv[n]=y;
  228.         pnt[n][2]=x; 
  229.         if ((chi>M_PI/4.0&&chi<M_PI*.75)||(chi>M_PI*1.25&&chi<M_PI*1.75))
  230.             { pnt[n][1]=ypm; pnt[n][0]=-xpm; }
  231.         else { pnt[n][1]=-ypm; pnt[n][0]=xpm; }
  232.         xyz[n]=2;
  233.     }
  234.     pnt[n][0]=xpm/1.18; pnt[n][1]=ypm/1.18; pnt[n][2]=-1.0;
  235.  
  236.     [shape convertObjectPoints:pnt count:n+1 toCamera:self];
  237.     x=pnt[n][0];
  238.     for (i=0; i<n; i++) {
  239.         if (i==0|| xyz[i]!=xyz[i-1]) 
  240.             strcpy(t,[[tickpos cellAt:2 :xyz[i]] stringValue]);
  241.         sprintf(s,t,pv[i]);
  242.         if (pnt[i][0]<x) PSmoveto(pnt[i][0]-20.0,pnt[i][1]-5.0);
  243.         else PSmoveto(pnt[i][0],pnt[i][1]-5.0);
  244.         PSshow(s);
  245.     }
  246.     PSstroke();
  247. }
  248.  
  249. return self;
  250. }    
  251.  
  252. /* recalculates and redisplays data */
  253. -zoom:sender
  254. {
  255. float x0,x1,xs,y0,y1,ys,xf,yf,zf;
  256. float z0,z1,x,y,z,zz,dz0,dz1,T,A,B,C,D;
  257. int i,j=0,k,cm,nc,color[5],xi,yi;
  258. id tmp;
  259.  
  260. T=[[varT cellAt:0 :0] floatValue];
  261. A=[[varT cellAt:1 :0] floatValue];
  262. B=[[varT cellAt:2 :0] floatValue];
  263. C=[[varT cellAt:3 :0] floatValue];
  264. D=[[varT cellAt:4 :0] floatValue];
  265.  
  266. /* calculate minima, maxima and step sizes */
  267. x0=minX;
  268. x1=maxX;
  269. y0=minY;
  270. y1=maxY;
  271.  
  272. xf=(x1-x0)/2.0;
  273. yf=(y1-y0)/2.0;
  274.  
  275. /* make sure there's enough space in the data array */
  276. for (i=0; i<NFN; i++) {
  277.     if ((pref[i].sym==-1&&(i!=1||pref[0].mapmode!=3)) || (pref[i].fileData!=NULL)) continue;
  278.     if (pref[i].ndata!=(pref[i].nx*pref[i].ny)) {
  279.         if (pref[i].ndata!=0) { free(pref[i].data); free(pref[i].color); }
  280.         pref[i].data=malloc(sizeof(Point)*(pref[i].nx*pref[i].ny+2));
  281.         pref[i].color=malloc(sizeof(RtColor)*(pref[i].nx*pref[i].ny+2));
  282.         pref[i].ndata=pref[i].nx*pref[i].ny;
  283.     }
  284. }
  285. z0=MAXFLOAT;
  286. z1= -MAXFLOAT;
  287.  
  288. /* calculate (function mode) or clip (file mode) the data */
  289. /* also finds min/max Z */
  290. for (i=NFN-1; i>=0; i--) {
  291.     if (pref[i].sym==-1&&(i!=1||pref[0].mapmode!=3)) continue;
  292.     tmp=pref[i].expr;
  293.     [tmp setVar:"t" value:T];
  294.     [tmp setVar:"a" value:A];
  295.     [tmp setVar:"b" value:B];
  296.     [tmp setVar:"c" value:C];
  297.     [tmp setVar:"d" value:D];
  298.  
  299.     switch (pref[i].flag) {
  300.     /* DEM mode */
  301.     case F_DEM:
  302.         xs=(maxX-x0)/(float)(pref[i].nx-1);
  303.         ys=(maxY-y0)/(float)(pref[i].ny-1);    
  304.         x1=maxX+xs/2.0;
  305.         y1=maxY+ys/2.0;
  306.         j=0;
  307.         for (y=y0; y<y1; y+=ys) {
  308.             for (x=x0; x<x1; x+=xs) {
  309.                 pref[i].data[j].x=(x-x0)/xf-1.0;
  310.                 pref[i].data[j].y=(y-y0)/yf-1.0;
  311.                 xi=floor((x-pref[i].demx[0])/pref[i].demx[2]+.5);
  312.                 yi=floor((y-pref[i].demy[0])/pref[i].demy[2]+.5);
  313.                 if (xi<0||yi<0||xi>pref[i].demnx-1||yi>pref[i].demny-1)
  314.                     zz=pref[i].data[j].z=0;
  315.                 else zz=pref[i].data[j].z=pref[i].demData[xi*pref[i].demny+yi];
  316.                     
  317.                 [tmp setVar:"x" value:x];
  318.                 [tmp setVar:"y" value:y];
  319.                 [tmp setVar:"z" value:zz];
  320.                 zz=pref[i].data[j].z=[tmp resultValue];
  321.                 if (zz!=zz || zz<-MAXFLOAT || zz>MAXFLOAT) 
  322.                     zz=pref[i].data[j].z=0;
  323.  
  324.                 if (zz>z1) z1=zz;
  325.                 if (zz<z0) z0=zz;
  326.                 j++;
  327.             }
  328.         }
  329.     break;
  330.  
  331.     /* FILE MODE */
  332.     case F_DATA:
  333.     case F_SDATA:
  334.         k=0;
  335.         for (j=0; j<pref[i].nfdata; j++) {
  336.             if (pref[i].fileData[j].x>x1||pref[i].fileData[j].x<x0||
  337.                 pref[i].fileData[j].y>y1||pref[i].fileData[j].y<y0) continue;
  338.             pref[i].data[k].x=(pref[i].fileData[j].x-x0)/xf-1.0;
  339.             [tmp setVar:"x" value:pref[i].data[k].x];
  340.             pref[i].data[k].y=(pref[i].fileData[j].y-y0)/yf-1.0;
  341.             [tmp setVar:"y" value:pref[i].data[k].y];
  342.             [tmp setVar:"z" value:pref[i].fileData[j].z];
  343.             pref[i].data[k].z=[tmp resultValue];
  344.  
  345.             if (pref[i].data[k].z>z1) z1=pref[i].data[k].z;
  346.             if (pref[i].data[k].z<z0) z0=pref[i].data[k].z;
  347.             k++;
  348.         }
  349.         pref[i].ndata=k;
  350.  
  351.         if ((pref[i].flag&3)==F_SDATA) ;
  352.         else if (pref[i].data[0].y!=pref[i].data[1].y) {
  353.             pref[i].nx=pref[i].ny=(int)floor(sqrt((float)k));
  354.         }
  355.         else {
  356.             for (j=1; j<k; j++) if (pref[i].data[j-1].y!=pref[i].data[j].y) break;
  357.             pref[i].nx=j;
  358.             pref[i].ny=k/j;
  359.         }
  360.     break;
  361.     /* FUNCTION MODE */
  362.     case F_EQN:
  363.         xs=(maxX-x0)/(float)(pref[i].nx-1);
  364.         ys=(maxY-y0)/(float)(pref[i].ny-1);    
  365.         x1=maxX+xs/2.0;
  366.         y1=maxY+ys/2.0;
  367.         j=0;
  368.         for (y=y0; y<y1; y+=ys) {
  369.             for (x=x0; x<x1; x+=xs) {
  370.                 pref[i].data[j].x=(x-x0)/xf-1.0;
  371.                 pref[i].data[j].y=(y-y0)/yf-1.0;
  372.                 [tmp setVar:"x" value:x];
  373.                 [tmp setVar:"y" value:y];
  374.                 zz=pref[i].data[j].z=[tmp resultValue];
  375.                 if (zz!=zz || zz<-MAXFLOAT || zz>MAXFLOAT) 
  376.                     zz=pref[i].data[j].z=0;
  377.                 if (zz>z1) z1=zz;
  378.                 if (zz<z0) z0=zz;
  379.                 j++;
  380.             }
  381.         }
  382.     break;
  383.     }
  384. }
  385. if (z0==MAXFLOAT) return self;
  386.  
  387. /* BOTH MODES */
  388. if (z1<=z0) { z1=z0+.001; z0-=.001; }
  389. /* allow the controller to override min/max Z */
  390. [controller minmaxZ:&z0 :&z1];
  391.  
  392. /* tick spacing calculations */
  393. if ([autotick intValue]) {
  394.     [self tickCalc:5.0 :x0 :x1 :&Tick0[0] :&Tick1[0]];
  395.     [[tickpos cellAt:0 :0] setFloatValue:Tick1[0]];
  396.     [[tickpos cellAt:1 :0] setFloatValue:Tick0[0]];
  397.     [self tickCalc:5.0 :y0 :y1 :&Tick0[1] :&Tick1[1]];
  398.     [[tickpos cellAt:0 :1] setFloatValue:Tick1[1]];
  399.     [[tickpos cellAt:1 :1] setFloatValue:Tick0[1]];
  400.     [self tickCalc:5.0 :z0 :z1 :&Tick0[2] :&Tick1[2]];
  401.     [[tickpos cellAt:0 :2] setFloatValue:Tick1[2]];
  402.     [[tickpos cellAt:1 :2] setFloatValue:Tick0[2]];
  403. }
  404. else {
  405.     Tick1[0]=[[tickpos cellAt:0 :0] floatValue];
  406.     Tick0[0]=[[tickpos cellAt:1 :0] floatValue];
  407.     Tick1[1]=[[tickpos cellAt:0 :1] floatValue];
  408.     Tick0[1]=[[tickpos cellAt:1 :1] floatValue];
  409.     Tick1[2]=[[tickpos cellAt:0 :2] floatValue];
  410.     Tick0[2]=[[tickpos cellAt:1 :2] floatValue];
  411. }
  412. Tick00[0]=(Tick0[0]-minX)/(maxX-minX)*2.0-1.0;
  413. Tick01[0]=Tick1[0]/(maxX-minX)*2.0;
  414. Tick00[1]=(Tick0[1]-minY)/(maxY-minY)*2.0-1.0;
  415. Tick01[1]=Tick1[1]/(maxY-minY)*2.0;
  416. Tick00[2]=(Tick0[2]-z0)/(z1-z0)*2.0-1.0;
  417. Tick01[2]=Tick1[2]/(z1-z0)*2.0;
  418. [shape setTicks:Tick00 :Tick01];
  419.  
  420. zf=(z1-z0)/2.0;
  421. /* scale and clip Z */
  422. for (i=NFN-1; i>=0; i--) {
  423.     if (pref[i].sym==-1&&(i!=1||pref[0].mapmode!=3)) continue;
  424.     
  425.     /* Spherical coordinates */
  426.     if (pref[i].sym==6) {
  427.         if (pref[i].Sdata!=NULL) free(pref[i].Sdata);
  428.         pref[i].Sdata=malloc(sizeof(Point)*pref[i].ndata);
  429.         for (k=0; k<pref[i].ndata; k++) {
  430.             x=(pref[i].data[k].x+1.0)*xf+x0;
  431.             y=(pref[i].data[k].y+1.0)*yf+y0;
  432.             if (fabs(z0)>fabs(z1)) z=pref[i].data[k].z/fabs(z0);
  433.             else z=pref[i].data[k].z/fabs(z1);
  434.             if (z>1.0) z=1.0;
  435.             if (z<-1.0) z=-1.0;
  436.             pref[i].Sdata[k].x=z*cos(y)*sin(x);
  437.             pref[i].Sdata[k].y=z*sin(y)*sin(x);
  438.             pref[i].Sdata[k].z=z*cos(x);
  439.         }
  440.     }
  441.  
  442.     /* color info */
  443.     cm=pref[i].mapmode;
  444.     if (cm==3&&(pref[i].nx!=pref[i+1].nx||pref[i].ny!=pref[i+1].ny)) cm=-1;
  445.     for (j=k=0; j<5; j++) if (pref[i].mapsel[j]) { color[k]=j; k++; }
  446.     nc=k;
  447.     if (nc<2) cm=0;
  448.  
  449.     // gradient mode, calculate gradients
  450.     if (cm==2 && pref[i].ndata==(pref[i].nx*pref[i].ny)) {
  451.         dz0=MAXFLOAT;
  452.         dz1=-MAXFLOAT;
  453.         for (j=0; j<pref[i].ny; j++) {
  454.             for (k=0; k<pref[i].nx; k++) {
  455.                 xi=pref[i].nx*j+k;
  456.                 yi=pref[i].nx;
  457.                 // df/dx
  458.                 if (k==0) x=(pref[i].data[xi+1].z-pref[i].data[xi].z)*2.0;
  459.                 else if (k==pref[i].nx-1) x=(pref[i].data[xi].z-pref[i].data[xi-1].z)*2.0;
  460.                 else x=pref[i].data[xi+1].z-pref[i].data[xi-1].z;
  461.  
  462.                 // df/dy
  463.                 if (j==0) y=(pref[i].data[xi+yi].z-pref[i].data[xi].z)*2.0;
  464.                 else if (j==pref[i].ny-1) y=(pref[i].data[xi].z-pref[i].data[xi-yi].z)*2.0;
  465.                 else y=pref[i].data[xi+yi].z-pref[i].data[xi-yi].z;
  466.  
  467.                 z=sqrt(x*x+y*y);
  468.                 if (z>dz1) dz1=z;
  469.                 if (z<dz0) dz0=z;
  470.                 pref[i].color[xi][0]=z;
  471.             }
  472.         }
  473.         dz1-=dz0;
  474.     }
  475.  
  476.     for (k=0; k<pref[i].ndata; k++) {
  477.         // clip data in z
  478.         if (pref[i].data[k].z>z1) pref[i].data[k].z=z1;
  479.         if (pref[i].data[k].z<z0) pref[i].data[k].z=z0;
  480.         z=pref[i].data[k].z=(pref[i].data[k].z-z0)/zf-1.0;
  481.  
  482.         // color mode 1 = altitude based color, 2 = grad based color, 
  483.         // 3 = color from next data set
  484.         if (cm==2) z=(pref[i].color[k][0]-dz0)/dz1;
  485.         else if (cm==3) z=(pref[i+1].data[k].z+1.0)/2.0;
  486.         else if(cm==-1) z=0.0;
  487.         else z=(z+1.0)/2.0;
  488.  
  489.         if (cm!=0) {
  490.             j=floor(z*.9999*(float)(nc-1));
  491.             z=z*(float)(nc-1)-(float)j;
  492.             pref[i].color[k][0]=z*pref[i].mapcol[color[j+1]][0]+
  493.                 (1.0-z)*pref[i].mapcol[color[j]][0];
  494.             pref[i].color[k][1]=z*pref[i].mapcol[color[j+1]][1]+
  495.                 (1.0-z)*pref[i].mapcol[color[j]][1];
  496.             pref[i].color[k][2]=z*pref[i].mapcol[color[j+1]][2]+
  497.                 (1.0-z)*pref[i].mapcol[color[j]][2];
  498.         }            
  499.     }
  500. }
  501.  
  502. /* display 3d plot */
  503. [shape setData:pref :Rmode :Rflags];
  504. [shape setAng:theta :chi :phi :aspect :ambient];
  505. [self display];
  506. /* display density plot */
  507. [controller updDen:Tick00 :Tick01];
  508. return self;
  509. }
  510.  
  511. /* obvious */
  512. -setAng:(float)alt :(float)az
  513. {
  514. theta=alt;
  515. chi=az;
  516. return self;
  517. }
  518.  
  519. -setPhi:sender
  520. {
  521. phi=[sender floatValue];
  522. [shape setAng:theta :chi :phi :aspect :ambient];
  523. [self display];
  524. return self;
  525. }
  526.  
  527. /* allows spinning and zooming with the mouse */
  528. -mouseDown:(NXEvent *)oevent 
  529. {
  530. int oldMask,loop=1;
  531. float ix=0,iy=0,ix2=0,iy2=0;
  532. NXEvent *event,evs;
  533. long tm,tm2;
  534.  
  535. evs=*oevent;
  536. oevent=&evs;
  537. [self convertPoint:&oevent->location fromView:nil];
  538. oevent->location.x=oevent->location.x/bounds.size.width*2.0-1.0;
  539. oevent->location.y=oevent->location.y/bounds.size.height*2.0-1.0;
  540. ix2=ix=oevent->location.x;
  541. iy2=iy=oevent->location.y;
  542. tm2=tm=oevent->time;
  543.  
  544. oldMask = [window addToEventMask:NX_LMOUSEDRAGGEDMASK];
  545.  
  546. while (loop) {
  547.     event = [NXApp getNextEvent:(NX_LMOUSEUPMASK | NX_LMOUSEDRAGGEDMASK)];
  548.     [self convertPoint:&event->location fromView:nil];
  549.     event->location.x=event->location.x/bounds.size.width*2.0-1.0;
  550.     event->location.y=event->location.y/bounds.size.height*2.0-1.0;
  551.  
  552.         switch (event->type) {
  553.         case NX_LMOUSEUP:
  554.                 loop = 0;
  555.                 dchi=-(event->location.x-ix2)/(float)(event->time-tm2)*15.0;
  556.                 if (fabs(dchi)<.004) dchi=0.0;
  557.                 [shape setAng:theta :chi :phi :aspect :ambient];
  558.                 [self display];
  559.             break;
  560.         case NX_LMOUSEDRAGGED:
  561.             theta-=(event->location.y-iy)*3.0;
  562.             chi-=(event->location.x-ix)*4.0;
  563.             if (theta>M_PI/2.0) theta=M_PI/2.0;
  564.             if (theta<-M_PI/2.0) theta=-M_PI/2.0;
  565.             while (chi>2.0*M_PI) chi-=2.0*M_PI;
  566.             while (chi<0.0) chi+=2.0*M_PI;
  567.             ix2=ix;
  568.             iy2=iy;
  569.             tm2=tm;
  570.             ix=event->location.x;
  571.             iy=event->location.y;
  572.             tm=event->time;
  573.             [shape setAng:theta :chi :phi :aspect :ambient];
  574.             [self display];
  575.             break;
  576.         default:
  577.             break;
  578.         }
  579. }
  580. [window setEventMask:oldMask];
  581. return self;
  582. }
  583.  
  584. /* function called by timer */
  585. void itstime(DPSTimedEntry entry,double now,id call)
  586. {
  587. [call step];
  588. return;
  589. }
  590.  
  591. /* do one time step */
  592. -step
  593. {
  594. if (initflag) { 
  595.     /* first time, do initialization stuff */
  596.     if (controller==nil) return self;
  597.     [controller startup:pref];
  598.     [self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES];
  599.     [self zoom:self];
  600.     initflag=0; 
  601. }
  602. if (dchi==0.0) return self;
  603. chi+=dchi;
  604. while (chi>2.0*M_PI) chi-=2.0*M_PI;
  605. while (chi<0.0) chi+=2.0*M_PI;
  606. [shape setAng:theta :chi :phi :aspect :ambient];
  607. [self display];
  608. return self;
  609. }
  610.  
  611. -tickCalc:(float)n :(float)x0 :(float)x1 :(float *)min :(float *)spa
  612. {
  613. float s,e;
  614.  
  615. s=(x1-x0)/n;
  616. e=floor(log10(s));
  617. if (s/pow(10.0,e)<3.0) s=floor(s/pow(10.0,e-1.0))*pow(10.0,e-1.0);
  618. else s=floor(s/pow(10.0,e))*pow(10.0,e);
  619. *min=(floor(x0/s)+1.0)*(s);
  620. *spa=s;
  621. return self;
  622. }
  623.  
  624. /* new min/max values */
  625. -zoomTo:(float)minx :(float)miny :(float)maxx :(float)maxy
  626. {
  627. minX=minx;
  628. minY=miny;
  629. maxX=maxx;
  630. maxY=maxy;
  631. return self;
  632. }
  633.  
  634. -(int)acceptsFirstMouse { return (YES); }
  635.  
  636. -setcontroller:con 
  637. {
  638. controller=con;
  639. return self;
  640. }
  641.  
  642. /* allow user to pause spinning */
  643. -togFreeze:sender
  644. {
  645. static float Tdchi;
  646.  
  647. if ([sender intValue]) {
  648.     Tdchi=dchi;
  649.     dchi=0.0;
  650.     return self;
  651. }
  652. dchi=Tdchi;
  653. return self;
  654. }
  655.  
  656. - renderSelf:(RtToken)context
  657. {
  658.  
  659. return self;
  660. }
  661.  
  662. -makeSMap:sender
  663. {
  664. FILE *out;
  665. char home[60],s[80];
  666. id image,rep;
  667. NXSize size = { 400.0,400.0 };
  668. NXStream *stream;
  669. float xs,ys,x,y,xpm,ypm,fs;
  670. int r;
  671.  
  672. sprintf(home,"/tmp/%s",getenv("USER"));
  673. if (getenv("USER")==NULL) strcpy(home,"/tmp"); 
  674.  
  675. /* write maps for axis labels */
  676. if (Rflags&RF_labels) {
  677.     [window setTitle:"Generating Axis Label Maps"];
  678.  
  679.     if (chi>(M_PI/2.0)&&chi<(M_PI*1.5)) ypm=1.0;
  680.     else ypm=-1.0;
  681.     if (chi<M_PI) xpm=1.0;
  682.     else xpm=-1.0;
  683.  
  684.     r=floor(chi/M_PI*4.0);
  685.  
  686.     image=[[NXImage alloc] initSize:&size];
  687.     [image setCacheDepthBounded:NO];
  688.     [image useCacheWithDepth:NX_TwentyFourBitRGBDepth];
  689.     rep=[image lastRepresentation];
  690.     [rep setAlpha:NO];
  691.     [rep setNumColors:3];
  692.     [image lockFocus];
  693.     PSselectfont("Helvetica-Bold",fs=[fontSize floatValue]);
  694.     PSsetrgbcolor(1.0,.95,1.0);
  695.     PSmoveto(0,0);
  696.     PSlineto(1.0,1.0);
  697.     PSstroke();
  698.  
  699.     PSsetrgbcolor(0,0,0);
  700.     strcpy(s,[[axisTitle cellAt:0 :0] stringValue]);
  701.     PSstringwidth(s,&xs,&ys);
  702.     PSmoveto((size.width-xs)/2.0,size.height/4.0-fs*2.0-10.0);
  703.     PSshow(s);
  704.     for (y=Tick0[0],x=Tick00[0]; x<1; y+=Tick1[0],x+=Tick01[0]) { 
  705.         sprintf(s,[[tickpos cellAt:2 :0] stringValue],y);
  706.         PSstringwidth(s,&xs,&ys);
  707.         if (ypm<0)
  708.             PSmoveto((x+1.0)*size.width/2.0-xs/2.0-1.0,size.height/4.0-fs-6.0);
  709.         else PSmoveto(size.width*(1.0-x)/2.0-xs/2.0-1.0,size.height/4.0-fs-6.0);
  710.         PSshow(s);
  711.     }
  712.     PSstroke();
  713.  
  714.     strcpy(s,[[axisTitle cellAt:1 :0] stringValue]);
  715.     PSstringwidth(s,&xs,&ys);
  716.     PSmoveto((size.width-xs)/2.0,size.height/2.0-fs*2.0-10.0);
  717.     PSshow(s);
  718.     for (y=Tick0[1],x=Tick00[1]; x<1; y+=Tick1[1],x+=Tick01[1]) { 
  719.         sprintf(s,[[tickpos cellAt:2 :1] stringValue],y);
  720.         PSstringwidth(s,&xs,&ys);
  721.         if (xpm>0) 
  722.             PSmoveto((x+1.0)*size.width/2.0-xs/2.0-1.0,size.height/2.0-fs-6.0);
  723.         else PSmoveto(size.width*(1.0-x)/2.0-xs/2.0-1.0,size.height/2.0-fs-6.0);
  724.         PSshow(s);
  725.     }
  726.     PSstroke();
  727.  
  728.     PSgsave();
  729.     strcpy(s,[[axisTitle cellAt:2 :0] stringValue]);
  730.     PSstringwidth(s,&xs,&ys);
  731.     PStranslate(size.width/2.0,size.height*3.0/4.0);
  732.     if (r%2==1) PSrotate(180.0);
  733.     PSmoveto(-xs/2.0,0.0);
  734.     PSshow(s);
  735.     PSstroke();
  736.     PSgrestore();
  737.     PSgsave();
  738.     PSrotate(90.0);
  739.     PStranslate(size.height/2.0,-size.width);
  740.     for (y=Tick0[2],x=Tick00[2]; x<1; y+=Tick1[2],x+=Tick01[2]) { 
  741.         sprintf(s,[[tickpos cellAt:2 :2] stringValue],y);
  742.         PSstringwidth(s,&xs,&ys);
  743.         if (r%2==1)
  744.             PSmoveto(size.height/2.0-xs-2.0,(x+1.0)*(size.width)/2.0-8.0);
  745.         else PSmoveto(8.0,(x+1.0)*(size.width)/2.0-8.0);
  746.         PSshow(s);
  747.     }
  748.     PSstroke();
  749.     PSgrestore();
  750.     [image unlockFocus];
  751.     stream=NXOpenMemory(NULL,0,NX_WRITEONLY);
  752.     [image writeTIFF:stream];
  753.     sprintf(s,"%s/plot3dxyz.tiff",home);
  754.     NXSaveToFile(stream,s);
  755.     NXClose(stream);
  756.     [image free];
  757.  
  758.     sprintf(s,"%s/plot3d.rib",home);
  759.     out=fopen(s,"w");
  760.     fprintf(out,"MakeTexture \"%s/plot3dxyz.tiff\" \"%s/plot3dxyz.tx\" \"clamp\" \"black\" \"box\" 1 1\n",home,home);
  761.     fclose(out);
  762.     sprintf(s,"/usr/prman/prman %s/plot3d.rib",home);
  763.     system(s);
  764.     [window setTitle:"3D"];
  765. }
  766.  
  767. if (Omode==0||Omode==OVER_csurf) return self;
  768. [window setTitle:"Generating Surface Map"];
  769.  
  770. /* make map of contour/density plot */
  771. [controller dumpContour];
  772. sprintf(s,"%s/plot3d.rib",home);
  773. out=fopen(s,"w");
  774. fprintf(out,"MakeTexture \"%s/plot3d.tiff\" \"%s/plot3d.tx\" \"black\" \"black\" \"gaussian\" 1.8 1.8\n",home,home);
  775. fclose(out);
  776. sprintf(s,"/usr/prman/prman %s/plot3d.rib",home);
  777. system(s);
  778. [window setTitle:"3D"];
  779. return self;
  780. }
  781.  
  782. - dumpRib:sender
  783. {
  784.   static id savePanel=nil;
  785.   NXStream *ts;
  786.   char buf[MAXPATHLEN+1];
  787.  
  788.   if (!savePanel) {
  789.     savePanel=[SavePanel new];
  790.     [savePanel setRequiredFileType:"rib"];
  791.   }
  792.  
  793.   Rmode+=4;
  794.   [shape setData:pref :Rmode :Rflags];
  795.  
  796.   if([savePanel runModal]){
  797.       [self makeSMap:self];
  798.     ts=NXOpenMemory(NULL, 0, NX_WRITEONLY);
  799.     strcpy(buf, [savePanel filename]);
  800.     strrchr(buf,'.')[0]='\0';
  801.     NXPrintf(ts, "Display \"%s.tiff\" \"file\" \"rgba\"\n", buf);
  802.     [self copyRIBCode:ts];
  803.     NXSaveToFile(ts, [savePanel filename]);
  804.     NXCloseMemory(ts,NX_FREEBUFFER);
  805.   }
  806.  
  807.   Rmode-=4;
  808.   [shape setData:pref :Rmode :Rflags];
  809. return self;
  810. }
  811.  
  812. -PRTiff:sender
  813. {
  814. static id savePanel=nil;
  815.  
  816. if (!savePanel) {
  817.     savePanel=[SavePanel new];
  818.     [savePanel setRequiredFileType:"tiff"];
  819. }
  820.  
  821. if([savePanel runModal]) [self renderTIFF:[savePanel filename]];
  822.  
  823. return self;
  824. }
  825.  
  826. - renderTIFF:(char *)fsp
  827. {
  828. NXStream *ts;
  829. char buf[MAXPATHLEN+1];
  830. char home[60];
  831.  
  832. sprintf(home,"/tmp/%s",getenv("USER"));
  833. if (getenv("USER")==NULL) strcpy(home,"/tmp"); 
  834.  
  835.  
  836. Rmode+=4;
  837. [shape setData:pref :Rmode :Rflags];
  838.  
  839. [self makeSMap:self];
  840. [window setTitle:"Rendering TIFF"];
  841. ts=NXOpenMemory(NULL, 0, NX_WRITEONLY);
  842. NXPrintf(ts, "Display \"%s\" \"file\" \"rgba\"\n", fsp);
  843. [self copyRIBCode:ts];
  844. sprintf(buf,"%s/plot3dp.rib",home);
  845. NXSaveToFile(ts, buf);
  846. NXCloseMemory(ts,NX_FREEBUFFER);
  847.  
  848.  
  849. [shape setData:pref :Rmode :Rflags];
  850. Rmode-=4;
  851.  
  852. sprintf(buf,"/usr/prman/prman %s/plot3dp.rib",home);
  853. system(buf);
  854.  
  855. [window setTitle:"3D"];
  856.  
  857. return self;
  858. }
  859.  
  860. - setAmbLight:sender
  861. {
  862. [ambLight setIntensity:ambient=[sender floatValue]];
  863. [self display];
  864. return self;
  865. }
  866.  
  867. - setLight:sender
  868. {
  869. [aLight setIntensity:[sender floatValue]];
  870. [self display];
  871. return self;
  872. }
  873.  
  874. -setLightX:sender
  875. {
  876. RtPoint from;
  877. lchi= -[sender floatValue];
  878. from[0]= LRAD*sin(lchi)*cos(ltheta);
  879. from[2]= LRAD*cos(lchi)*cos(ltheta);
  880. from[1]= LRAD*sin(ltheta);
  881. [aLight setFrom:from];
  882. [self display];
  883. return self;
  884. }
  885.  
  886. -setLightY:sender
  887. {
  888. RtPoint from;
  889. ltheta=[sender floatValue];
  890. from[0]= LRAD*sin(lchi)*cos(ltheta);
  891. from[2]= LRAD*cos(lchi)*cos(ltheta);
  892. from[1]= LRAD*sin(ltheta);
  893. [aLight setFrom:from];
  894. [self display];
  895. return self;
  896. }
  897.  
  898. - setMode:sender
  899. {
  900. int i;
  901.  
  902. Rmode=i=[sender selectedRow];
  903. switch(i) {
  904. case 0:
  905.  [self setSurfaceTypeForAll:N3D_PointCloud chooseHider:YES];
  906.  [window setDepthLimit:NX_TwoBitGrayDepth];
  907. break;
  908. case 1:
  909.  [self setSurfaceTypeForAll:N3D_WireFrame chooseHider:YES];
  910.  [window setDepthLimit:NX_TwoBitGrayDepth];
  911. break;
  912. case 2:
  913.  [self setSurfaceTypeForAll:N3D_FacetedSolids chooseHider:YES];
  914. break;
  915. case 3:
  916.  [self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES];
  917. break;
  918. }
  919. [shape setData:pref :Rmode :Rflags];
  920. [self display];
  921. return self;
  922. }
  923.  
  924. -setOverlay:sender
  925. {
  926. Omode=0;
  927. if ([[sender cellAt:0 :0] intValue]) Omode+=OVER_surf;
  928. if ([[sender cellAt:1 :0] intValue]) Omode+=OVER_csurf;
  929. if ([[sender cellAt:2 :0] intValue]) Omode+=OVER_base;
  930.  
  931. [shape setOver:Omode];
  932. return self;
  933. }
  934.  
  935. -printPSCode:sender
  936. {
  937.  
  938. [self makeSMap:self];
  939. Rmode+=4;
  940. [shape setData:pref :Rmode :Rflags];
  941. [super printPSCode:sender];
  942. Rmode-=4;
  943. [shape setData:pref :Rmode :Rflags];
  944. return self;
  945. }
  946.  
  947. -setFlags:sender
  948. {
  949. Rflags=0;
  950. if ([[flagSel findCellWithTag:0] intValue]) Rflags+=RF_axis;
  951. if ([[flagSel findCellWithTag:1] intValue]) Rflags+=RF_backs;
  952. if ([[flagSel findCellWithTag:2] intValue]) Rflags+=RF_floor;
  953. if ([[flagSel findCellWithTag:3] intValue]) Rflags+=RF_ticks;
  954. if ([[flagSel findCellWithTag:4] intValue]) Rflags+=RF_planes;
  955. if ([[flagSel findCellWithTag:5] intValue]) Rflags+=RF_labels;
  956. [shape setData:pref :Rmode :Rflags];
  957. [self display];
  958. return self;
  959. }
  960.  
  961. -setFlagColor:sender
  962. {
  963. int i;
  964.  
  965. i=[sender tag];
  966. NXConvertColorToRGB([sender color], 
  967.     &flagcol[i][0],&flagcol[i][1],&flagcol[i][2]);
  968. [shape setFlagColors:flagcol];
  969. [self display];
  970. return self;
  971. }
  972.  
  973. -size320:sender
  974. {
  975. [[self window] sizeWindow:325 :204];
  976. return self;
  977. }
  978.  
  979. -setEye:sender
  980. {
  981. RtPoint fromP = {0,0,6.0},toP={0.0,0.0,0.0};
  982. RtMatrix mx = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1.0 };
  983.  
  984. fromP[2]=[sender floatValue];
  985. [self setEyeAt:fromP toward:toP roll:0.0];
  986. mx[0][0]=mx[1][1]=mx[2][2]=3.0/fromP[2];
  987. [self setPreTransformMatrix:mx];
  988. [self display];
  989. return self;
  990. }
  991.  
  992. -setAsp:sender
  993. {
  994. aspect=[sender floatValue];
  995. [shape setAng:theta :chi :phi :aspect :ambient];
  996. [self display];
  997. return self;
  998. }
  999.  
  1000. -setProj:sender
  1001. {
  1002. if ([sender intValue]) {
  1003.     [self setProjection:N3D_Perspective];
  1004.     Rflags|=RF_persp;
  1005.     [self setUsePreTransformMatrix:NO];
  1006. }
  1007. else {
  1008.     [self setProjection:N3D_Orthographic];
  1009.     Rflags&=(~RF_persp);
  1010.     [self setUsePreTransformMatrix:YES];
  1011. }
  1012. [self display];
  1013. return self;
  1014. }
  1015.  
  1016. -(float)getTheta
  1017. {
  1018. return(theta);
  1019. }
  1020.  
  1021. -(float)getChi
  1022. {
  1023. return(chi);
  1024. }
  1025.  
  1026. -aspect11:sender
  1027. {
  1028. [aspectS setFloatValue:1.0];
  1029. aspect=1.0;
  1030. [shape setAng:theta :chi :phi :aspect :ambient];
  1031. [self display];
  1032. return self;
  1033. }
  1034. @end
  1035.