This is D3View.m in view mode; [Download] [Up]
/* 3DView.m Copyright 1992 Steve Ludtke */ /* This view allows the display of molecules with real time rotation */ /* The quick mode is handled in drawPS:: */ #import "Mtypes.h" #import "D3View.h" #import "MolObj.h" #import "MolShape.h" #import "SelectView.h" #import <appkit/appkit.h> #import <dpsclient/event.h> #import <dpsclient/psops.h> #import <stdio.h> #import <math.h> #include <libc.h> #include <sys/file.h> void PSsethel(); /* makes Helvetica current font */ int comp(struct DSORT *a,struct DSORT *b); #define LRAD 10.0 extern id NXApp; @implementation D3View -initFrame:(NXRect *)myrect { char s[120]; RtPoint lFromP = {5.0,10.0,5.0},lToP = {0,0,0}; int i; id aShader; fromP[0]=fromP[1]=0; fromP[2]=60.0; toP[0]=toP[1]=toP[2]=0.0; bpath=(char *)[[NXBundle mainBundle] directory]; [super initFrame:(NXRect *)myrect]; /* set up light sources, etc... */ [self setBackgroundColor:NX_COLORWHITE]; [self setDrawBackgroundColor:YES]; fromP[2]=60.0; [self setEyeAt:fromP toward:toP roll:0.0]; aShader=[[N3DShader alloc] init]; [(N3DShader *)aShader setShader:"matte"]; shape=[[MolShape alloc] init]; [(N3DShape *) shape setShader:aShader]; [shape scale:-1.0 :1.0 :1.0]; [shape setBSSR:2.0 :0.1]; [[self setWorldShape:shape] free]; ambLight=[[N3DLight alloc] init]; [ambLight makeAmbientWithIntensity:0.4]; [self addLight:ambLight]; 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:1.0]; [self addLight:aLight]; Mmode=0; Rmode=4; /* start in "quick" mode */ useColor=0; /* start spinning, all angles in radians */ chi=phi=0; theta=0; /*dchi=0.025;*/ dchi=dtheta=0.0; initflag=1; Rflags=0; /* printer setup */ [[[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]; busy=0; /* images for spinning icon */ for (i=0; i<8; i++) { sprintf(s,"%s/icon%d.tiff",bpath,i); AIMGS[i]=[[NXImage alloc] initFromFile:s]; } timer=(void *) DPSAddTimedEntry(TIMESTEP,(void *)itstime,self,NX_RUNMODALTHRESHOLD); minshape=0; return self; } - appDidInit: sender { AICV=[[NXApp appIcon] contentView]; AIMG=[NXImage findImageNamed: "NXAppTile"]; Ior1.x=Ior1.y=0.0; Ior2.x=Ior2.y=8.0; animicon=0; [self setSurfaceTypeForAll:N3D_WireFrame chooseHider:YES]; [self zoom:self]; initflag=0; return self; } -setData:(Molecule *)Mol :(int)Nmol :(struct ELINFO *)Elinfo { mol=Mol; nmol=Nmol; elinfo=Elinfo; [self zoom:self]; return self; } /* fix the scaling after being resized */ -superviewSizeChanged:(const NXSize *)oldsize { [super superviewSizeChanged:oldsize]; [[winSize cellAt:0 :0] setFloatValue:frame.size.width]; [[winSize cellAt:0 :1] setFloatValue:frame.size.height]; [self zoom:self]; return self; } -free { DPSRemoveTimedEntry(timer); [super free]; return self; } -(BOOL)canPrintRIB { if (Rmode==4) return NO; return YES; } -createQuick:(int)n { FILE *out; char s[180]; out=fopen("/tmp/el.rib","w"); fprintf(out, "Display \"%s/Library/MolViewer/el%02d.tiff\" \"file\" \"rgba\"\n", (char *)getenv("HOME"),n); fprintf(out,"##RenderMan RIB-Structure 1.0\n##System NeXT Release 3\nFrameBegin 1\n#\nFormat 100 100 1.000000\n\nScreenWindow -1 1 -1 1\n"); fprintf(out,"Projection \"perspective\" \"fov\" [ 40 ]\nTransform [ -1 0 0 0\n 0 1 0 0 0 0 -1 0 0 0 3.269231 1 ]\nWorldBegin\nTransformBegin\nConcatTransform [ 1 0 0 0\n 0 1 0 0 0 0 1 0 0 0 0 1 ]\n"); fprintf(out,"LightSource \"Light0x15178c\" \"distantlight\" \"intensity\" [ .95 ] \"lightcolor\" [ 1 1 1 ] \"from\" [ -4.999999 7.068252 5.003982 ] \"to\" [ 0 0 0 ]\n"); fprintf(out,"TransformEnd\nTransformBegin\nConcatTransform [ 1 0 0 0\n 0 1 0 0 0 0 1 0 0 0 0 1 ]\nLightSource \"Light0x14dbdc\" \"ambientlight\" \"intensity\" [ .3 ] \"lightcolor\" [ 1 1 1 ]\n"); fprintf(out,"TransformEnd\nShadingRate 1\nAttributeBegin\nColor [ 1 1 1 ]\nDeclare \"Ka\" \"float\"\nDeclare \"Kd\" \"float\"\n#\nSurface \"matte\" \"Ka\" 1 \"Kd\" 1\nShadingInterpolation \"smooth\"\n"); fprintf(out,"GeometricRepresentation \"primitive\"\nTransformBegin\nConcatTransform [ -1 0 0 0\n 0 1 0 0 0 0 1 0 0 0 0 1 ]\n"); fprintf(out,"Surface \"plastic\"\nColor [ %f %f %f ]\nSphere %f %f %f 360\n",elinfo[n].color[0],elinfo[n].color[1],elinfo[n].color[2],elinfo[n].arad,-elinfo[n].arad,elinfo[n].arad); fprintf(out,"TransformEnd\nAttributeEnd\nWorldEnd\nFrameEnd\n"); fclose(out); sprintf(s,"Rendering %c%c. Please be patient.", elinfo[n].name[0],elinfo[n].name[1]); [controller error:s :NO]; system("/usr/prman/prman /tmp/el.rib"); unlink("/tmp/el.rib"); return self; } /* This is called after QRM has finished rendering. In quick mode */ /* nothing is rendered. It's all done here */ -drawPS:(NXRect *)rects :(int)rectCount { char s[80]; float mx[9]; int i,j,k,t; float tx,ty,tz,sca,xc,yc,xw,yw,mp[3]; static struct DSORT *dsort=NULL; static int dsmax=1000000; NXPoint point; NXSize size; if (mol==NULL) return self; PSsethel(); if (Rmode==4) { /* ok, since the QRman interface has a bug, here we'll do some quick stuff */ /* with roughly the same effect (this is also much faster for space-filling) */ if (mol[0].numa>dsmax) { free(dsort); dsort=NULL; } /* dsort structure holds drawing information. For space filling mode it */ /* is actually sorted. In stick mode it just holds the transformed */ /* molecule coordinates */ if (dsort==NULL) { dsort=malloc(sizeof(struct DSORT)*(mol[0].numa+1)); dsmax=mol[0].numa; } PSsetlinewidth(0.0); PSsetgray(1.0); NXRectFill(&bounds); PSsetgray(NX_BLACK); /* a transform that almost matches the QRM transformation */ chi*=-1.0; phi*=-1.0; theta*=-1.0; mx[0]=cos(chi)*cos(phi)-cos(theta)*sin(phi)*sin(chi); mx[1]=cos(chi)*sin(phi)+cos(theta)*cos(phi)*sin(chi); mx[2]=sin(chi)*sin(theta); mx[3]= -sin(chi)*cos(phi)-cos(theta)*sin(phi)*cos(chi); mx[4]= -sin(chi)*sin(phi)+cos(theta)*cos(phi)*cos(chi); mx[5]=cos(chi)*sin(theta); mx[6]=sin(theta)*sin(phi); mx[7]= -sin(theta)*cos(phi); mx[8]=cos(theta); chi*=-1.0; phi*=-1.0; theta*=-1.0; /* scaling info */ xw=bounds.size.width; yw=bounds.size.height; xc=bounds.size.width/2.0; yc=bounds.size.height/2.0; sca=bounds.size.height*1.8; /* transform the coordinates -> DSORT struct */ for (i=0; i<mol[0].numa; i++) { tx=mol[0].coord[i][0]; ty= -mol[0].coord[i][2]; tz=mol[0].coord[i][1]; dsort[i].c[1]=tx*mx[3]+ty*mx[4]+tz*mx[5]+fromP[2]; if (dsort[i].c[1]<=0.0) continue; dsort[i].c[0]=(tx*mx[0]+ty*mx[1]+tz*mx[2]+fromP[0])*sca/dsort[i].c[1]+xc; dsort[i].c[2]=(tx*mx[6]+ty*mx[7]+tz*mx[8]-fromP[1])*sca/dsort[i].c[1]+yc; dsort[i].anum=mol[0].atom[i].anum; dsort[i].atom=i; dsort[i].sel=mol[0].atom[i].sel; dsort[i].lab=mol[0].atom[i].lab; if (Rflags==0&&(dsort[i].c[0]<0 ||dsort[i].c[0]>xw||dsort[i].c[2]<0|| dsort[i].c[2]>yw)) dsort[i].c[0]=-1.0; } /* stick mode. Use user paths for speed */ if (Rflags==0) { pathc=0; for (i=0; i<mol[0].numlb; i++) { j=mol[0].lb[i].n1; k=mol[0].lb[i].n2; if (dsort[j].c[0]==-1.0||dsort[k].c[0]==-1.0) continue; path[pathc*2]=dsort[j].c[0]; path[pathc*2+1]=dsort[j].c[2]; path[pathc*2+2]=dsort[k].c[0]; path[pathc*2+3]=dsort[k].c[2]; ops[pathc]=dps_moveto; ops[pathc+1]=dps_lineto; pathc+=2; if (pathc>=1400) { DPSDoUserPath(path, pathc * 2, dps_float, ops, pathc, &bounds, dps_ustroke); pathc=0; } } if (pathc!=0) DPSDoUserPath(path, pathc * 2, dps_float, ops, pathc, &bounds, dps_ustroke); sca*=1.05; sca/=fromP[2]; /* circle selected atoms */ for (i=0; i<mol[0].numa; i++) { if (dsort[i].lab) { PSsetgray(0.0); PSmoveto(dsort[i].c[0]+2.0,dsort[i].c[2]-3.0); sprintf(s,"%c%c%1d",elinfo[dsort[i].anum].name[0], elinfo[dsort[i].anum].name[1],dsort[i].atom); PSshow(s); PSstroke(); } if (dsort[i].sel) { PSsetgray(0.0); PSmoveto(dsort[i].c[0]+sca/3.0,dsort[i].c[2]); PSarc(dsort[i].c[0],dsort[i].c[2],sca/3.0,0.0,360.0); PSstroke(); } } } /* ball & stick is stick mode with colors & double bonds */ else if (Rflags==1) { for (i=0; i<mol[0].numlb; i++) { j=mol[0].lb[i].n1; k=mol[0].lb[i].n2; t=mol[0].lb[i].type; if (dsort[j].c[0]==-1.0||dsort[k].c[0]==-1.0) continue; mp[0]=(dsort[j].c[0]+dsort[k].c[0])/2.0; mp[2]=(dsort[j].c[2]+dsort[k].c[2])/2.0; if (t=='D') PSsetlinewidth(4.0); else PSsetlinewidth(1.0); PSsetrgbcolor(elinfo[dsort[j].anum].color[0], elinfo[dsort[j].anum].color[1],elinfo[dsort[j].anum].color[2]); PSmoveto(dsort[j].c[0],dsort[j].c[2]); PSlineto(mp[0],mp[2]); PSstroke(); PSsetrgbcolor(elinfo[dsort[k].anum].color[0], elinfo[dsort[k].anum].color[1],elinfo[dsort[k].anum].color[2]); PSmoveto(dsort[k].c[0],dsort[k].c[2]); PSlineto(mp[0],mp[2]); PSstroke(); } sca*=1.05; sca/=fromP[2]; /* circle selected atoms */ for (i=0; i<mol[0].numa; i++) { if (dsort[i].lab) { PSsetgray(0.0); PSmoveto(dsort[i].c[0]+2.0,dsort[i].c[2]); sprintf(s,"%c%c%1d",elinfo[dsort[i].anum].name[0], elinfo[dsort[i].anum].name[1],dsort[i].atom); PSshow(s); PSstroke(); } if (dsort[i].sel) { PSsetgray(0.0); PSmoveto(dsort[i].c[0]+sca/3.0,dsort[i].c[2]); PSarc(dsort[i].c[0],dsort[i].c[2],sca/3.0,0.0,360.0); PSstroke(); } } } /* Space filling mode */ else { sca*=1.05; sca*=(elinfo[0].rad/elinfo[0].arad); sca/=fromP[2]; size.height=size.width=floor(sca)*2.0; /* scale the pre-rendered images. I tried using RIB images */ /* here, but it gave all sorts of errors. NeXT said that it */ /* should work. Maybe next release ... */ for (i=0; i<16; i++) { if (elinfo[i].image==nil) continue; [elinfo[i].image setSize:&size]; } /* Sort for painters algorithm */ qsort(dsort,mol[0].numa,sizeof(struct DSORT),(void *)comp); /* composite images */ for (i=0; i<mol[0].numa; i++) { if (dsort[i].c[1]<0.0) continue; j=dsort[i].anum; point.x=dsort[i].c[0]-sca; point.y=dsort[i].c[2]-sca; [elinfo[j].image composite:NX_SOVER toPoint:&point]; /* label atoms with label flag */ if (dsort[i].lab) { PSsetgray(0.5); PSmoveto(dsort[i].c[0]+2.0,dsort[i].c[2]); sprintf(s,"%c%c%1d",elinfo[dsort[i].anum].name[0], elinfo[dsort[i].anum].name[1],dsort[i].atom+1); PSshow(s); PSstroke(); } /* put a dot on selected atoms (or circle if H) */ if (dsort[i].sel) { PSmoveto(dsort[i].c[0]+sca/3.0,dsort[i].c[2]); PSarc(dsort[i].c[0],dsort[i].c[2],sca/3.0,0.0,360.0); if (j==0) { PSsetgray(0.0); PSstroke(); } else { PSsetgray(1.0); PSfill(); } } } } } if (bounds.size.width<150) { busy=0; return self; } /* display alt and az in upper right corner */ PSsetgray(0.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); sprintf(s,"Psi:%6.2f",phi/DRC); PSmoveto(bounds.size.width-60.0,bounds.size.height-28.0); PSshow(s); PSstroke(); busy=0; return self; } /* recalculates and redisplays data */ -zoom:sender { [shape setData:mol :nmol :elinfo :Rmode :Rflags]; [shape setAng:theta :chi :phi]; [self display]; return self; } /* obvious */ -setAng:(float)az :(float)alt :(float)Phi { theta=alt; chi=az; phi=Phi; return self; } -setMmode:sender { Mmode=[sender selectedCol]; return self; } -zeroRot:sender { dtheta=dchi=theta=chi=phi=0.0; [[mangS cellAt:0 :0] setFloatValue:theta/DRC]; [[mangS cellAt:1 :0] setFloatValue:chi/DRC]; [[mangS cellAt:2 :0] setFloatValue:phi/DRC]; [[mangT cellAt:0 :0] setFloatValue:theta/DRC]; [[mangT cellAt:1 :0] setFloatValue:chi/DRC]; [[mangT cellAt:2 :0] setFloatValue:phi/DRC]; [self display]; return self; } -zeroXlate:sender { fromP[0]=fromP[1]=0.0; toP[0]=toP[1]=0.0; [self setEyeAt:fromP toward:toP roll:0.0]; [self display]; return self; } -deSel:sender { [selView deselectAll]; [selView notifyO]; return self; } -selectAt:(float)x :(float)y :(int) flag { float mx[9]; int i,s= -1; float tx,ty,tz,sca,xc,yc,xw,yw,x2,y2,z2,d=1000.0,d2; /* a transform that almost matches the QRM transformation */ chi*=-1.0; phi*=-1.0; theta*=-1.0; mx[0]=cos(chi)*cos(phi)-cos(theta)*sin(phi)*sin(chi); mx[1]=cos(chi)*sin(phi)+cos(theta)*cos(phi)*sin(chi); mx[2]=sin(chi)*sin(theta); mx[3]= -sin(chi)*cos(phi)-cos(theta)*sin(phi)*cos(chi); mx[4]= -sin(chi)*sin(phi)+cos(theta)*cos(phi)*cos(chi); mx[5]=cos(chi)*sin(theta); mx[6]=sin(theta)*sin(phi); mx[7]= -sin(theta)*cos(phi); mx[8]=cos(theta); chi*=-1.0; phi*=-1.0; theta*=-1.0; /* scaling info */ xw=bounds.size.width; yw=bounds.size.height; xc=bounds.size.width/2.0; yc=bounds.size.height/2.0; sca=bounds.size.height*1.8; /* transform the coordinates */ for (i=0; i<mol[0].numa; i++) { tx=mol[0].coord[i][0]; ty= -mol[0].coord[i][2]; tz=mol[0].coord[i][1]; y2=tx*mx[3]+ty*mx[4]+tz*mx[5]+fromP[2]; if (y2<=0.0) continue; x2=(tx*mx[0]+ty*mx[1]+tz*mx[2]+fromP[0])*sca/y2+xc; z2=(tx*mx[6]+ty*mx[7]+tz*mx[8]-fromP[1])*sca/y2+yc; d2=sqrt(SQR(x2-x)+SQR(z2-y)); if (d2<10.0 && d2<d) { s=i; d=d2; } /* printf("%d %f %f %f %f %f\n",i,x,x2,y,y2,d2);*/ } if (s==-1) return self; if (!flag) [selView deselectAll]; [selView select:s]; return self; } /* allows spinning and zooming with the mouse */ -mouseDown:(NXEvent *)oevent { int oldMask,loop=1; float ix=0,iy=0,ix1=0,iy1=0,ix2=0,iy2=0,ix3=0,iy3=0; NXEvent *event,evs; long tm,tm2; evs=*oevent; oevent=&evs; [self convertPoint:&oevent->location fromView:nil]; 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]; /* [shape setDrawAsBox:YES];*/ switch (event->type) { case NX_LMOUSEUP: loop = 0; if (Mmode==0) { if (event->time-tm2==0) tm2=event->time-1; dchi=(event->location.x-ix2)/(float)(event->time-tm2)/10.0; dtheta=-(event->location.y-iy2)/(float)(event->time-tm2)/10.0; if (fabs(dchi)<.004) dchi=0.0; [shape setAng:theta :chi :phi]; [self display]; [[mangS cellAt:0 :0] setFloatValue:theta/DRC]; [[mangS cellAt:1 :0] setFloatValue:chi/DRC]; [[mangT cellAt:0 :0] setFloatValue:theta/DRC]; [[mangT cellAt:1 :0] setFloatValue:chi/DRC]; } else if (Mmode==1) { } else if (Mmode==2) { if (event->flags&NX_SHIFTMASK) [self selectAt:event->location.x :event->location.y :1]; else [self selectAt:event->location.x :event->location.y :0]; } break; case NX_LMOUSEDRAGGED: if (Mmode==0) { theta-=(event->location.y-iy)/30.0; chi+=(event->location.x-ix)/30.0; if (theta>M_PI) theta-=2.0*M_PI; if (theta<-M_PI) theta+=2.0*M_PI; 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]; [self display]; } else if (Mmode==1) { toP[0]=fromP[0]+=(event->location.x-ix)/25.0; toP[1]=fromP[1]-=(event->location.y-iy)/25.0; ix=event->location.x; iy=event->location.y; [self setEyeAt:fromP toward:toP roll:0.0]; [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 */ } /* This animates the icon */ if (animicon>=0 && (dchi!=0 || dtheta!=0)) { [AICV lockFocus]; [AIMG composite:NX_SOVER toPoint:&Ior1]; [AIMGS[animicon] composite:NX_SOVER toPoint:&Ior2]; [AICV unlockFocus]; [AICV display]; animicon++; if (animicon>7) animicon=0; } if (minshape) { [controller minStep:self]; if (dchi==0.0) { [self display]; return self; } } if (dchi==0.0&&dtheta==0.0) return self; chi+=dchi; theta+=dtheta; if (theta>M_PI) theta-=2.0*M_PI; if (theta<-M_PI) theta+=2.0*M_PI; while (chi>2.0*M_PI) chi-=2.0*M_PI; while (chi<0.0) chi+=2.0*M_PI; if (busy) { return self; } [shape setAng:theta :chi :phi]; [[mangS cellAt:0 :0] setFloatValue:theta/DRC]; [[mangS cellAt:1 :0] setFloatValue:chi/DRC]; [[mangS cellAt:2 :0] setFloatValue:phi/DRC]; [[mangS cellAt:3 :0] setFloatValue:fromP[2]]; [[mangT cellAt:0 :0] setFloatValue:theta/DRC]; [[mangT cellAt:1 :0] setFloatValue:chi/DRC]; [[mangT cellAt:2 :0] setFloatValue:phi/DRC]; [[mangT cellAt:3 :0] setFloatValue:fromP[2]]; [self display]; return self; } -(int)acceptsFirstMouse { return (YES); } -setcontroller:con { controller=con; return self; } /* allow user to pause spinning (not used)*/ -togFreeze:sender { static float Tdchi; if ([sender intValue]) { Tdchi=dchi; dchi=0.0; return self; } dchi=Tdchi; return self; } /* just set a few things before MolShape takes over */ - renderSelf:(RtToken)context { RtFloat par[2]= {8.0,8.0}; /*RiErrorIgnore();*/ RiShadingRate(2.0); RiGeometricApproximation(RI_TESSELATION,RI_PARAMETRIC,par,RI_NULL); busy=1; return self; } /* dump the current screen image as a RIB file */ - dumpRib:sender { static id savePanel=nil; NXStream *ts; char buf[MAXPATHLEN+1]; int omode; if (!savePanel) { savePanel=[SavePanel new]; [savePanel setRequiredFileType:"rib"]; } if([savePanel runModal]){ ts=NXOpenMemory(NULL, 0, NX_WRITEONLY); strcpy(buf, [savePanel filename]); strrchr(buf,'.')[0]='\0'; NXPrintf(ts, "Display \"%s.tiff\" \"file\" \"rgb\"\n", buf); omode=Rmode; Rmode=3; /* the Rmode+8 causes a white rectangle to appear behind the molecule */ [shape setData:mol :nmol :elinfo :Rmode+8 :Rflags]; [self copyRIBCode:ts]; Rmode=omode; [shape setData:mol :nmol :elinfo :Rmode :Rflags]; NXSaveToFile(ts, [savePanel filename]); NXCloseMemory(ts,NX_FREEBUFFER); } return self; } - setAmbLight:sender { [ambLight setIntensity:[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; } /* rendering mode - ie. point,line,surface,smooth,quick ... */ - setMode:sender { int i; Rmode=i=[sender selectedRow]; [shape setData:mol :nmol :elinfo :Rmode :Rflags]; switch(i) { case 0: [self setSurfaceTypeForAll:N3D_PointCloud chooseHider:YES]; if (!useColor) [window setDepthLimit:NX_TwoBitGrayDepth]; break; case 1: [self setSurfaceTypeForAll:N3D_WireFrame chooseHider:YES]; if (!useColor) [window setDepthLimit:NX_TwoBitGrayDepth]; break; case 2: [self setSurfaceTypeForAll:N3D_FacetedSolids chooseHider:YES]; break; case 3: [self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES]; break; case 4: [self setSurfaceTypeForAll:N3D_WireFrame chooseHider:NO]; [self setHider:N3D_NoRendering]; if (!useColor) [window setDepthLimit:NX_TwoBitGrayDepth]; break; } [self display]; return self; } -printPS:sender { id image; int fd; NXStream *out; [shape setData:mol :nmol :elinfo :Rmode+8 :Rflags]; if (Rflags==2&&Rmode==4) { [self lockFocus]; image=[[NXBitmapImageRep alloc] initData:NULL fromRect:&bounds]; [self unlockFocus]; out=NXOpenFile(fd=open("/tmp/MVprint.tiff",O_WRONLY|O_CREAT,0777),NX_WRITEONLY); [image writeTIFF:out]; NXClose(out); close(fd); [image free]; system("open /tmp/MVprint.tiff"); } else [super printPSCode:sender]; [shape setData:mol :nmol :elinfo :Rmode :Rflags]; return self; } /* mode, ie. stick, ball&stick or spacefill */ -setFlags:sender { int i; Rflags=0; if ([[flagSel findCellWithTag:1] intValue]) Rflags+=1; if ([[flagSel findCellWithTag:2] intValue]) Rflags+=2; if (Rflags==2&&Rmode==4) { for (i=0; i<40; i++) if (elinfo[i].image!=nil) break; if (i==40) [controller error:"Warning: you must render some atoms with 'make quick' on the preferences panel and restart before this mode will work" :NO]; } if ([chgCol intValue]) Rflags+=4; [shape setData:mol :nmol :elinfo :Rmode :Rflags]; [self display]; return self; } /* dist form observer to object */ -setEDist:sender { fromP[2]= -[sender floatValue]; [self setEyeAt:fromP toward:toP roll:0.0]; [self display]; return self; } /* generate a sequence of RIB's as an animation */ - ribRot:sender { static id savePanel=nil; NXStream *ts; float ophi,step,start; char buf[MAXPATHLEN+1],s[20]; int i,omode,j; if (savePanel==nil) savePanel=[SavePanel new]; [savePanel setRequiredFileType:"rib"]; j=[[animSpin cellAt:1 :0] intValue]; step=2.0*M_PI/(float)j; start=[[animSpin cellAt:0 :0] floatValue]; ophi=phi; omode=Rmode; if([savePanel runModal]){ /* if you want to change the number of frames in the animation, change */ /* the next 2 lines */ for (i=0; i<j; i++) { phi=(float)i*step+start; [shape setAng:theta :chi :phi]; strcpy(buf, [savePanel filename]); strrchr(buf,'.')[0]='\0'; ts=NXOpenMemory(NULL, 0, NX_WRITEONLY); NXPrintf(ts, "Display \"%s.%d.tiff\" \"file\" \"rgb\"\n", buf,i); Rmode=3; [shape setData:mol :nmol :elinfo :Rmode :Rflags]; [self copyRIBCode:ts]; Rmode=omode; [shape setData:mol :nmol :elinfo :Rmode :Rflags]; [self display]; sprintf(s,".%d.rib",i); strcat(buf,s); NXSaveToFile(ts, buf); NXCloseMemory(ts,NX_FREEBUFFER); } } phi=ophi; [shape setAng:theta :chi :phi]; [self display]; return self; } /* generate a sequence of RIB's as an animation */ - ribConform:sender { static id savePanel=nil; NXStream *ts; float ophi; char buf[MAXPATHLEN+1],s[20]; int i,omode; float x,y; if (savePanel==nil) savePanel=[SavePanel new]; [savePanel setRequiredFileType:"rib"]; ophi=phi; omode=Rmode; if([savePanel runModal]){ /* if you want to change the number of frames in the animation, change */ /* the next 2 lines */ for (i=1; i<=60; i+=1) { x=cos((float)i*.1047+.785)*180.0*(float)(65-i)/65.0; y=sin((float)i*.1047+.785)*180.0*(float)(65-i)/65.0; [controller setPhi:x]; [controller setPsi:y]; strcpy(buf, [savePanel filename]); strrchr(buf,'.')[0]='\0'; ts=NXOpenMemory(NULL, 0, NX_WRITEONLY); NXPrintf(ts, "Display \"%s.%d.tiff\" \"file\" \"rgb\"\n", buf,i); Rmode=3; [shape setData:mol :nmol :elinfo :Rmode :Rflags]; [self copyRIBCode:ts]; Rmode=omode; [shape setData:mol :nmol :elinfo :Rmode :Rflags]; [self display]; sprintf(s,".%d.rib",i); strcat(buf,s); NXSaveToFile(ts, buf); NXCloseMemory(ts,NX_FREEBUFFER); } } phi=ophi; [shape setAng:theta :chi :phi]; [self display]; return self; } /* generate a sequence of RIB's as an animation */ - ribConfTo:sender { static id savePanel=nil; NXStream *ts; float ophi; char buf[MAXPATHLEN+1],s[20]; int i,steps,omode; float x,y,x2,y2; if (savePanel==nil) savePanel=[SavePanel new]; [savePanel setRequiredFileType:"rib"]; ophi=phi; omode=Rmode; if([savePanel runModal]){ /* if you want to change the number of frames in the animation, change */ /* the next 2 lines */ x=mol[0].am[1].phi/DRC; y=mol[0].am[1].psi/DRC; x2=[[animConf cellAt:0 :0] floatValue]; y2=[[animConf cellAt:1 :0] floatValue]; steps=[[animConf cellAt:2 :0] intValue]; for (i=1; i<=steps; i++) { [controller setPhi:(x2-x)*(float)i/(float)steps+x]; [controller setPsi:(y2-y)*(float)i/(float)steps+y]; phi=(float)i*.15708; [shape setAng:theta :chi :phi]; strcpy(buf, [savePanel filename]); strrchr(buf,'.')[0]='\0'; ts=NXOpenMemory(NULL, 0, NX_WRITEONLY); NXPrintf(ts, "Display \"%s.%d.tiff\" \"file\" \"rgb\"\n", buf,i); Rmode=3; [shape setData:mol :nmol :elinfo :Rmode :2]; [self copyRIBCode:ts]; Rmode=omode; [shape setData:mol :nmol :elinfo :Rmode :Rflags]; [self display]; sprintf(s,".%d.rib",i); strcat(buf,s); NXSaveToFile(ts, buf); NXCloseMemory(ts,NX_FREEBUFFER); } } phi=ophi; [shape setAng:theta :chi :phi]; [self display]; return self; } /* This used to dump a DKB raytracer format file. Now it dumps a POV */ /* (based on DKB) file. You can get POV from wuarchive.wustl.edu */ /* in /graphics/graphics/ray. POV is certainly slower than renderman, */ /* but it is much more flexible. */ -dkbDump:sender { static id savePanel=nil; FILE *out; char s[80]; int i,n; float x,y,z,mx[9]; if (savePanel==nil) savePanel=[SavePanel new]; [savePanel setRequiredFileType:"pov"]; if([savePanel runModal]){ sprintf(s,"cp %s/header.dat %s",bpath,[savePanel filename]); system(s); out=fopen([savePanel filename],"a"); fprintf(out,"camera {\n location <0 0 %f>\n",fromP[2]); fprintf(out," up <0 1 0>\n right <1.33333 0 0>\n"); fprintf(out," look_at <0 0 0>\n sky <0 1 0>\n}\n"); chi*=-1.0; phi*=-1.0; theta*=-1.0; mx[0]=cos(chi)*cos(phi)-cos(theta)*sin(phi)*sin(chi); mx[1]=cos(chi)*sin(phi)+cos(theta)*cos(phi)*sin(chi); mx[2]=sin(chi)*sin(theta); mx[3]= -sin(chi)*cos(phi)-cos(theta)*sin(phi)*cos(chi); mx[4]= -sin(chi)*sin(phi)+cos(theta)*cos(phi)*cos(chi); mx[5]=cos(chi)*sin(theta); mx[6]=sin(theta)*sin(phi); mx[7]= -sin(theta)*cos(phi); mx[8]=cos(theta); chi*=-1.0; phi*=-1.0; theta*=-1.0; for (i=0; i<mol[0].numa; i++) { x=mol[0].coord[i][0]; y=mol[0].coord[i][1]; z=mol[0].coord[i][2]; n=mol[0].atom[i].anum; fprintf(out,"object {\n sphere { <%f %f %f> %f }\n", -(x*mx[0]+y*mx[1]+z*mx[2]),x*mx[3]+y*mx[4]+z*mx[5], x*mx[6]+y*mx[7]+z*mx[8],elinfo[n].rad); fprintf(out," texture {\n\tcolor red %5.3f green %5.3f blue %5.3f\n\tphong 1.0\n }\n}\n\n",elinfo[n].color[0], elinfo[n].color[1],elinfo[n].color[2]); } fclose(out); } return self; } -togMin:sender { if ([sender intValue]) minshape=1; else minshape=0; return self; } /* save the current scene as EPS */ - dumpEPS:sender { static id savePanel=nil; NXStream *out; if (!savePanel) { savePanel=[SavePanel new]; [savePanel setRequiredFileType:"eps"]; } if([savePanel runModal]){ out=NXOpenMemory(NULL,0, NX_WRITEONLY); [self copyPSCodeInside:&bounds to:out]; NXSaveToFile(out,[savePanel filename]); NXCloseMemory(out,NX_FREEBUFFER); } return self; } -setColor:sender { int i; useColor=[sender intValue]; i=Rmode; [self setSurfaceTypeForAll:N3D_PointCloud chooseHider:YES]; switch(i) { case 0: [self setSurfaceTypeForAll:N3D_PointCloud chooseHider:YES]; if (!useColor) [window setDepthLimit:NX_TwoBitGrayDepth]; break; case 1: [self setSurfaceTypeForAll:N3D_WireFrame chooseHider:YES]; if (!useColor) [window setDepthLimit:NX_TwoBitGrayDepth]; break; case 2: [self setSurfaceTypeForAll:N3D_FacetedSolids chooseHider:YES]; break; case 3: [self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES]; break; case 4: [self setSurfaceTypeForAll:N3D_WireFrame chooseHider:NO]; [self setHider:N3D_NoRendering]; if (!useColor) [window setDepthLimit:NX_TwoBitGrayDepth]; break; } [self display]; return self; } -setAngT:sender { int i; dchi=dtheta=0; i=[sender selectedRow]; switch (i) { case 0: theta=[[mangT cellAt:0 :0] floatValue]*DRC; [[mangS cellAt:0 :0] setFloatValue:theta/DRC]; break; case 1: chi=[[mangT cellAt:1 :0] floatValue]*DRC; [[mangS cellAt:1 :0] setFloatValue:chi/DRC]; break; case 2: phi=[[mangT cellAt:2 :0] floatValue]*DRC; [[mangS cellAt:2 :0] setFloatValue:phi/DRC]; break; case 3: fromP[2]=[[mangT cellAt:3 :0] floatValue]; [[mangS cellAt:3 :0] setFloatValue:fromP[2]]; [self setEyeAt:fromP toward:toP roll:0.0]; break; } [shape setAng:theta :chi :phi]; [self display]; return self; } -setAngS:sender { int i; dchi=dtheta=0; i=[sender selectedRow]; switch (i) { case 0: theta=[[mangS cellAt:0 :0] floatValue]*DRC; [[mangT cellAt:0 :0] setFloatValue:theta/DRC]; break; case 1: chi=[[mangS cellAt:1 :0] floatValue]*DRC; [[mangT cellAt:1 :0] setFloatValue:chi/DRC]; break; case 2: phi=[[mangS cellAt:2 :0] floatValue]*DRC; [[mangT cellAt:2 :0] setFloatValue:phi/DRC]; break; case 3: fromP[2]=[[mangS cellAt:3 :0] floatValue]; [[mangT cellAt:3 :0] setFloatValue:fromP[2]]; [self setEyeAt:fromP toward:toP roll:0.0]; break; } [shape setAng:theta :chi :phi]; [self display]; return self; } /* NeXT said that this should clean up most of the QRM problems. */ /* As far as I can tell it doesn't have any effect */ - flushRIB { RiSynchronize( RI_FLUSH ); RiSynchronize( RI_WAIT ); return self; } -newBSSR:sender { [shape setBSSR:[[sender cellAt:0 :0] floatValue] :[[sender cellAt:1 :0] floatValue]]; [self display]; return self; } int comp(struct DSORT *a,struct DSORT *b) { if (a->c[1]>b->c[1]) return(-1); if (a->c[1]==b->c[1]) return(0); else return(1); } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.