/* * Celestial Mechanics Simulation Tool * * W. John Guineau * 3 Royal Crest Drive #9 * Marlboro, Mass. 01752 * (508) 485-6233 * * Files: * cm.c * cm.h * cm.doc * * To Compile with Lattice 5.02: * * lc -b0 -Lm cm * * * NOTICE * ------ * * I have placed this software in the Public Domain with the * condition that all the files remain together and that I remain * listed as the original author. This software may not be used for * commercial purposes or to make money in any way without expressed * written permission from the author (me). I'm including the source * code so if you make any significant modifications please concider * sending me a copy at the above address. I'd also be interested in * any interesting saved setup files you create. * * * This is my first Amiga program so I welcome any comments at all. * I wrote this program as both a way to learn the Amiga environment * and in response to a conversation I had with a friend on Celestial * Mechanics. * * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cm.h" #define NOWAIT 0 #define WAIT 1 extern struct IntuitionBase *IntuitionBase; extern struct GfxBase *GfxBase; struct IntuiMessage *message; struct Screen *s; struct Window *w; struct Window *pw; struct RastPort *rp; struct RastPort *prp; struct ViewPort *vp; #define ReqNone 0 #define ReqBody 1 #define ReqSetup 2 #define ReqFile 3 #define ReqAbout 4 UBYTE CancelHit=0; /* If user selects CANCEL from Reqester */ UBYTE ReqActive=ReqNone; /* Set when a Reqester is active */ /* to keep DoIntuiEvents() from returning */ /* until it gets a REQCLEAR msg */ struct setup { double G; double ds; double dt; UBYTE t; WORD TrailLength; UBYTE ShowTime; } SI; #define MAXTRAILEN 300 struct Body { /* Info for a Celestial Body */ UBYTE real; /* If it's real */ UBYTE fixed; /* Body fixed in place */ UBYTE pen; /* Color Register */ char name[10]; /* user given name */ ULONG Radius; /* radius */ double Mass; /* mass */ double x,y; /* current position */ double Vx,Vy; /* velocity components */ double Fx,Fy; /* resultant force components */ double Dir; /* direction angle (radians) */ double TrailX[MAXTRAILEN]; /* X of trail of pixels to clear */ double TrailY[MAXTRAILEN]; /* X of trail of pixels to clear */ WORD TrailIDX; }; #define MAXBODYS 10 struct Body Bodys[MAXBODYS]; /* The array of bodys */ BYTE CurBody,TotalBodys=0; ULONG Et; /* elapsed time */ #define MODE_CREATE 1 #define MODE_MODIFY 2 #define MODE_START 3 #define MODE_STOP 4 UBYTE mode = MODE_STOP; /* Current simulation mode */ /* pointer text for ShowMouse() */ char pbuf[80]; struct IntuiText pos_txt = { WHTPEN,BLKPEN, /* FrontPen, BackPen */ JAM2, /* DrawMode */ 7,2, /* LeftEdge, TopEdge */ &TxtAt_Plain, /* TextAttr */ pbuf, /* IText */ NULL /* NextText */ }; struct MsgPort *TimerPort; /* for Timer stuff */ struct timerequest *TR; UBYTE TimerOpen=0; /* ============================================================ * Main * * ============================================================*/ main(argc,argv) int argc; char *argv[]; { OpenStuff(); Init(); DoIntuiEvents(WAIT); return(0); } OpenStuff() { TimerPort = (struct MsgPort *)CreatePort(0,0); if(TimerPort == 0) { printf("Cant get a Timer Port\n"); CleanUp(); exit(10); }; TR = (struct timerequest *)CreateExtIO(TimerPort, sizeof(struct timerequest)); if(TR == 0) { printf("Cant get a Timer Request\n"); CleanUp(); exit(11); }; if(OpenDevice(TIMERNAME,UNIT_VBLANK,TR,0) != 0) { printf("Cant open Timer Device\n"); CleanUp(); exit(12); }; TimerOpen = 1; if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0))) { printf("no graphics library!!!\n"); CleanUp(); exit(13); }; if(!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",0))) { printf("no intuition here!!\n"); CleanUp(); exit(14); }; if (!(s = (struct Screen *)OpenScreen(&ns) )) { printf("could not open the screen\n"); CleanUp(); exit(15); }; /* * set up color map for new screen */ vp = (struct ViewPort *)&s->ViewPort; LoadRGB4(vp,colortable,COLORS); nw.Screen = s; /* point to our screen */ npw.Screen = s; /* pointer window struct also */ if (!(w = (struct Window *)OpenWindow(&nw) )) { printf("could not open the window\n"); CleanUp(); exit(16); }; rp = w->RPort; SetAPen(rp,WHTPEN); SetMenuStrip(w,&Control); return(0); } Init() { SI.G = 6.67; SI.ds = 1.0; SI.dt = 1.0; SI.t = 0; SI.TrailLength = 0; cancel_text.IText = cantxt; OffMenu(w,MN_CStop); OffMenu(w,MN_EMod); OffMenu(w,MN_FSScr); ClearScreen(); ClearBodys(); SetupGADefaults(); BodyGADefaults(); return(0); } ClearScreen() { SetRast(rp,0); SetAPen(rp,WHTPEN); return(0); } DoIntuiEvents(wait) UBYTE wait; { ULONG MessageClass; USHORT code,qual; struct Gadget *GAD; struct MsgPort *mp; mp = w->UserPort; for(;;) { if(message = (struct IntuiMessage *)GetMsg(w->UserPort)) { MessageClass = message->Class; code = message->Code; qual = message->Qualifier; GAD = (struct Gadget *)message->IAddress; ReplyMsg(message); switch (MessageClass) { case GADGETUP : DoGadget(GAD); break; case MENUPICK : if(code != MENUNULL) { DoMenu(code); }; break; case CLOSEWINDOW : CleanUp(); exit(0); break; case MOUSEBUTTONS: if(code == SELECTDOWN) { MakeBody(w->GZZMouseX,w->GZZMouseY); }; break; case MOUSEMOVE : if(mode == MODE_CREATE) { ShowMouse(w->GZZMouseX,w->GZZMouseY); }; break; case REQCLEAR : ReqActive = ReqNone; break; default : break; }; } else { if(!wait&&!ReqActive) return(0); WaitPort(mp); }; }; return(0); } DoGadget(GAD) struct Gadget *GAD; { ULONG val; struct StringInfo *info; info = (struct StringInfo *)GAD->SpecialInfo; val = info->LongInt; switch(GAD->GadgetID) { case NAMEGAD : ActivateGadget(&mass,w,&BodyInfo); break; case RADIUSGAD : break; case MASSGAD : ActivateGadget(&velocity,w,&BodyInfo); break; case VELOCITYGAD : ActivateGadget(&direction,w,&BodyInfo); break; case DIRECTIONGAD : break; case OKGAD : CancelHit=0; if(pw) WindowToFront(pw); break; case CANCELGAD : CancelHit=1; if(pw) WindowToFront(pw); break; case RESETGAD : switch(ReqActive) { case ReqBody : BodyGADefaults(); RefreshGadgets(&mass, w,&BodyInfo); break; case ReqSetup : SetupGADefaults(); RefreshGadgets(&dt, w,&SetupInfo); break; }; break; case GGAD : ActivateGadget(&dt,w,&SetupInfo); break; case DTGAD : ActivateGadget(&t,w,&SetupInfo); break; case TGAD : ActivateGadget(&ds,w,&SetupInfo); break; case DSGAD : ActivateGadget(&tl,w,&SetupInfo); break; case TLGAD : break; case COLOR1GAD : Bodys[CurBody].pen = (UBYTE)GAD->UserData; break; case COLOR2GAD : Bodys[CurBody].pen = (UBYTE)GAD->UserData; break; case COLOR3GAD : Bodys[CurBody].pen = (UBYTE)GAD->UserData; break; case COLOR4GAD : Bodys[CurBody].pen = (UBYTE)GAD->UserData; break; case COLOR5GAD : Bodys[CurBody].pen = (UBYTE)GAD->UserData; break; case COLOR6GAD : Bodys[CurBody].pen = (UBYTE)GAD->UserData; break; case COLOR7GAD : Bodys[CurBody].pen = (UBYTE)GAD->UserData; break; case FNOKGAD : CancelHit=0; break; case FNCANGAD : CancelHit=1; break; case STGAD : if(st.Flags&SELECTED) { st.GadgetText = &yes_text; RefreshGadgets(&st,w,&SetupInfo); SI.ShowTime=1; } else { st.GadgetText = &no_text; RefreshGadgets(&st,w,&SetupInfo); SI.ShowTime=0; }; break; case FXGAD : if(fixed.Flags&SELECTED) { fixed.GadgetText = &yes_text; RefreshGadgets(&fixed,w,&BodyInfo); Bodys[CurBody].fixed=1; } else { fixed.GadgetText = &no_text; RefreshGadgets(&fixed,w,&BodyInfo); Bodys[CurBody].fixed=0; }; break; default : break; }; return(0); } DoMenu(MN) USHORT MN; { switch(MENUNUM(MN)) { case M_Control : switch(ITEMNUM(MN)) { case I_Stop : mode = MODE_STOP; ClosePw(); OffMenu(w,MN_CStop); OnMenu(w,MN_ECreate); OnMenu(w,MN_ESetup); OnMenu(w,MN_EMod); OnMenu(w,MN_EClearS); OnMenu(w,MN_EClearB); OnMenu(w,MN_FSDat); OnMenu(w,MN_FLDat); OnMenu(w,MN_CStart); break; case I_Start : if(TotalBodys == 0) { MSG("No Bodys Created!!","OK","OK"); break; }; mode = MODE_START; ModifyIDCMP(w,IDCMPFL); if(SI.ShowTime) OpenPw(); OffMenu(w,MN_ECreate); OffMenu(w,MN_ESetup); OffMenu(w,MN_EMod); OffMenu(w,MN_CStart); OffMenu(w,MN_EClearS); OffMenu(w,MN_EClearB); OffMenu(w,MN_FSDat); OffMenu(w,MN_FLDat); OnMenu(w,MN_CStop); DoSimulation(); break; }; break; case M_Edit : switch(ITEMNUM(MN)) { case I_ClearB : if(MSG("Really Clear Bodys?", "YES!","NO!!")) { ClearBodys(); OnMenu(w,MN_FSDat); OnMenu(w,MN_FLDat); }; break; case I_ClearS : ClearScreen(); break; case I_Modify : mode = MODE_MODIFY; ModifyBodys(); break; case I_Create : mode = MODE_CREATE; ModifyIDCMP(w,IDCMPFL_MM); OpenPw(); OnMenu(w,MN_CStart); OnMenu(w,MN_EMod); OffMenu(w,MN_ECreate); OffMenu(w,MN_FLDat); cancel_text.IText = cantxt; break; case I_Setup : Request(&SetupInfo,w); Sleep(0L,100000L); ActivateGadget(&G,w,&SetupInfo); ReqActive = ReqSetup; DoIntuiEvents(NOWAIT); cancel_text.IText = cantxt; if(!CancelHit) GetSetupInfo(); break; }; break; case M_File : switch(ITEMNUM(MN)) { case I_Exit : CleanUp(); exit(0); break; case I_SavScr : break; case I_SavDat : DoSaveData(); break; case I_LoadDat : DoLoadData(); break; case I_About : Request(&RAbout,w); ReqActive = ReqAbout; DoIntuiEvents(NOWAIT); break; }; break; }; return(0); } ShowMouse(x,y) SHORT x,y; { if(x<0||y<0) return(0); sprintf(pbuf," %.3e , %.3e", (double)(x)*SI.ds,(double)(w->GZZHeight-y+1)*SI.ds); PrintIText(prp,&pos_txt,0,0); return(0); } OpenPw() { if(pw) return(0); if (!(pw = (struct Window *)OpenWindow(&npw) )) { printf("could not open the pointer window\n"); CleanUp(); exit(17); }; prp = pw->RPort; SetAPen(prp,BLKPEN); SetBPen(prp,WHTPEN); return(0); } ClosePw() { if(pw) CloseWindow(pw); pw = (struct Window *)NULL; return(0); } GetBodyInfo() { double V; strcpy(Bodys[CurBody].name,name_sbuf); if(sscanf(mass_sbuf,"%le",&Bodys[CurBody].Mass) != 1) { MSG("Bad Value for Mass!","OK","OK"); return(0); }; Bodys[CurBody].Dir = (double)direction_txstr.LongInt * PI/180.0; if(sscanf(velocity_sbuf,"%le",&V) != 1) { MSG("Bad Value for Velocity!","OK","OK"); return(0); }; Bodys[CurBody].Vx = V * cos(Bodys[CurBody].Dir); Bodys[CurBody].Vy = V * sin(Bodys[CurBody].Dir); if(Bodys[CurBody].pen == 0) Bodys[CurBody].pen = WHTPEN; Bodys[CurBody].Fx = 0.0; Bodys[CurBody].Fy = 0.0; return(0); } GetSetupInfo() { WORD n; if(sscanf(G_sbuf,"%le",&SI.G) != 1) { MSG("Bad Value for G!","OK","OK"); return(0); }; if(sscanf(ds_sbuf,"%le",&SI.ds) != 1) { MSG("Bad Value for ds!","OK","OK"); return(0); }; if(sscanf(dt_sbuf,"%le",&SI.dt) != 1) { MSG("Bad Value for dt!","OK","OK"); return(0); }; SI.t = (UBYTE)t_txstr.LongInt; n = (WORD)tl_txstr.LongInt; if(n>MAXTRAILEN) { MSG("TrailLength too large!","OK","OK"); return(0); }; SI.TrailLength=n; return(0); } MakeBody(x,y) SHORT x,y; { if(mode != MODE_CREATE) return(0); if(x<0 || y<0) return(0); if(TotalBodys++ > MAXBODYS) { TotalBodys--; MSG("No More Body's Available!!","OK","OK"); return(0); }; SetAPen(rp,REDPEN); WritePixel(rp,x,y); CurBody = FindFreeBody(); if(CurBody == -1) { TotalBodys--; MSG("No More Body's Available!!","OK","OK"); return(0); }; cancel_text.IText = cantxt; BodyGADefaults(); sprintf(xy_buf," %.3e , %.3e ", (double)(x)*SI.ds,(double)(w->GZZHeight-y+1)*SI.ds); Request(&BodyInfo,w); ReqActive = ReqBody; Sleep(0L,100000L); ActivateGadget(&name,w,&BodyInfo); DoIntuiEvents(NOWAIT); if(CancelHit) { TotalBodys--; SetAPen(rp,BLKPEN); WritePixel(rp,x,y); return(0); }; GetBodyInfo(); if(Bodys[CurBody].Mass == 0.0) { TotalBodys--; SetAPen(rp,BLKPEN); WritePixel(rp,x,y); MSG("Mass can't be ZERO!!","OK","OK"); return(0); }; Bodys[CurBody].x = (double)(x)*SI.ds; Bodys[CurBody].y = (double)(y)*SI.ds; Bodys[CurBody].real = 1; SetAPen(rp,Bodys[CurBody].pen); WritePixel(rp,x,y); return(0); } FindFreeBody() { int x; for(x=0 ; xGZZHeight-y+1)*SI.ds); Request(&BodyInfo,w); Sleep(0L,100000L); ReqActive = ReqBody; ActivateGadget(&name,w,&BodyInfo); DoIntuiEvents(NOWAIT); if(CancelHit) { /* GAD really says "DELETE" */ TotalBodys--; SetAPen(rp,BLKPEN); WritePixel(rp,x,y); continue; }; GetBodyInfo(); if(Bodys[n].Mass == 0.0) { TotalBodys--; SetAPen(rp,BLKPEN); WritePixel(rp,(SHORT)x,(SHORT)y); MSG("Mass can't be ZERO!!","OK","OK"); continue; }; Bodys[n].real=1; SetAPen(rp,Bodys[CurBody].pen); WritePixel(rp,x,y); }; }; color_text.FrontPen = WHTPEN; OnMenu(w,MN_CStart); OnMenu(w,MN_ECreate); if(TotalBodys) OnMenu(w,MN_EMod); else OffMenu(w,MN_EMod); return(0); } LoadBodyReq(n) int n; { double v; name_txstr.NumChars = sprintf(name_sbuf,"%s",Bodys[n].name); mass_txstr.NumChars = sprintf(mass_sbuf,"%.3e",Bodys[n].Mass); direction_txstr.LongInt = (ULONG)(Bodys[n].Dir * 180.0/PI); direction_txstr.NumChars = sprintf(direction_sbuf,"%ld", direction_txstr.LongInt); v = Bodys[n].Vx*Bodys[n].Vx + Bodys[n].Vy*Bodys[n].Vy; v = sqrt(v); velocity_txstr.NumChars = sprintf(velocity_sbuf,"%.3e",v); if(Bodys[n].fixed) { fixed.GadgetText = &yes_text; fixed.Flags |= SELECTED; } else { fixed.GadgetText = &no_text; fixed.Flags &= ~SELECTED; } return(0); } DoSimulation() { UBYTE b; double F,Fx=0.0,Fy=0.0,V; Et = 0L; while(mode == MODE_START) { if(SI.ShowTime) { sprintf(pbuf," Time %ld",Et); PrintIText(prp,&pos_txt,0,0); }; /* * Calculate new directions & velocities * resulting from all external forces (all other bodies) */ for(b=0 ; b0) { if(Bodys[b].TrailIDX >= SI.TrailLength) Bodys[b].TrailIDX=0; if(Bodys[b].TrailX[Bodys[b].TrailIDX]>=0) { SetAPen(rp,BLKPEN); WritePixel(rp,(SHORT)(Bodys[b].TrailX[Bodys[b].TrailIDX]/SI.ds), (SHORT)(Bodys[b].TrailY[Bodys[b].TrailIDX]/SI.ds)); }; Bodys[b].TrailX[Bodys[b].TrailIDX] = Bodys[b].x; Bodys[b].TrailY[Bodys[b].TrailIDX] = Bodys[b].y; Bodys[b].TrailIDX++; }; }; Bodys[b].x += (Bodys[b].Vx * SI.dt); Bodys[b].y -= (Bodys[b].Vy * SI.dt); SetAPen(rp,Bodys[b].pen); WritePixel(rp,(SHORT)(Bodys[b].x/SI.ds),(SHORT)(Bodys[b].y/SI.ds)); }; DoIntuiEvents(NOWAIT); if(SI.t) Sleep(0L,(ULONG)SI.t*1000L); Et++; }; return(0); } GetForces(b,fx,fy) UBYTE b; double *fx,*fy; { int x; double dY,dX,Fx,Fy,F,R; Fx = Fy = 0.0; for(x=0 ; xGZZHeight-Bodys[x].y+1, Bodys[x].Vx,Bodys[x].Vy, Bodys[x].Dir*180.0/PI); }; fclose(fp); return(0); } DoLoadData() { int n; FILE *fp; char buf[101],name[10]; ULONG pen,fixed,Radius; double x,y,Mass,Vx,Vy,Dir; CancelHit=0; Request(&FileName,w); Sleep(0L,100000L); ActivateGadget(&fn,w,&FileName); ReqActive = ReqFile; DoIntuiEvents(NOWAIT); if(CancelHit) return(0); fp = fopen(fn_sbuf,"r"); if(!fp) { MSG("Can't open Data File!","OK!","OH WELL!"); return(0); }; fgets(buf,100,fp); /* forget first line, it's just a header */ fgets(buf,100,fp); if(sscanf(buf,"G=%le\n",&SI.G) != 1) { MSG("Bad data file (G)!","OK!","OOPS!"); fclose(fp); return(0); }; fgets(buf,100,fp); if(sscanf(buf,"ds=%le\n",&SI.ds) != 1) { MSG("Bad data file (ds)!","OK!","OOPS!"); fclose(fp); return(0); }; fgets(buf,100,fp); if(sscanf(buf,"dt=%le\n",&SI.dt) != 1) { MSG("Bad data file (dt)!","OK!","OOPS!"); fclose(fp); return(0); }; fgets(buf,100,fp); if(sscanf(buf,"t=%d\n",&n) != 1) { MSG("Bad data file (t)!","OK!","OOPS!"); fclose(fp); return(0); }; SI.t = (UBYTE)n; fgets(buf,100,fp); if(sscanf(buf,"TrailLength=%d\n",&n) != 1) { MSG("Bad data file (TrailLength)!","OK!","OOPS!"); fclose(fp); return(0); }; if(n>MAXTRAILEN) { MSG("TrailLength too big","OK!","OOPS!"); fclose(fp); return(0); }; SI.TrailLength = (WORD)n; fgets(buf,100,fp); if(sscanf(buf,"ShowTime=%d\n",&n) != 1) { MSG("Bad data file (ShowTime)!","OK!","OOPS!"); fclose(fp); return(0); }; SI.ShowTime = (WORD)n; if(n) { st.GadgetText = &yes_text; st.Flags |= SELECTED; } else { st.GadgetText = &no_text; st.Flags &= ~SELECTED; }; G_txstr.NumChars = sprintf(G_sbuf,"%.3e",SI.G); dt_txstr.NumChars = sprintf(dt_sbuf,"%.3e",SI.dt); t_txstr.NumChars = sprintf(t_sbuf,"%d",SI.t); t_txstr.LongInt = (ULONG)SI.t; ds_txstr.NumChars = sprintf(ds_sbuf,"%.3e",SI.ds); tl_txstr.LongInt = (LONG)SI.TrailLength; tl_txstr.NumChars = sprintf(tl_sbuf,"%d",SI.TrailLength); ClearBodys(); fgets(buf,100,fp); fgets(buf,100,fp); while(fgets(buf,100,fp) != (char *)NULL) { if(sscanf(buf,"%d=%s;%d;%d;%ld;%le;%le,%le;%le,%le;%le", &n,name,&pen,&fixed,&Radius,&Mass,&x,&y,&Vx,&Vy,&Dir) != 11) { MSG("Bad Body in data file","OK!","OOPS!"); fclose(fp); return(0); }; if(n>MAXBODYS) { MSG("Bad Body # in data file","OK!","OOPS!"); fclose(fp); return(0); }; if(!Bodys[n].real) TotalBodys++; /* don't count same definition twice */ Bodys[n].real = 1; Bodys[n].pen = pen; Bodys[n].fixed = fixed; Bodys[n].Radius = Radius; Bodys[n].Mass = Mass; Bodys[n].x = x; Bodys[n].y = w->GZZHeight-y+1; Bodys[n].Vx = Vx; Bodys[n].Vy = Vy; Bodys[n].Dir = Dir*PI/180.0; strcpy(Bodys[n].name,name); SetAPen(rp,pen); WritePixel(rp,(SHORT)(Bodys[n].x/SI.ds),(SHORT)(Bodys[n].y/SI.ds)); }; fclose(fp); OnMenu(w,MN_ECreate); OnMenu(w,MN_EMod); return(0); } MSG(msg,p,n) char *msg,*p,*n; { struct IntuiText msg_txt = { BLKPEN,REDPEN, /* FrontPen, BackPen */ JAM1, /* DrawMode */ 10,20, /* LeftEdge, TopEdge */ &TxtAt_Plain, /* TextAttr */ 0, /* IText */ NULL /* NextText */ }; struct IntuiText pos_txt = { BLKPEN,REDPEN, /* FrontPen, BackPen */ JAM1, /* DrawMode */ 3,3, /* LeftEdge, TopEdge */ &TxtAt_Plain, /* TextAttr */ 0, /* IText */ NULL /* NextText */ }; struct IntuiText neg_txt = { BLKPEN,REDPEN, /* FrontPen, BackPen */ JAM1, /* DrawMode */ 3,3, /* LeftEdge, TopEdge */ &TxtAt_Plain, /* TextAttr */ 0, /* IText */ NULL /* NextText */ }; msg_txt.IText = msg; pos_txt.IText = p; neg_txt.IText = n; return(AutoRequest(w,&msg_txt,&pos_txt,&neg_txt, NULL,NULL,40+IntuiTextLength(&msg_txt),80)); } Sleep(secs,usecs) ULONG secs,usecs; { TR->tr_node.io_Command = TR_ADDREQUEST; TR->tr_time.tv_secs = secs; TR->tr_time.tv_micro = usecs; DoIO(TR); return(0); } CleanUp() { if(TimerPort) DeletePort(TimerPort); if(TimerOpen) CloseDevice(TR); if(TR) DeleteExtIO(TR,sizeof(struct timerequest)); if(w) { ClearMenuStrip(w); CloseWindow(w); }; if(pw) CloseWindow(pw); if(s) { CloseScreen(s); /* FreeColorMap(cm); */ }; if(GfxBase) CloseLibrary(GfxBase); (void)OpenWorkBench(); if(IntuitionBase) CloseLibrary(IntuitionBase); return(0); }