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

  1. #import "PControl.h"
  2. #import "Plot3DView.h"
  3. #import "PlotShape.h"
  4. #import <appkit/appkit.h>
  5. #import <dpsclient/event.h>
  6. #import <dpsclient/psops.h>
  7. #import <appkit/color.h>
  8. #import <stdio.h>
  9. #import <math.h>
  10. #import <ctype.h>
  11. #include <libc.h>
  12. #import "Expression.h"
  13. #import "DensView.h"
  14.  
  15. int comp(float *x,float *y);
  16.  
  17. @implementation PControl
  18. -init
  19. {
  20. [super init];
  21. return self;
  22. }
  23.  
  24. /* Called once by the Plot3DView to do initialization and pass pref pointer */
  25. -startup:(SetPref *)Pref
  26. {
  27.     pref=Pref;
  28. /* display initial preferences settings */
  29.     curPref=0;
  30.     bpath=(char *)[[NXBundle mainBundle] directory];
  31.     [symsel selectCellWithTag:pref[0].sym+1];
  32.     equation=[equation docView];
  33.     [equation setText:[pref[0].expr text]];
  34. /* make sure plot agrees with displayed min/max values */
  35.     [gridx setIntValue:pref[curPref].nx];
  36.     [gridy setIntValue:pref[curPref].ny];
  37.     [d3View zoomTo:[minX floatValue] :[minY floatValue] :[maxX floatValue] :[maxY floatValue]];
  38.     [d3View setDelegate:self];
  39. /*[self readFile:self];*/
  40.  
  41.     I_lim=[I_lim contentView];
  42.     I_dis=[I_dis contentView];
  43.     I_pho=[I_pho contentView];
  44. return self;
  45. }
  46.  
  47. /* display preferences for a data set */
  48. -disPref:sender
  49. {
  50. int i;
  51. curPref=[[sender selectedCell] tag];
  52. [symsel selectCellWithTag:pref[curPref].sym+1];
  53. [color1 setColor:NXConvertRGBToColor(pref[curPref].mapcol[0][0], 
  54.     pref[curPref].mapcol[0][1],pref[curPref].mapcol[0][2])];
  55. [color2 setColor:NXConvertRGBToColor(pref[curPref].mapcol[1][0], 
  56.     pref[curPref].mapcol[1][1],pref[curPref].mapcol[1][2])];
  57. [color3 setColor:NXConvertRGBToColor(pref[curPref].mapcol[2][0], 
  58.     pref[curPref].mapcol[2][1],pref[curPref].mapcol[2][2])];
  59. [color4 setColor:NXConvertRGBToColor(pref[curPref].mapcol[3][0], 
  60.     pref[curPref].mapcol[3][1],pref[curPref].mapcol[3][2])];
  61. [color5 setColor:NXConvertRGBToColor(pref[curPref].mapcol[4][0], 
  62.     pref[curPref].mapcol[4][1],pref[curPref].mapcol[4][2])];
  63. [alpha setFloatValue:pref[curPref].alpha];
  64.  
  65. [colortype selectCellWithTag:pref[curPref].mapmode];
  66. if (curPref!=0) [[colortype cellAt:1 :1] setEnabled:NO];
  67. else [[colortype cellAt:1 :1] setEnabled:YES];
  68.  
  69. for (i=0; i<5; i++) 
  70.     [[colorsel cellAt:0 :i] setIntValue:pref[curPref].mapsel[i]];
  71.  
  72. if ((pref[curPref].flag&7)==F_EQN) [ffSel selectCellWithTag:0];
  73. else if ((pref[curPref].flag&7)==F_DATA) [ffSel selectCellWithTag:1];
  74. else if ((pref[curPref].flag&7)==F_SDATA) [ffSel selectCellWithTag:2];
  75. else if ((pref[curPref].flag&7)==F_DEM) [ffSel selectCellWithTag:3];
  76.  
  77. [equation setText:[pref[curPref].expr text]];
  78. [gridx setIntValue:pref[curPref].nx];
  79. [gridy setIntValue:pref[curPref].ny];
  80. [d3View zoom:self];
  81. return self;
  82. }
  83.  
  84. /* put preferences from screen into SetPref for curPref set */
  85. -stoPref:sender
  86. {
  87. char *tmp;
  88. int i,j,k;
  89. pref[curPref].sym=[[symsel selectedCell] tag]-1;
  90. pref[curPref].nx=[gridx intValue];
  91. if (pref[curPref].nx>MAXGRID||pref[curPref].nx<4) 
  92.     [gridx setIntValue:pref[curPref].nx=10];
  93. pref[curPref].ny=[gridy intValue];
  94. if (pref[curPref].ny>MAXGRID||pref[curPref].ny<4) 
  95.     [gridy setIntValue:pref[curPref].ny=10];
  96. tmp=malloc([equation textLength]+50);
  97. [equation getSubstring:tmp start:0 length:[equation textLength]+1];
  98. /* Fix equation for parsing */
  99. k=strlen(tmp);
  100. for (i=0; i<k; i++) {
  101.     if (tmp[i]=='[') tmp[i]='(';
  102.     if (tmp[i]==']') tmp[i]=')';
  103.     if (isupper(tmp[i])) tmp[i]=tolower(tmp[i]);
  104.     if ((tmp[i]=='+'||tmp[i]=='-')&&(isdigit(tmp[i+1])||tmp[i+1]=='.')) {
  105.         for (j=k; j>i; j--) tmp[j+1]=tmp[j];
  106.         tmp[i+1]=' ';
  107.         k++;
  108.     }
  109. }
  110.  
  111. /* if the equation doesn't parse, set it to 0 */
  112. if (strlen(tmp)==0 ||
  113.      [pref[curPref].expr parse:tmp]==0) {
  114.     [self error:"Cannot parse equation!"];
  115.     [pref[curPref].expr parse:"0"];
  116.     }
  117.  
  118. /* Colors */
  119. NXConvertColorToRGB([color1 color],&pref[curPref].mapcol[0][0], 
  120.     &pref[curPref].mapcol[0][1],&pref[curPref].mapcol[0][2]);
  121. NXConvertColorToRGB([color2 color],&pref[curPref].mapcol[1][0], 
  122.     &pref[curPref].mapcol[1][1],&pref[curPref].mapcol[1][2]);
  123. NXConvertColorToRGB([color3 color],&pref[curPref].mapcol[2][0], 
  124.     &pref[curPref].mapcol[2][1],&pref[curPref].mapcol[2][2]);
  125. NXConvertColorToRGB([color4 color],&pref[curPref].mapcol[3][0], 
  126.     &pref[curPref].mapcol[3][1],&pref[curPref].mapcol[3][2]);
  127. NXConvertColorToRGB([color5 color],&pref[curPref].mapcol[4][0], 
  128.     &pref[curPref].mapcol[4][1],&pref[curPref].mapcol[4][2]);
  129. pref[curPref].alpha=[alpha floatValue];
  130.  
  131. for (i=0; i<5; i++) pref[curPref].mapsel[i]=[[colorsel cellAt:0 :i] intValue];
  132.     
  133. pref[curPref].mapmode=[[colortype selectedCell] tag];
  134.  
  135. if ([[ffSel selectedCell] tag]==0) pref[curPref].flag=F_EQN;
  136. else if ([[ffSel selectedCell] tag]==1) pref[curPref].flag=F_DATA;
  137. else if ([[ffSel selectedCell] tag]==2) pref[curPref].flag=F_SDATA;
  138. else if ([[ffSel selectedCell] tag]==3) pref[curPref].flag=F_DEM;
  139.  
  140. /* if spherical plot, set proper limits */
  141. if (pref[curPref].sym==6) {
  142.     [minX setFloatValue:0];
  143.     [maxX setFloatValue:M_PI];
  144.     [minY setFloatValue:0];
  145.     [maxY setFloatValue:M_PI*2.0];
  146.     [self setMinMax:self];
  147. }
  148. [d3View zoom:self];
  149. return self;
  150. }
  151.  
  152. /* Read 3d data from a file and put it into the current data set */
  153. /* does NOT wait for an "OK" press, like other prefs */
  154. -readFile:sender
  155. {
  156. id panel;
  157. int i,j,k,cc=0,nx,ny;
  158. char s[201],sc[20];
  159. FILE *in;
  160. float x0,y0,z0,z1,f,x[MAXGRID+1],y[MAXGRID+1];
  161. Point *p;
  162.  
  163. if (pref[curPref].fileData!=NULL) { 
  164.     free(pref[curPref].fileData); 
  165.     pref[curPref].fileData=NULL; 
  166. }
  167.  
  168. if (sender!=self) {
  169.     /* get a filespec from the user */
  170.     panel=[[OpenPanel new] allowMultipleFiles:NO];
  171.     if (![panel runModalForTypes:NULL]) {
  172.         [ffSel selectCellWithTag:0];
  173.         pref[curPref].flag=F_EQN;
  174.         [equation setText:"0"];
  175.         [pref[curPref].expr parse:"0"];
  176.         return self;
  177.     }
  178.     
  179.     /* if we can't open the file, go back to equation mode */
  180.     in=fopen([panel filename],"r");
  181. }
  182. else {
  183.     [ffSel selectCellWithTag:1];
  184.     sprintf(s,"%s/title.3d",bpath);
  185.     in=fopen(s,"r");
  186. }
  187.  
  188. if (fgets(s,200,in)==NULL) {
  189.     [ffSel selectCellWithTag:0];
  190.     pref[curPref].flag=F_EQN;
  191.     [equation setText:"0"];
  192.     [pref[curPref].expr parse:"0"];
  193.     [self error:"Can't open file."];
  194.     return self;
  195. }
  196.  
  197. /* ignore leading # lines */
  198. while (s[0]=='#') { fgets(s,80,in); cc++; }
  199.  
  200. /* accept either "x,y,z\n" or "x y z\n" files */
  201. strcpy(sc," %f , %f , %f");
  202. if (sscanf(s,sc,&x[0],&y[0],&z0)!=3) {
  203.     strcpy(sc," %f %f %f");
  204.     if (sscanf(s,sc,&x[0],&y[0],&z0)!=3) {
  205.         [ffSel selectCellWithTag:0];
  206.         pref[curPref].flag=F_EQN;
  207.         [equation setText:"0"];
  208.         [pref[curPref].expr parse:"0"];
  209.         [self error:"File not in 'x y z' or 'x,y,z' format."];
  210.         return self;
  211.     }
  212. }
  213. z1=z0;
  214.  
  215. /* count the number of points in the file */
  216. nx=ny=1;
  217. while (fscanf(in,sc,&x[nx],&y[ny],&f)==3) {
  218.     if (f<z0) z0=f;
  219.     for (i=0; i<nx; i++) if (x[nx]==x[i]) break;
  220.     if (i==nx) nx++;
  221.     for (i=0; i<ny; i++) if (y[ny]==y[i]) break;
  222.     if (i==ny) ny++;
  223.     if (nx==MAXGRID+1||ny==MAXGRID+1) {
  224.         [ffSel selectCellWithTag:0];
  225.         pref[curPref].flag=F_EQN;
  226.         [equation setText:"0"];
  227.         [pref[curPref].expr parse:"0"];
  228.         [self error:"More than MAXGRID points in x or y."];
  229.         fclose(in);
  230.          return self;
  231.     }
  232. }
  233. qsort(x,nx,sizeof(float),comp);    
  234. qsort(y,ny,sizeof(float),comp);    
  235. rewind(in);
  236.  
  237. /* 2nd pass, allocate memory,initialize and read data into array */
  238. p=pref[curPref].fileData=malloc(sizeof(Point)*nx*ny);
  239. pref[curPref].nfdata=nx*ny;
  240. for (i=0; i<nx; i++) {
  241.     for (j=0; j<ny; j++) {
  242.         p[i+nx*j].x=x[i];
  243.         p[i+nx*j].y=y[j];
  244.         p[i+nx*j].z=z0;
  245.     }
  246. }
  247.  
  248. for (i=0; i<cc; i++) fgets(s,240,in);
  249. while (fscanf(in,sc,&x0,&y0,&f)==3) {
  250.     for (j=0; j<nx; j++) if (x0==x[j]) break;
  251.     for (k=0; k<ny; k++) if (y0==y[k]) break;
  252.     if (k==ny||j==nx) [self error:"Unusual error, notify author."];
  253.     p[j+nx*k].z=f;
  254. }
  255. if (pref[curPref].data!=NULL) free(pref[curPref].data);
  256. pref[curPref].data=malloc(sizeof(Point)*pref[curPref].nfdata);
  257. pref[curPref].color=malloc(sizeof(RtColor)*pref[curPref].nfdata);
  258. [minX setFloatValue:x[0]];
  259. [minY setFloatValue:y[0]];
  260. [maxX setFloatValue:x[nx-1]];
  261. [maxY setFloatValue:y[ny-1]];
  262.  
  263. /* equation is now used to modify data Z values, set initial formula for */
  264. /* z(x,y,z)=z. ie - for log plots you would enter "log(z)" */
  265. [equation setText:"z"];
  266. [pref[curPref].expr parse:"z"];
  267. pref[curPref].flag=F_DATA;
  268.  
  269. /* update the display */
  270. [self setMinMax:self];
  271. [d3View zoom:self];
  272. return self;
  273. }
  274.  
  275. /* Read processed DEM data from a file and put it into the DEM data set */
  276. /* does NOT wait for an "OK" press, like other prefs */
  277. -readDEM:sender
  278. {
  279. id panel;
  280. int nx,ny;
  281. FILE *in;
  282.  
  283. if (pref[curPref].fileData!=NULL) { 
  284.     free(pref[curPref].fileData); 
  285.     pref[curPref].fileData=NULL; 
  286. }
  287. if (pref[curPref].demData!=NULL) { 
  288.     free(pref[curPref].demData); 
  289.     pref[curPref].demData=NULL; 
  290. }
  291.  
  292. /* get a filespec from the user */
  293. panel=[[OpenPanel new] allowMultipleFiles:NO];
  294.  
  295. /* if we can't open the file, go back to equation mode */
  296. if (![panel runModalForTypes:NULL]) {
  297.     [ffSel selectCellWithTag:0];
  298.     pref[curPref].flag=F_EQN;
  299.     [equation setText:"0"];
  300.     [pref[curPref].expr parse:"0"];
  301.     return self;
  302. }    
  303. in=fopen([panel filename],"r");
  304.  
  305. /* read the processed DEM header */
  306. fread(&pref[curPref].demnx,sizeof(int),1,in);
  307. fread(&pref[curPref].demny,sizeof(int),1,in);
  308. fread(pref[curPref].demx,sizeof(float),2,in);
  309. fread(pref[curPref].demy,sizeof(float),2,in);
  310. if (fread(pref[curPref].demz,sizeof(float),2,in)!=2|| 
  311.         pref[curPref].demnx<10||pref[curPref].demnx>5000||pref[curPref].demny<10||pref[curPref].demny>5000) {
  312.     [ffSel selectCellWithTag:0];
  313.     pref[curPref].flag=F_EQN;
  314.     [equation setText:"0"];
  315.     [pref[curPref].expr parse:"0"];
  316.     [self error:"Can't open file."];
  317.     return self;
  318. }
  319. pref[curPref].demx[2]=(pref[curPref].demx[1]-pref[curPref].demx[0])/(float)(pref[curPref].demnx-1);
  320. pref[curPref].demy[2]=(pref[curPref].demy[1]-pref[curPref].demy[0])/(float)(pref[curPref].demny-1);
  321.  
  322. /* allocate a big chunk of memory */
  323. nx=pref[curPref].demnx;
  324. ny=pref[curPref].demny;
  325. pref[curPref].demData=malloc(sizeof(short)*nx*ny);
  326.  
  327. /* read the data */
  328. if (fread(pref[curPref].demData,nx*sizeof(short),ny,in)!=ny) {
  329.         [ffSel selectCellWithTag:0];
  330.         pref[curPref].flag=F_EQN;
  331.         [equation setText:"0"];
  332.         [pref[curPref].expr parse:"0"];
  333.         [self error:"More than MAXGRID points in x or y."];
  334.         fclose(in);
  335.          return self;
  336. }
  337. [minX setFloatValue:pref[curPref].demx[0]];
  338. [minY setFloatValue:pref[curPref].demy[0]];
  339. [maxX setFloatValue:pref[curPref].demx[1]];
  340. [maxY setFloatValue:pref[curPref].demy[1]];
  341.  
  342. /* equation is now used to modify data Z values, set initial formula for */
  343. /* z(x,y,z)=z. ie - for log plots you would enter "log(z)" */
  344. [equation setText:"z"];
  345. [pref[curPref].expr parse:"z"];
  346. pref[curPref].flag=F_DEM;
  347.  
  348. /* update the display */
  349. [self setMinMax:self];
  350. [d3View zoom:self];
  351. return self;
  352. }
  353.  
  354.  
  355. /* Read 3d scatter data from a file and put it into the current data set */
  356. /* does NOT wait for an "OK" press, like other prefs */
  357. -readSFile:sender
  358. {
  359. id panel;
  360. int i,j,k,cc=0,n;
  361. char s[201],sc[20];
  362. FILE *in;
  363. float x0,y0,x1,y1,z0,z1,f;
  364. Point *p;
  365.  
  366. if (pref[curPref].fileData!=NULL) { free(pref[curPref].fileData); pref[curPref].
  367. fileData=NULL; }
  368.  
  369. if (sender!=self) {
  370.     /* get a filespec from the user */
  371.     panel=[[OpenPanel new] allowMultipleFiles:NO];
  372.     if (![panel runModalForTypes:NULL]) {
  373.         [ffSel selectCellWithTag:0];
  374.         pref[curPref].flag=F_EQN;
  375.         [equation setText:"0"];
  376.         [pref[curPref].expr parse:"0"];
  377.         return self;
  378.     }
  379.     
  380.     /* if we can't open the file, go back to equation mode */
  381.     in=fopen([panel filename],"r");
  382. }
  383. else {
  384.     [ffSel selectCellWithTag:1];
  385.     sprintf(s,"%s/title.3d",bpath);
  386.     in=fopen(s,"r");
  387. }
  388.  
  389. if (fgets(s,200,in)==NULL) {
  390.     [ffSel selectCellWithTag:0];
  391.     pref[curPref].flag=F_EQN;
  392.     [equation setText:"0"];
  393.     [pref[curPref].expr parse:"0"];
  394.     [self error:"Can't open file."];
  395.     return self;
  396. }
  397.  
  398. /* ignore leading # lines */
  399. while (s[0]=='#') { fgets(s,80,in); cc++; }
  400.  
  401. /* accept either "x,y,z\n" or "x y z\n" files */
  402. strcpy(sc," %f , %f , %f");
  403. if (sscanf(s,sc,&x0,&y0,&z0)!=3) {
  404.     strcpy(sc," %f %f %f");
  405.     if (sscanf(s,sc,&x0,&y0,&z0)!=3) {
  406.         [ffSel selectCellWithTag:0];
  407.         pref[curPref].flag=F_EQN;
  408.         [equation setText:"0"];
  409.         [pref[curPref].expr parse:"0"];
  410.         [self error:"File not in 'x y z' or 'x,y,z' format."];
  411.         return self;
  412.     }
  413.     x1=x0;
  414.     y1=y0;
  415. }
  416.  
  417. /* count the number of points in the file */
  418. n=1;
  419. while (fscanf(in,sc,&f,&f,&f)==3) n++;
  420.  
  421. rewind(in);
  422.  
  423. /* 2nd pass, allocate memory,initialize and read data into array */
  424. p=pref[curPref].fileData=malloc(sizeof(Point)*n);
  425. pref[curPref].nfdata=n;
  426.  
  427. for (i=0; i<cc; i++) fgets(s,240,in);
  428. n=0;
  429. while (fscanf(in,sc,&p[n].x,&p[n].y,&p[n].z)==3) {
  430.     if (p[n].x<x0) x0=p[n].x;
  431.     if (p[n].x>x1) x1=p[n].x;
  432.     if (p[n].y<y0) y0=p[n].y;
  433.     if (p[n].y>y1) y1=p[n].y;
  434.     n++;
  435. }
  436.  
  437. if (pref[curPref].data!=NULL) free(pref[curPref].data);
  438. pref[curPref].data=malloc(sizeof(Point)*pref[curPref].nfdata);
  439. pref[curPref].color=malloc(sizeof(RtColor)*pref[curPref].nfdata);
  440. [minX setFloatValue:x0];
  441. [minY setFloatValue:y0];
  442. [maxX setFloatValue:x1];
  443. [maxY setFloatValue:y1];
  444.  
  445. /* equation is now used to modify data Z values, set initial formula for */
  446. /* z(x,y,z)=z. ie - for log plots you would enter "log(z)" */
  447. [equation setText:"z"];
  448. [pref[curPref].expr parse:"z"];
  449. pref[curPref].flag=F_SDATA;
  450.  
  451. /* update the display */
  452. [self setMinMax:self];
  453. [d3View zoom:self];
  454. return self;
  455. }
  456.  
  457.  
  458. /* return a data set to equation mode, free memory used by the file */
  459. -clearFile:sender
  460. {
  461. if (pref[curPref].fileData!=NULL) { free(pref[curPref].fileData); pref[curPref].fileData=NULL; }
  462. pref[curPref].nfdata=0;
  463.  
  464. [equation setText:"0"];
  465. [pref[curPref].expr parse:"0"];
  466. [d3View zoom:self];
  467. return(self);
  468. }
  469.  
  470. /* minz and maxz can be modified before returning, but currently aren't */
  471. -minmaxZ:(float *)minz :(float *)maxz
  472. {
  473. [dminZ setFloatValue:*minz];
  474. [dmaxZ setFloatValue:*maxz];
  475. if ([dzSwitch intValue]) {
  476.     [minZ setFloatValue:*minz];
  477.     [maxZ setFloatValue:*maxz];
  478. }
  479. *minz=[minZ floatValue];
  480. *maxz=[maxZ floatValue];
  481. return self;
  482. }
  483.  
  484. /* display new min/max values (does not inform the views of the change) */
  485. -setMM:(float)minx :(float)maxx :(float)miny :(float)maxy
  486. {
  487. [minX setFloatValue:minx];
  488. [minY setFloatValue:miny];
  489. [maxX setFloatValue:maxx];
  490. [maxY setFloatValue:maxy];
  491. return self;
  492. }
  493.  
  494. /* Tell the Plot3DView and (indirectly) the DensView about new max/min vals */
  495. -setMinMax:sender
  496. {
  497. int aspect;
  498.  
  499. aspect=[demAsp intValue];
  500. if (aspect) 
  501.     [maxY setFloatValue:[maxX floatValue]-[minX floatValue]+[minY floatValue]];
  502. [d3View zoomTo:[minX floatValue] :[minY floatValue] :[maxX floatValue] :[maxY floatValue]];
  503. if (aspect)
  504.     [maxZ setFloatValue:[minZ floatValue]+([maxX floatValue]-[minX floatValue])*83000.0];
  505. [d3View zoom:self];
  506. return self;
  507. }
  508.  
  509. -stoMM:sender
  510. {
  511. sMM[0]=[minX floatValue];
  512. sMM[1]=[minY floatValue];
  513. sMM[2]=[maxX floatValue];
  514. sMM[3]=[maxY floatValue];
  515. return self;
  516. }
  517.  
  518. -rclMM:sender
  519. {
  520. [minX setFloatValue:sMM[0]];
  521. [minY setFloatValue:sMM[1]];
  522. [maxX setFloatValue:sMM[2]];
  523. [maxY setFloatValue:sMM[3]];
  524.  
  525. [self setMinMax:sender];
  526. return self;
  527. }
  528. /* zoom in by a fixed amount */
  529. -zoomIn:sender
  530. {
  531. float x,y,x1,y1;
  532. x1=[maxX floatValue];
  533. x=[minX floatValue];
  534. y1=[maxY floatValue];
  535. y=[minY floatValue];
  536.  
  537. [maxX setFloatValue:x1-(x1-x)/4.0];
  538. [minX setFloatValue:x+(x1-x)/4.0];
  539. [maxY setFloatValue:y1-(y1-y)/4.0];
  540. [minY setFloatValue:y+(y1-y)/4.0];
  541.  
  542. [self setMinMax:self];
  543. [d3View zoom:self];
  544. return self;
  545. }
  546.  
  547. /* zoom out by a fixed amount */
  548. -zoomOut:sender
  549. {
  550. float x,y,x1,y1;
  551. x1=[maxX floatValue];
  552. x=[minX floatValue];
  553. y1=[maxY floatValue];
  554. y=[minY floatValue];
  555.  
  556. [maxX setFloatValue:x1+(x1-x)/4.0];
  557. [minX setFloatValue:x-(x1-x)/4.0];
  558. [maxY setFloatValue:y1+(y1-y)/4.0];
  559. [minY setFloatValue:y-(y1-y)/4.0];
  560.  
  561. [self setMinMax:self];
  562. [d3View zoom:self];
  563. return self;
  564. }
  565.  
  566. /* sent by DensView, min/max are from 0.0 to 1.0, not real units */
  567. -zoomTo:(float)minx :(float)miny :(float)maxx :(float)maxy
  568. {
  569. float x0,x1,y0,y1;
  570.  
  571. x0=[minX floatValue];
  572. x1=[maxX floatValue];
  573. y0=[minY floatValue];
  574. y1=[maxY floatValue];
  575.  
  576. [minX setFloatValue:x0+(x1-x0)*minx];
  577. [minY setFloatValue:y0+(y1-y0)*miny];
  578. [maxX setFloatValue:x0+(x1-x0)*maxx];
  579. [maxY setFloatValue:y0+(y1-y0)*maxy];
  580. [self setMinMax:self];
  581. [d3View zoom:self];
  582. return self;
  583. }
  584.  
  585. -dumpContour
  586. {
  587. [dView saveTiff:self];
  588. return self;
  589. }
  590.  
  591. /* update the density plot */
  592. -updDen:(RtPoint)TickO :(RtPoint)TickS
  593. {
  594. static float *densData=NULL;
  595. static int ndd=0;
  596. int k,i,nx,ny;
  597. NXRect rec,rec2,tick;
  598. float x0=0,x1=0,y0=0,y1=0,zlim[4] = { -1.0,1.0,0,0};
  599. char s[80];
  600. float lev0,lev1;
  601.  
  602. zlim[2]=[minZ floatValue];
  603. zlim[3]=[maxZ floatValue];
  604.  
  605. if ([autoCont intValue]) {
  606.     i=[[levels cellAt:2 :0] intValue];
  607.     lev1=2.0/(float)i;
  608.     lev0= -1.0+lev1/2.0;
  609.     [[levels cellAt:0 :0] setFloatValue:(lev0+1.0)/2.0* 
  610.         (zlim[3]-zlim[2])+zlim[2]];
  611.     [[levels cellAt:1 :0] setFloatValue:lev1/2.0* 
  612.         (zlim[3]-zlim[2])];
  613. }
  614. else {
  615.     lev0=[[levels cellAt:0 :0] floatValue];
  616.     lev1=[[levels cellAt:1 :0] floatValue];
  617.     lev0=(lev0-zlim[2])/(zlim[3]-zlim[2])*2.0-1.0;
  618.     lev1=lev1/(zlim[3]-zlim[2])*2.0;
  619. }
  620.  
  621. if (lev1<=0) lev1=.2;
  622. [[d3View worldShape] setContour:lev0/2.0+.5 :lev1/2.0];
  623.  
  624. tick.origin.x=(TickO[0]+1.0)/2.0;
  625. tick.origin.y=(TickO[1]+1.0)/2.0;
  626. tick.size.width=TickS[0]/2.0;
  627. tick.size.height=TickS[1]/2.0;
  628.  
  629. rec2.origin.x=[minX floatValue];
  630. rec2.origin.y=[minY floatValue];
  631. rec2.size.width=[maxX floatValue]-[minX floatValue];
  632. rec2.size.height=[maxY floatValue]-[minY floatValue];
  633. rec=rec2;
  634. if (pref[curPref].ndata==0||(pref[curPref].flag&3)==F_SDATA) {
  635.     [dView setData:0 :0 :NULL :zlim :tick :rec :rec2 :lev0 :lev1 :NULL];
  636.     return self;
  637. }
  638.  
  639. nx=pref[curPref].nx; 
  640. ny=pref[curPref].ny;
  641. if (ndd<(nx*ny)) {
  642.     if (densData!=NULL) free(densData);
  643.     densData=malloc(nx*ny*sizeof(float));
  644.     ndd=nx*ny;
  645. }
  646.  
  647. if (pref[curPref].fileData==NULL||nx*ny==pref[curPref].ndata) {
  648.     for (k=0; k<pref[curPref].ndata; k++) densData[k]=pref[curPref].data[k].z;
  649. }
  650. else {
  651.     sprintf(s,"Error nx*ny=%d  ndata=%d\n",nx*ny,pref[curPref].ndata);
  652.     [self error:s];
  653. /*    for (k=0; k<(nx*ny); k++) densData[k]= -.5;
  654.     for (k=0; k<pref[curPref].ndata; k++) {
  655.         i=floor((pref[curPref].data[k].x+.5)*(float)nx)+ 
  656.             floor((pref[curPref].data[k].y+.5)*(float)ny)*nx;
  657.         if (i>=0 && i<ndd) densData[i]=pref[curPref].data[k].z;
  658.     }*/
  659. }
  660.  
  661. if (pref[curPref].fileData!=NULL) {
  662.     for (i=0; i<pref[curPref].nfdata; i++) {
  663.         x0=pref[curPref].fileData[i].x;
  664.         y0=pref[curPref].fileData[i].y;
  665.         if (x0>=rec2.origin.x && y0>=rec2.origin.y) break;
  666.     }
  667.     for (i=pref[curPref].nfdata-1; i>=0; i--) {
  668.         x1=pref[curPref].fileData[i].x;
  669.         y1=pref[curPref].fileData[i].y;
  670.         if (x1<=rec2.origin.x+rec2.size.width && 
  671.             y1<=rec2.origin.y+rec2.size.height) break;
  672.     }
  673.  
  674.     rec.size.width=x1-x0;
  675.     rec.origin.x=x0;
  676.     rec.size.height=y1-y0;
  677.     rec.origin.y=y0;
  678. }
  679.  
  680. if (pref[curPref].sym!= -1) {
  681.     if (pref[curPref].mapmode!=0) [dView setData:nx :ny :densData :zlim :tick :rec :rec2 :lev0 :lev1 :pref[curPref].color];
  682.     else [dView setData:nx :ny :densData :zlim :tick :rec :rec2 :lev0 :lev1 :NULL];
  683. }
  684. else [dView setData:0 :0 :NULL :zlim :tick :rec :rec2 :lev0 :lev1 :NULL];
  685. return self;
  686. }
  687.  
  688. int comp(float *x,float *y)
  689. {
  690. if (x<y) return(-1);
  691. if (y>x) return(1);
  692. return (0);
  693. }
  694.  
  695. -newInsp:sender
  696. {
  697. int i;
  698.  
  699. i=[[sender selectedCell] tag];
  700. switch(i) {
  701. case 0: [I_BOX setContentView:I_lim];
  702.         break;
  703. case 1:    [I_BOX setContentView:I_dis];
  704.         break;
  705. case 2:    [I_BOX setContentView:I_pho];
  706.         break;
  707. }
  708. [I_BOX display];
  709. return self;
  710. }
  711.  
  712. /* variable slider changed */
  713. -setVarS:sender
  714. {
  715. int i;
  716.  
  717. for (i=0; i<5; i++) 
  718.     [[varText cellAt:i :0] setFloatValue:[[varSli cellAt:i :0] floatValue]];
  719. [d3View zoom:self];
  720. return self;
  721. }
  722.  
  723. /* variable text changed */
  724. -setVarT:sender
  725. {
  726. int i;
  727. for (i=0; i<5; i++) 
  728.     [[varSli cellAt:i :0] setFloatValue:[[varText cellAt:i :0] floatValue]];
  729. [d3View zoom:self];
  730. return self;
  731. }
  732.  
  733. /* new var min/max */
  734. -setVarMinMax:sender
  735. {
  736. int i;
  737.  
  738. for (i=0; i<5; i++)
  739.     [[[varSli cellAt:i :0] setMaxValue:[[varMax cellAt:i :0] floatValue]] setMinValue:[[varMin cellAt:i :0] floatValue]];
  740. return self;
  741. }
  742.  
  743. -saveData:sender
  744. {
  745. id pan;
  746. FILE *out;
  747. int i;
  748. float x0,x1,y0,y1,z0,z1;
  749. x0=[minX floatValue];
  750. x1=[maxX floatValue]-x0;
  751. y0=[minY floatValue];
  752. y1=[maxY floatValue]-y0;
  753. z0=[minZ floatValue];
  754. z1=[maxZ floatValue]-z0;
  755.  
  756. pan=[SavePanel new];
  757. if ([pan runModal]) {
  758.     out=fopen([pan filename],"w");
  759.     fprintf(out,"# Created by Plot3D\n");
  760.     for (i=0; i<pref[curPref].ndata; i++) 
  761.         fprintf(out,"%f\t%f\t%f\n",(pref[curPref].data[i].x/2.0+.5)*x1+x0,
  762.             (pref[curPref].data[i].y/2.0+.5)*y1+y0,
  763.             (pref[curPref].data[i].z/2.0+.5)*z1+z0);
  764.     fclose(out);
  765. }
  766. return self;
  767. }
  768.  
  769. /* Start rendering an animation */
  770. -makeAnim:sender
  771. {
  772. int afl=0,n=16,cf;
  773. static id savePanel=nil;
  774. float chi,chistp,theta,t,tstp;
  775. char animFile[100];        /* animation directory */
  776. char animName[30];            /* animation name */
  777. char fsp[MAXPATHLEN];
  778. int i,j=0;
  779.  
  780. if (!savePanel) {
  781.     savePanel=[SavePanel new];
  782.     [savePanel setRequiredFileType:"anim"];
  783. }
  784.  
  785. if(![savePanel runModal]) return self;
  786. if (strlen([savePanel filename])>78) {
  787.     [self error:"Filespec too long. Please notify author."];
  788.     return self;
  789. }
  790. strcpy(animFile, [savePanel filename]);
  791. mkdir(animFile,0777);
  792. for (i=strlen(animFile)-1; i>=0; i--) if (animFile[i]=='/') break;
  793. i++;
  794. while (i<strlen(animFile)-5) animName[j++]=animFile[i++];
  795. animName[j]=0;
  796. afl=[[animFlag cellAt:0 :0] intValue]*ANIM_spin+
  797.     [[animFlag cellAt:1 :0] intValue]*ANIM_t;
  798. if (afl==0) {
  799.     [self error:"Animation doesn't do anything!"];
  800.     return self;
  801. }
  802. n=[animFrames intValue];
  803. chistp=M_PI*2.0/(float)n;
  804. chi=[d3View getChi];
  805. theta=[d3View getTheta];
  806. t=[[varMin cellAt:0 :0] floatValue];
  807. tstp=([[varMax cellAt:0 :0] floatValue]-t)/(float)(n-1);
  808.  
  809. for (cf=0; cf<n; cf++) {
  810.     [[varText cellAt:0 :0] setFloatValue:t];
  811.     [[varSli cellAt:0 :0] setFloatValue:t];
  812.     [d3View setAng:theta :chi];
  813.     [d3View zoom:self];
  814.     sprintf(fsp,"%s/%s.%d.tiff",animFile,animName,cf+1);
  815.     [self message:"Rendering animation. This will take a while ..." :fsp];
  816.     [d3View renderTIFF:fsp];
  817.     if (afl&ANIM_t) t+=tstp;
  818.     if (afl&ANIM_spin) chi+=chistp;
  819. }
  820. [self message:"Rendering complete !!!" :"(use Movie.app or a similar program to view)"];
  821. return self;
  822. }
  823.  
  824. -error:(char *)msg
  825. {
  826. [errTitle setStringValue:"ERROR"];
  827. [errMsg setStringValue:msg];
  828. [errPan makeKeyAndOrderFront:self];
  829. return self;
  830. }
  831.  
  832. -message:(char *)s1 :(char *)s2
  833. {
  834. [errTitle setStringValue:s1];
  835. [errMsg setStringValue:s2];
  836. [errPan makeKeyAndOrderFront:self];
  837. return self;
  838. }
  839.  
  840. @end
  841.