home *** CD-ROM | disk | FTP | other *** search
- /* 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 <appkit/appkit.h>
- #import <dpsclient/event.h>
- #import <dpsclient/psops.h>
- #import <stdio.h>
- #import <math.h>
- #include <libc.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 fromP = {0,0,60.0}, toP = {0,0,0};
- RtPoint lFromP = {5.0,10.0,5.0},lToP = {0,0,0};
- int i;
- id aShader;
-
- bpath=(char *)[[NXBundle mainBundle] directory];
-
- [super initFrame:(NXRect *)myrect];
-
- /* set up light sources, etc... */
- [self setBackgroundColor:NX_COLORWHITE];
- [self setDrawBackgroundColor:YES];
-
- edist=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];
- [[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];
-
- 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];
- [self zoom:self];
- return self;
- }
-
- -free
- {
- DPSRemoveTimedEntry(timer);
- [super free];
- 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;
- float tx,ty,tz,sca,xc,yc,xw,yw;
- static struct DSORT *dsort=NULL;
- static int dsmax=1000000;
- NXPoint point;
- NXSize size;
-
- if (mol==NULL) return self;
- 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]+edist;
- if (dsort[i].c[1]<=0.0) continue;
- dsort[i].c[0]=(tx*mx[0]+ty*mx[1]+tz*mx[2])*sca/dsort[i].c[1]+xc;
- dsort[i].c[2]=(tx*mx[6]+ty*mx[7]+tz*mx[8])*sca/dsort[i].c[1]+yc;
- dsort[i].anum=mol[0].atom[i].anum;
- dsort[i].sel=mol[0].atom[i].sel;
- if (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/=edist;
- /* circle selected atoms */
- for (i=0; i<mol[0].numa; i++) {
- 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 and ball-stick mode are the same in quick mode */
- else {
- sca*=1.05;
- sca*=(elinfo[0].rad/elinfo[0].arad);
- sca/=edist;
- 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];
- /* 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);
- PSsethel();
- 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();
-
- 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;
- }
-
- /* 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];
- 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;
- /* [shape setDrawAsBox:YES];*/
- switch (event->type) {
- case NX_LMOUSEUP:
- loop = 0;
- if (event->time-tm2==0) tm2=event->time-1;
- dchi=(event->location.x-ix2)/(float)(event->time-tm2)*15.0;
- dtheta=-(event->location.y-iy2)/(float)(event->time-tm2)*15.0;
- if (fabs(dchi)<.004) dchi=0.0;
- [shape setAng:theta :chi :phi];
- /* [shape setDrawAsBox:NO];*/
- [self display];
- break;
- case NX_LMOUSEDRAGGED:
- theta-=(event->location.y-iy)*3.0;
- chi+=(event->location.x-ix)*4.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];
- 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];
- [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 :2];
- [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
- {
- [shape setData:mol :nmol :elinfo :Rmode+8 :Rflags];
- [super printPSCode:sender];
- [shape setData:mol :nmol :elinfo :Rmode :Rflags];
- return self;
- }
-
- /* mode, ie. stick, ball&stick or spacefill */
- -setFlags:sender
- {
- Rflags=0;
- if ([[flagSel findCellWithTag:1] intValue]) Rflags+=1;
- if ([[flagSel findCellWithTag:2] intValue]) Rflags+=2;
- [shape setData:mol :nmol :elinfo :Rmode :Rflags];
- [self display];
- return self;
- }
-
- /* dist form observer to object */
- -setEDist:sender
- {
- RtPoint fromP = {0,0,30.0}, toP = {0,0,0};
-
- edist= -[sender floatValue];
- fromP[2]=edist;
- [self setEyeAt:fromP toward:toP roll:0.0];
- [self display];
- return self;
- }
-
- -setPhi:sender
- {
- phi=[sender floatValue]/57.2958;
- [shape setAng:theta :chi :phi];
- [self display];
- return self;
- }
-
- /* generate a sequence of RIB's as an animation */
- - ribRot:sender
- {
- static id savePanel=nil;
- NXStream *ts;
- float ophi;
- char buf[MAXPATHLEN+1],s[20];
- int i,omode;
-
- 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<=30; i+=1) {
- phi=(float)i*.2094;
- [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",edist);
- 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
- {
- useColor=[sender intValue];
- 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;
- }
-
- int comp(struct DSORT *a,struct DSORT *b)
- {
- if (a->c[1]>b->c[1]) return(-1);
- else return(1);
- }
- @end
-