home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff280.lzh / CM / cm.c < prev    next >
C/C++ Source or Header  |  1989-11-20  |  29KB  |  1,405 lines

  1. /*
  2.  * Celestial Mechanics Simulation Tool
  3.  *
  4.  *    W. John Guineau
  5.  *      3 Royal Crest Drive #9
  6.  *      Marlboro, Mass. 01752
  7.  *      (508) 485-6233
  8.  *
  9.  * Files:
  10.  *        cm.c
  11.  *        cm.h
  12.  *          cm.doc
  13.  *
  14.  * To Compile with Lattice 5.02:
  15.  *
  16.  *        lc -b0 -Lm cm
  17.  *
  18.  *
  19.  *                  NOTICE
  20.  *                  ------ 
  21.  *
  22.  *  I have placed this software in the Public Domain with the
  23.  * condition that all the files remain together and that I remain
  24.  * listed as the original author. This software may not be used for
  25.  * commercial purposes or to make money in any way without expressed
  26.  * written permission from the author (me). I'm including the source
  27.  * code so if you make any significant modifications please concider
  28.  * sending me a copy at the above address. I'd also be interested in
  29.  * any interesting saved setup files you create.
  30.  *
  31.  *
  32.  * This is my first Amiga program so I welcome any comments at all.
  33.  * I wrote this program as both a way to learn the Amiga environment
  34.  * and in response to a conversation I had with a friend on Celestial
  35.  * Mechanics.
  36.  *
  37.  *
  38.  */
  39.  
  40. #include <stdio.h>
  41. #include <ctype.h>
  42. #include <math.h>
  43.  
  44. #include <exec/types.h>
  45. #include <exec/ports.h>
  46. #include <exec/devices.h>
  47. #include <libraries/dosextens.h>
  48. #include <intuition/intuition.h>
  49. #include <intuition/intuitionbase.h>
  50. #include <graphics/rastport.h>
  51. #include <graphics/gfxbase.h>
  52. #include <graphics/gfx.h>
  53. #include <graphics/display.h>
  54. #include <graphics/text.h>
  55.  
  56.  
  57.  
  58.  
  59. #include "cm.h"
  60.  
  61.  
  62.  
  63. #define NOWAIT 0
  64. #define WAIT   1
  65.  
  66.  
  67. extern struct IntuitionBase *IntuitionBase;
  68. extern struct GfxBase *GfxBase;
  69. struct IntuiMessage *message;
  70.  
  71. struct Screen *s;
  72. struct Window *w;
  73. struct Window *pw;
  74. struct RastPort *rp;
  75. struct RastPort *prp;
  76. struct ViewPort *vp;
  77.  
  78.  
  79. #define ReqNone  0
  80. #define ReqBody  1
  81. #define ReqSetup 2
  82. #define ReqFile  3
  83. #define ReqAbout 4
  84.  
  85.  
  86. UBYTE  CancelHit=0;       /* If user selects CANCEL from Reqester */
  87. UBYTE  ReqActive=ReqNone;  /* Set when a Reqester is active */
  88.                /*  to keep DoIntuiEvents() from returning */
  89.                /*  until it gets a REQCLEAR msg */
  90.  
  91.  
  92. struct setup {
  93.    double   G;
  94.    double   ds;
  95.    double   dt;
  96.    UBYTE    t;
  97.    WORD     TrailLength;
  98.    UBYTE    ShowTime;
  99. } SI;
  100.  
  101. #define MAXTRAILEN 300
  102.    
  103. struct Body {            /* Info for a Celestial Body */
  104.    UBYTE    real;        /* If it's real */
  105.    UBYTE    fixed;        /* Body fixed in place */
  106.    UBYTE    pen;            /* Color Register */
  107.    char     name[10];        /* user given name */
  108.    ULONG    Radius;        /* radius */
  109.    double   Mass;        /* mass */
  110.    double   x,y;        /* current position */
  111.    double   Vx,Vy;        /* velocity components */
  112.    double   Fx,Fy;        /* resultant force components */
  113.    double   Dir;        /* direction angle (radians) */
  114.    double   TrailX[MAXTRAILEN]; /* X of trail of pixels to clear */
  115.    double   TrailY[MAXTRAILEN]; /* X of trail of pixels to clear */
  116.    WORD     TrailIDX;
  117. };
  118.  
  119.  
  120. #define MAXBODYS 10
  121. struct Body Bodys[MAXBODYS];         /* The array of bodys */
  122. BYTE   CurBody,TotalBodys=0;
  123.  
  124. ULONG    Et;                /* elapsed time */
  125.  
  126.  
  127. #define MODE_CREATE 1
  128. #define MODE_MODIFY 2
  129. #define MODE_START  3
  130. #define MODE_STOP   4
  131. UBYTE    mode = MODE_STOP;        /* Current simulation mode */
  132.  
  133.  
  134.  
  135.  
  136. /* pointer text for ShowMouse() */
  137. char    pbuf[80];
  138. struct IntuiText pos_txt = {
  139.    WHTPEN,BLKPEN,            /* FrontPen, BackPen */
  140.    JAM2,                /* DrawMode */
  141.    7,2,                  /* LeftEdge, TopEdge */
  142.    &TxtAt_Plain,            /* TextAttr */
  143.    pbuf,                /* IText */
  144.    NULL                 /* NextText */
  145. };
  146.  
  147.  
  148.  
  149. struct    MsgPort *TimerPort;        /* for Timer stuff */
  150. struct    timerequest *TR;
  151. UBYTE    TimerOpen=0;
  152.  
  153.  
  154.  
  155.  
  156.  
  157. /* ============================================================
  158.  *   Main
  159.  *
  160.  * ============================================================*/
  161.  
  162. main(argc,argv)
  163. int   argc;
  164. char  *argv[];
  165. {
  166.  
  167. OpenStuff();
  168. Init();
  169.  
  170. DoIntuiEvents(WAIT);
  171.  
  172. return(0);
  173.  
  174. }
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184. OpenStuff()
  185. {
  186.  
  187. TimerPort = (struct MsgPort *)CreatePort(0,0);
  188. if(TimerPort == 0) {
  189.    printf("Cant get a Timer Port\n");
  190.    CleanUp();
  191.    exit(10);
  192. };
  193.  
  194. TR = (struct timerequest *)CreateExtIO(TimerPort,
  195.                        sizeof(struct timerequest));
  196. if(TR == 0) {
  197.    printf("Cant get a Timer Request\n");
  198.    CleanUp();
  199.    exit(11);
  200. };
  201.  
  202.  
  203. if(OpenDevice(TIMERNAME,UNIT_VBLANK,TR,0) != 0) {
  204.    printf("Cant open Timer Device\n");
  205.    CleanUp();
  206.    exit(12);
  207. };
  208. TimerOpen = 1;
  209.  
  210.  
  211. if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0))) {
  212.    printf("no graphics library!!!\n");
  213.    CleanUp();
  214.    exit(13);
  215. };
  216.  
  217. if(!(IntuitionBase = (struct IntuitionBase *)
  218.                   OpenLibrary("intuition.library",0))) {
  219.    printf("no intuition here!!\n");
  220.    CleanUp();
  221.    exit(14);
  222. };
  223.  
  224.  
  225.  
  226. if (!(s = (struct Screen *)OpenScreen(&ns) )) {
  227.    printf("could not open the screen\n");
  228.    CleanUp();
  229.    exit(15);
  230. };
  231.  
  232.  
  233. /*
  234.  * set up color map for new screen
  235.  */
  236. vp = (struct ViewPort *)&s->ViewPort;
  237. LoadRGB4(vp,colortable,COLORS);
  238.  
  239. nw.Screen = s;         /* point to our screen */
  240. npw.Screen = s;         /* pointer window struct also */
  241.  
  242. if (!(w = (struct Window *)OpenWindow(&nw) )) {
  243.    printf("could not open the window\n");
  244.    CleanUp();
  245.    exit(16);
  246. };
  247.  
  248. rp = w->RPort;
  249. SetAPen(rp,WHTPEN);
  250.  
  251. SetMenuStrip(w,&Control);
  252.  
  253. return(0);
  254.  
  255. }
  256.  
  257.  
  258.  
  259. Init()
  260. {
  261.  
  262. SI.G = 6.67;
  263. SI.ds = 1.0;
  264. SI.dt = 1.0;
  265. SI.t = 0;
  266. SI.TrailLength = 0;
  267.  
  268. cancel_text.IText = cantxt;
  269.  
  270. OffMenu(w,MN_CStop);
  271. OffMenu(w,MN_EMod);
  272. OffMenu(w,MN_FSScr);
  273.  
  274.  
  275. ClearScreen();
  276. ClearBodys();
  277. SetupGADefaults();
  278. BodyGADefaults();
  279.  
  280. return(0);
  281.  
  282. }
  283.  
  284.  
  285.  
  286.  
  287. ClearScreen()
  288. {
  289.  
  290. SetRast(rp,0);
  291.  
  292. SetAPen(rp,WHTPEN);
  293.  
  294. return(0);
  295.  
  296. }
  297.  
  298.  
  299. DoIntuiEvents(wait)
  300. UBYTE wait;
  301. {
  302. ULONG  MessageClass;
  303. USHORT code,qual;
  304. struct Gadget *GAD;
  305. struct MsgPort *mp;
  306.  
  307. mp = w->UserPort;
  308.  
  309. for(;;) {
  310.  
  311.    if(message = (struct IntuiMessage *)GetMsg(w->UserPort)) {
  312.  
  313.       MessageClass = message->Class;
  314.       code = message->Code;
  315.       qual = message->Qualifier;
  316.       GAD = (struct Gadget *)message->IAddress;
  317.  
  318.       ReplyMsg(message);
  319.  
  320.       switch (MessageClass) {
  321.  
  322.      case GADGETUP      : DoGadget(GAD);
  323.                 break;
  324.  
  325.      case MENUPICK    : if(code != MENUNULL) {
  326.                                DoMenu(code);
  327.                             };
  328.                             break;
  329.  
  330.      case CLOSEWINDOW : CleanUp();
  331.                 exit(0);
  332.                 break;
  333.  
  334.      case MOUSEBUTTONS: if(code == SELECTDOWN) {
  335.                    MakeBody(w->GZZMouseX,w->GZZMouseY);
  336.                 };
  337.                 break;
  338.  
  339.      case MOUSEMOVE   : if(mode == MODE_CREATE) {
  340.                    ShowMouse(w->GZZMouseX,w->GZZMouseY);
  341.                 };
  342.                 break;
  343.  
  344.      case REQCLEAR      : 
  345.                 ReqActive = ReqNone;
  346.                 break;
  347.  
  348.      default      : 
  349.                 break;
  350.  
  351.       };
  352.  
  353.    } else {
  354.  
  355.       if(!wait&&!ReqActive) return(0);
  356.  
  357.       WaitPort(mp);
  358.  
  359.    };
  360.  
  361. };
  362. return(0);
  363. }
  364.  
  365.  
  366.  
  367. DoGadget(GAD)
  368. struct    Gadget *GAD;
  369. {
  370. ULONG    val;
  371. struct    StringInfo *info;
  372.  
  373.  
  374. info = (struct StringInfo *)GAD->SpecialInfo;
  375. val  = info->LongInt;
  376.  
  377. switch(GAD->GadgetID) {
  378.  
  379.    case NAMEGAD        : 
  380.                           ActivateGadget(&mass,w,&BodyInfo);
  381.                           break;
  382.    case RADIUSGAD       : 
  383.                           break;
  384.  
  385.    case MASSGAD         : 
  386.                           ActivateGadget(&velocity,w,&BodyInfo);
  387.                           break;
  388.  
  389.    case VELOCITYGAD     : 
  390.                           ActivateGadget(&direction,w,&BodyInfo);
  391.                           break;
  392.  
  393.    case DIRECTIONGAD    : 
  394.                           break;
  395.  
  396.    case OKGAD        : 
  397.               CancelHit=0;
  398.                           if(pw)
  399.                              WindowToFront(pw);
  400.               break;
  401.  
  402.    case CANCELGAD    : 
  403.               CancelHit=1;
  404.                           if(pw)
  405.                              WindowToFront(pw);
  406.               break;
  407.  
  408.    case RESETGAD        : 
  409.                           switch(ReqActive) {
  410.                              case ReqBody  : BodyGADefaults();
  411.                                              RefreshGadgets(&mass,
  412.                                                             w,&BodyInfo);
  413.                                              break;
  414.                              case ReqSetup : SetupGADefaults();
  415.                                              RefreshGadgets(&dt,
  416.                                                             w,&SetupInfo);
  417.                                              break;
  418.                             
  419.                           };
  420.                           break;
  421.  
  422.    case GGAD            : 
  423.                           ActivateGadget(&dt,w,&SetupInfo);
  424.                           break;
  425.  
  426.    case DTGAD           : 
  427.                           ActivateGadget(&t,w,&SetupInfo);
  428.                           break;
  429.  
  430.    case TGAD            : 
  431.                           ActivateGadget(&ds,w,&SetupInfo);
  432.                           break;
  433.  
  434.    case DSGAD           : 
  435.                           ActivateGadget(&tl,w,&SetupInfo);
  436.                           break;
  437.  
  438.    case TLGAD           : 
  439.                           break;
  440.  
  441.    case COLOR1GAD    : 
  442.                           Bodys[CurBody].pen = (UBYTE)GAD->UserData;
  443.                           break;
  444.    case COLOR2GAD    : 
  445.                           Bodys[CurBody].pen = (UBYTE)GAD->UserData;
  446.                           break;
  447.    case COLOR3GAD    : 
  448.                           Bodys[CurBody].pen = (UBYTE)GAD->UserData;
  449.                           break;
  450.    case COLOR4GAD    : 
  451.                           Bodys[CurBody].pen = (UBYTE)GAD->UserData;
  452.                           break;
  453.    case COLOR5GAD    : 
  454.                           Bodys[CurBody].pen = (UBYTE)GAD->UserData;
  455.                           break;
  456.    case COLOR6GAD    : 
  457.                           Bodys[CurBody].pen = (UBYTE)GAD->UserData;
  458.                           break;
  459.    case COLOR7GAD    : 
  460.                           Bodys[CurBody].pen = (UBYTE)GAD->UserData;
  461.                           break;
  462.    case FNOKGAD        : 
  463.                           CancelHit=0;
  464.                           break;
  465.    case FNCANGAD    : 
  466.                           CancelHit=1;
  467.                           break;
  468.    case STGAD        : if(st.Flags&SELECTED) {
  469.                              st.GadgetText = &yes_text;
  470.                              RefreshGadgets(&st,w,&SetupInfo);
  471.                              SI.ShowTime=1;
  472.                           } else {
  473.                              st.GadgetText = &no_text;
  474.                              RefreshGadgets(&st,w,&SetupInfo);
  475.                              SI.ShowTime=0;
  476.                           };
  477.                           break;
  478.    case FXGAD        : if(fixed.Flags&SELECTED) {
  479.                              fixed.GadgetText = &yes_text;
  480.                              RefreshGadgets(&fixed,w,&BodyInfo);
  481.                              Bodys[CurBody].fixed=1;
  482.                           } else {
  483.                              fixed.GadgetText = &no_text;
  484.                              RefreshGadgets(&fixed,w,&BodyInfo);
  485.                              Bodys[CurBody].fixed=0;
  486.                           };
  487.                           break;
  488.  
  489.    default        : 
  490.               break;
  491.  
  492. };
  493.  
  494. return(0);
  495. }
  496.  
  497.  
  498.  
  499. DoMenu(MN)
  500. USHORT MN;
  501. {
  502.  
  503. switch(MENUNUM(MN)) {
  504.  
  505.    case M_Control : 
  506.                     switch(ITEMNUM(MN)) { 
  507.  
  508.                        case I_Stop    : 
  509.                                         mode = MODE_STOP;
  510.                                         ClosePw();
  511.                             OffMenu(w,MN_CStop);
  512.                             OnMenu(w,MN_ECreate);
  513.                             OnMenu(w,MN_ESetup);
  514.                             OnMenu(w,MN_EMod);
  515.                             OnMenu(w,MN_EClearS);
  516.                             OnMenu(w,MN_EClearB);
  517.                                         OnMenu(w,MN_FSDat);
  518.                                         OnMenu(w,MN_FLDat);
  519.                                         OnMenu(w,MN_CStart);
  520.                                         break;
  521.                        case I_Start   : 
  522.                                         if(TotalBodys == 0) {
  523.                                MSG("No Bodys Created!!","OK","OK");
  524.                                break;
  525.                             };
  526.                             mode = MODE_START;
  527.                             ModifyIDCMP(w,IDCMPFL);
  528.                                         if(SI.ShowTime) OpenPw();
  529.                             OffMenu(w,MN_ECreate);
  530.                             OffMenu(w,MN_ESetup);
  531.                             OffMenu(w,MN_EMod);
  532.                             OffMenu(w,MN_CStart);
  533.                             OffMenu(w,MN_EClearS);
  534.                             OffMenu(w,MN_EClearB);
  535.                                         OffMenu(w,MN_FSDat);
  536.                                         OffMenu(w,MN_FLDat);
  537.                                         OnMenu(w,MN_CStop);
  538.                                DoSimulation();
  539.                                         break;
  540.                     };
  541.                     break;
  542.  
  543.    case M_Edit    :
  544.                     switch(ITEMNUM(MN)) {
  545.  
  546.                        case I_ClearB  : if(MSG("Really Clear Bodys?",
  547.                                                "YES!","NO!!")) {
  548.                                            ClearBodys();
  549.                                            OnMenu(w,MN_FSDat);
  550.                                            OnMenu(w,MN_FLDat);
  551.                                         };
  552.  
  553.                                         break;
  554.                        case I_ClearS  : 
  555.                                         ClearScreen();
  556.                                         break;
  557.                        case I_Modify  : 
  558.                                         mode = MODE_MODIFY;
  559.                                         ModifyBodys();
  560.                                         break;
  561.                        case I_Create  : 
  562.                                         mode = MODE_CREATE;
  563.                             ModifyIDCMP(w,IDCMPFL_MM);
  564.                                         OpenPw();
  565.                             OnMenu(w,MN_CStart);
  566.                             OnMenu(w,MN_EMod);
  567.                             OffMenu(w,MN_ECreate);
  568.                                         OffMenu(w,MN_FLDat);
  569.                                         cancel_text.IText = cantxt;
  570.                                         break;
  571.                        case I_Setup   : 
  572.                                         Request(&SetupInfo,w);
  573.                                         Sleep(0L,100000L);
  574.                                         ActivateGadget(&G,w,&SetupInfo);
  575.                                         ReqActive = ReqSetup;
  576.                                         DoIntuiEvents(NOWAIT);
  577.                                         cancel_text.IText = cantxt;
  578.                                         if(!CancelHit) GetSetupInfo();
  579.                                         break;
  580.                     };
  581.                     break;
  582.  
  583.    case M_File    :
  584.                     switch(ITEMNUM(MN)) {
  585.  
  586.                        case I_Exit    : 
  587.                                         CleanUp();
  588.                                         exit(0);
  589.                                         break;
  590.                        case I_SavScr  : 
  591.                                         break;
  592.                        case I_SavDat  : 
  593.                                         DoSaveData();
  594.                                         break;
  595.                        case I_LoadDat : 
  596.                                         DoLoadData();
  597.                                         break;
  598.                        case I_About   : 
  599.                                         Request(&RAbout,w);
  600.                                         ReqActive = ReqAbout;
  601.                                         DoIntuiEvents(NOWAIT);
  602.                                         break;
  603.                     };
  604.                     break;
  605.  
  606. };
  607.  
  608. return(0);
  609.  
  610. }
  611.  
  612.  
  613.  
  614. ShowMouse(x,y)
  615. SHORT x,y;
  616. {
  617.  
  618. if(x<0||y<0) return(0);
  619.  
  620. sprintf(pbuf,"  %.3e , %.3e",
  621.    (double)(x)*SI.ds,(double)(w->GZZHeight-y+1)*SI.ds);
  622. PrintIText(prp,&pos_txt,0,0);
  623.  
  624. return(0);
  625. }
  626.  
  627. OpenPw()
  628. {
  629.  
  630. if(pw) return(0);
  631.  
  632. if (!(pw = (struct Window *)OpenWindow(&npw) )) {
  633.    printf("could not open the pointer window\n");
  634.    CleanUp();
  635.    exit(17);
  636. };
  637.  
  638. prp = pw->RPort;
  639. SetAPen(prp,BLKPEN);
  640. SetBPen(prp,WHTPEN);
  641.  
  642. return(0);
  643.  
  644. }
  645.  
  646. ClosePw()
  647. {
  648. if(pw) CloseWindow(pw);
  649. pw = (struct Window *)NULL;
  650. return(0);
  651. }
  652.  
  653.  
  654.  
  655. GetBodyInfo()
  656. {
  657. double V;
  658.  
  659.  
  660. strcpy(Bodys[CurBody].name,name_sbuf);
  661.  
  662. if(sscanf(mass_sbuf,"%le",&Bodys[CurBody].Mass) != 1) {
  663.    MSG("Bad Value for Mass!","OK","OK");
  664.    return(0);
  665. };
  666.  
  667. Bodys[CurBody].Dir  =
  668.    (double)direction_txstr.LongInt * PI/180.0;
  669.  
  670. if(sscanf(velocity_sbuf,"%le",&V) != 1) {
  671.    MSG("Bad Value for Velocity!","OK","OK");
  672.    return(0);
  673. };
  674.  
  675. Bodys[CurBody].Vx  =
  676.    V * cos(Bodys[CurBody].Dir);
  677. Bodys[CurBody].Vy  =
  678.    V * sin(Bodys[CurBody].Dir);
  679.  
  680. if(Bodys[CurBody].pen == 0)
  681.    Bodys[CurBody].pen = WHTPEN;
  682.  
  683. Bodys[CurBody].Fx  =  0.0;
  684. Bodys[CurBody].Fy  =  0.0;
  685.  
  686.  
  687. return(0);
  688. }
  689.  
  690.  
  691.  
  692.  
  693.  
  694. GetSetupInfo()
  695. {
  696. WORD    n;
  697.  
  698. if(sscanf(G_sbuf,"%le",&SI.G) != 1) {
  699.    MSG("Bad Value for G!","OK","OK");
  700.    return(0);
  701. };
  702.  
  703. if(sscanf(ds_sbuf,"%le",&SI.ds) != 1) {
  704.    MSG("Bad Value for ds!","OK","OK");
  705.    return(0);
  706. };
  707.  
  708. if(sscanf(dt_sbuf,"%le",&SI.dt) != 1) {
  709.    MSG("Bad Value for dt!","OK","OK");
  710.    return(0);
  711. };
  712.  
  713. SI.t  = (UBYTE)t_txstr.LongInt;
  714.  
  715. n = (WORD)tl_txstr.LongInt;
  716. if(n>MAXTRAILEN) {
  717.    MSG("TrailLength too large!","OK","OK");
  718.    return(0);
  719. };
  720.  
  721. SI.TrailLength=n;
  722.  
  723. return(0);
  724. }
  725.  
  726.  
  727.  
  728.  
  729. MakeBody(x,y)
  730. SHORT x,y;
  731. {
  732.  
  733.  
  734. if(mode != MODE_CREATE)
  735.    return(0);
  736. if(x<0 || y<0)
  737.    return(0);
  738.  
  739. if(TotalBodys++ > MAXBODYS) {
  740.    TotalBodys--;
  741.    MSG("No More Body's Available!!","OK","OK");
  742.    return(0);
  743. };
  744.  
  745. SetAPen(rp,REDPEN);
  746. WritePixel(rp,x,y);
  747. CurBody = FindFreeBody();
  748. if(CurBody == -1) {
  749.    TotalBodys--;
  750.    MSG("No More Body's Available!!","OK","OK");
  751.    return(0);
  752. };
  753. cancel_text.IText = cantxt;
  754.  
  755. BodyGADefaults();
  756. sprintf(xy_buf," %.3e , %.3e ",
  757.    (double)(x)*SI.ds,(double)(w->GZZHeight-y+1)*SI.ds);
  758. Request(&BodyInfo,w);
  759. ReqActive = ReqBody;
  760. Sleep(0L,100000L);
  761. ActivateGadget(&name,w,&BodyInfo);
  762. DoIntuiEvents(NOWAIT);
  763.  
  764. if(CancelHit) {
  765.    TotalBodys--;
  766.    SetAPen(rp,BLKPEN);
  767.    WritePixel(rp,x,y);
  768.    return(0);
  769. };
  770.  
  771. GetBodyInfo();
  772.  
  773. if(Bodys[CurBody].Mass == 0.0) {
  774.    TotalBodys--;
  775.    SetAPen(rp,BLKPEN);
  776.    WritePixel(rp,x,y);
  777.    MSG("Mass can't be ZERO!!","OK","OK");
  778.    return(0);
  779. };
  780.  
  781. Bodys[CurBody].x = (double)(x)*SI.ds;
  782. Bodys[CurBody].y = (double)(y)*SI.ds;
  783. Bodys[CurBody].real = 1;
  784. SetAPen(rp,Bodys[CurBody].pen);
  785. WritePixel(rp,x,y);
  786.  
  787. return(0);
  788.  
  789. }
  790.  
  791. FindFreeBody()
  792. {
  793. int    x;
  794.  
  795. for(x=0 ; x<MAXBODYS ; x++)
  796.    if(!Bodys[x].real) return(x);
  797.  
  798. return(-1);
  799.  
  800. }
  801.  
  802.  
  803. ModifyBodys()
  804. {
  805. int     n;
  806. SHORT    x,y;
  807.  
  808.  
  809. mode = MODE_MODIFY;
  810. ModifyIDCMP(w,IDCMPFL);
  811. ClosePw();
  812. OffMenu(w,MN_CStart);
  813. OffMenu(w,MN_EMod);
  814. OffMenu(w,MN_ECreate);
  815. cancel_text.IText = deltxt;
  816.  
  817.  
  818. for(n=0 ; n<MAXBODYS ; n++) {
  819.  
  820.    CurBody = n;
  821.    if(Bodys[n].real) {
  822.  
  823.       Bodys[n].real=0;
  824.  
  825.       LoadBodyReq(n);
  826.       x = (SHORT)(Bodys[n].x/SI.ds);
  827.       y = (SHORT)(Bodys[n].y/SI.ds);
  828.  
  829.       color_text.FrontPen = Bodys[n].pen;
  830.       sprintf(xy_buf," %.3e , %.3e ",
  831.               (double)(x)*SI.ds,(double)(w->GZZHeight-y+1)*SI.ds);
  832.       Request(&BodyInfo,w);
  833.       Sleep(0L,100000L);
  834.       ReqActive = ReqBody;
  835.       ActivateGadget(&name,w,&BodyInfo);
  836.       DoIntuiEvents(NOWAIT);
  837.    
  838.       if(CancelHit) {        /* GAD really says "DELETE" */
  839.          TotalBodys--;
  840.          SetAPen(rp,BLKPEN);
  841.          WritePixel(rp,x,y);
  842.          continue;
  843.       };
  844.    
  845.       GetBodyInfo();
  846.    
  847.       if(Bodys[n].Mass == 0.0) {
  848.          TotalBodys--;
  849.          SetAPen(rp,BLKPEN);
  850.          WritePixel(rp,(SHORT)x,(SHORT)y);
  851.          MSG("Mass can't be ZERO!!","OK","OK");
  852.          continue;
  853.       };
  854.    
  855.       Bodys[n].real=1;
  856.       SetAPen(rp,Bodys[CurBody].pen);
  857.       WritePixel(rp,x,y);
  858.  
  859.    };
  860. };
  861.  
  862.  
  863. color_text.FrontPen = WHTPEN;
  864.  
  865. OnMenu(w,MN_CStart);
  866. OnMenu(w,MN_ECreate);
  867. if(TotalBodys)
  868.    OnMenu(w,MN_EMod);
  869. else
  870.    OffMenu(w,MN_EMod);
  871.  
  872. return(0);
  873.  
  874. }
  875.  
  876.  
  877.  
  878. LoadBodyReq(n)
  879. int    n;
  880. {
  881. double    v;
  882.  
  883. name_txstr.NumChars = sprintf(name_sbuf,"%s",Bodys[n].name);
  884. mass_txstr.NumChars = sprintf(mass_sbuf,"%.3e",Bodys[n].Mass);
  885.  
  886. direction_txstr.LongInt = (ULONG)(Bodys[n].Dir * 180.0/PI);
  887. direction_txstr.NumChars = sprintf(direction_sbuf,"%ld",
  888.                                    direction_txstr.LongInt);
  889.  
  890. v = Bodys[n].Vx*Bodys[n].Vx + Bodys[n].Vy*Bodys[n].Vy;
  891. v = sqrt(v);
  892. velocity_txstr.NumChars = sprintf(velocity_sbuf,"%.3e",v);
  893.  
  894. if(Bodys[n].fixed) {
  895.    fixed.GadgetText = &yes_text;
  896.    fixed.Flags |= SELECTED;
  897. } else {
  898.    fixed.GadgetText = &no_text;
  899.    fixed.Flags &= ~SELECTED;
  900. }
  901.  
  902. return(0);
  903. }
  904.  
  905.  
  906.  
  907.  
  908. DoSimulation()
  909. {
  910. UBYTE b;
  911. double     F,Fx=0.0,Fy=0.0,V;
  912.  
  913.  
  914. Et = 0L;
  915.  
  916. while(mode == MODE_START) {
  917.  
  918.  if(SI.ShowTime) {
  919.    sprintf(pbuf," Time  %ld",Et);
  920.    PrintIText(prp,&pos_txt,0,0);
  921.  };
  922.  
  923.  /*
  924.   * Calculate new directions & velocities
  925.   * resulting from all external forces (all other bodies)
  926.   */
  927.  
  928.  for(b=0 ; b<MAXBODYS ; b++ ) {
  929.  
  930.    if(!Bodys[b].real) continue;
  931.    if(Bodys[b].fixed) continue;
  932.  
  933.    GetForces(b,&Fx,&Fy);
  934.  
  935.    if(Fx != 0.0 && Fy != 0.0) {
  936.  
  937.       F = sqrt(Fx*Fx+Fy*Fy);           /* Total force on this body */
  938.                        /*  indirection of A */
  939.       V = F*SI.dt/Bodys[b].Mass;       /* FT = MV (impulse) */
  940.  
  941.       Bodys[b].Vx += V*Fx/F; /* Fx/F = cos(A). adj vel as a result of impulse */
  942.       Bodys[b].Vy += V*Fy/F; /* Fy/F = sin(A).  in direction of resultant Force */
  943.  
  944.       Bodys[b].Dir = atan2(Bodys[b].Vy,Bodys[b].Vx);  /* new direction */
  945.       if(Bodys[b].Dir < 0.0)
  946.      Bodys[b].Dir += 2.0*PI;
  947.    };
  948.  
  949.  
  950.  };
  951.  
  952.  /*
  953.   * Display new positions
  954.   */
  955.  
  956.  for(b=0 ; b<MAXBODYS ; b++) {
  957.  
  958.    if(!Bodys[b].real) continue;
  959.  
  960.    if(!SI.TrailLength) {
  961.       SetAPen(rp,BLKPEN);
  962.       WritePixel(rp,(SHORT)(Bodys[b].x/SI.ds),(SHORT)(Bodys[b].y/SI.ds));
  963.    } else {
  964.       if(SI.TrailLength>0) {
  965.          if(Bodys[b].TrailIDX >= SI.TrailLength)
  966.             Bodys[b].TrailIDX=0;
  967.          if(Bodys[b].TrailX[Bodys[b].TrailIDX]>=0) {
  968.             SetAPen(rp,BLKPEN);
  969.             WritePixel(rp,(SHORT)(Bodys[b].TrailX[Bodys[b].TrailIDX]/SI.ds),
  970.                           (SHORT)(Bodys[b].TrailY[Bodys[b].TrailIDX]/SI.ds));
  971.             
  972.          };
  973.          Bodys[b].TrailX[Bodys[b].TrailIDX] = Bodys[b].x;
  974.          Bodys[b].TrailY[Bodys[b].TrailIDX] = Bodys[b].y;
  975.          Bodys[b].TrailIDX++;
  976.       };
  977.    };
  978.  
  979.    Bodys[b].x += (Bodys[b].Vx * SI.dt);
  980.    Bodys[b].y -= (Bodys[b].Vy * SI.dt);
  981.  
  982.    SetAPen(rp,Bodys[b].pen);
  983.    WritePixel(rp,(SHORT)(Bodys[b].x/SI.ds),(SHORT)(Bodys[b].y/SI.ds));
  984.  
  985.  };
  986.  
  987. DoIntuiEvents(NOWAIT);
  988.  
  989. if(SI.t)
  990.    Sleep(0L,(ULONG)SI.t*1000L);
  991.  
  992. Et++;
  993.  
  994. };
  995.  
  996. return(0);
  997. }
  998.  
  999.  
  1000. GetForces(b,fx,fy)
  1001. UBYTE b;
  1002. double *fx,*fy;
  1003. {
  1004. int x;
  1005. double dY,dX,Fx,Fy,F,R;
  1006.  
  1007. Fx = Fy = 0.0;
  1008. for(x=0 ; x<MAXBODYS ; x++) {
  1009.  
  1010.    if(x==b) continue;
  1011.    if(!Bodys[x].real) continue;
  1012.  
  1013.    dX =  (Bodys[x].x - Bodys[b].x) * SI.ds; /* X2 - X1 */
  1014.    dY =  (Bodys[b].y - Bodys[x].y) * SI.ds; /* Y2 - Y1 BUT */
  1015.                          /* normalized to bottom */
  1016.                          /* left of window */
  1017.  
  1018.    R = dX*dX+dY*dY;    /* part of sqrt(x^2+y^2) */
  1019.             /* for F calc below. F needs R^2 so we'll */
  1020.             /* do sqrt() part after (sqrt(x)^2 = x) */
  1021.  
  1022.    F =    SI.G * (Bodys[b].Mass * Bodys[x].Mass) / R;
  1023.  
  1024.    R = sqrt(R);         /* distance between points */
  1025.  
  1026.    Fx += F*(dX/R);    /* dX/R = cos(A) but faster */
  1027.    Fy += F*(dY/R);    /* dY/R = sin(A) but faster */
  1028.  
  1029. };
  1030.  
  1031. *fx = Fx;
  1032. *fy = Fy;
  1033.  
  1034. return(0);
  1035. }
  1036.  
  1037.  
  1038. SetupGADefaults()
  1039. {
  1040.  
  1041. strcpy(G_sbuf,"6.67e0");
  1042. G_txstr.NumChars=6;
  1043.  
  1044. strcpy(t_sbuf,"0");
  1045. t_txstr.NumChars=1;
  1046. t_txstr.LongInt = 0L;
  1047.  
  1048. strcpy(ds_sbuf,"1.0e0");
  1049. ds_txstr.NumChars=5;
  1050.  
  1051. strcpy(dt_sbuf,"1.0e0");
  1052. dt_txstr.NumChars=5;
  1053.  
  1054. strcpy(tl_sbuf,"0");
  1055. dt_txstr.NumChars=1;
  1056.  
  1057. st.GadgetText = &no_text;
  1058. st.Flags &= ~SELECTED;
  1059.  
  1060. return(0);
  1061.  
  1062. }
  1063.  
  1064.  
  1065. BodyGADefaults()
  1066. {
  1067.  
  1068. strcpy(name_sbuf,"SUN");
  1069. name_txstr.NumChars=3;
  1070.  
  1071. strcpy(mass_sbuf,"1.0e0");
  1072. mass_txstr.NumChars=5;
  1073.  
  1074. strcpy(velocity_sbuf,"0.0e0");
  1075. velocity_txstr.NumChars=5;
  1076.  
  1077. strcpy(direction_sbuf,"0");
  1078. direction_txstr.NumChars=1;
  1079. direction_txstr.LongInt = 0L;
  1080.  
  1081. fixed.GadgetText = &no_text;
  1082. fixed.Flags &= ~SELECTED;
  1083.  
  1084. return(0);
  1085.  
  1086. }
  1087.  
  1088.  
  1089.  
  1090. ClearBodys()
  1091. {
  1092. int    x,t;
  1093.  
  1094. for(x=0 ; x<MAXBODYS ; x++) {
  1095.    Bodys[x].real = 0;
  1096.    Bodys[x].pen = 0;
  1097.  
  1098.    for(t=0 ; t<MAXTRAILEN ; t++) {
  1099.       Bodys[x].TrailX[t]=-1.0;
  1100.       Bodys[x].TrailY[t]=-1.0;
  1101.    };
  1102.    Bodys[x].TrailIDX = 0;
  1103.  
  1104. };
  1105.  
  1106. ClearScreen();
  1107. TotalBodys = 0;
  1108.  
  1109. return(0);
  1110.  
  1111. }
  1112.  
  1113.  
  1114.  
  1115. DoSaveData()
  1116. {
  1117. int    x;
  1118. FILE    *fp;
  1119.  
  1120.  
  1121. Request(&FileName,w);
  1122. Sleep(0L,100000L);
  1123. ActivateGadget(&fn,w,&FileName);
  1124. ReqActive = ReqFile;
  1125. DoIntuiEvents(NOWAIT);
  1126.  
  1127. if(CancelHit)
  1128.    return(0);
  1129.  
  1130.  
  1131. fp = fopen(fn_sbuf,"w");
  1132. if(!fp) {
  1133.    MSG("Can't open output file!","OK!","OH WELL!");
  1134.    return(0);
  1135. };
  1136.  
  1137. fprintf(fp,"--- CM Setup Data ---\n");
  1138. fprintf(fp,"G=%.3e\n",SI.G);
  1139. fprintf(fp,"ds=%.3e\n",SI.ds);
  1140. fprintf(fp,"dt=%.3e\n",SI.dt);
  1141. fprintf(fp,"t=%d\n",(int)SI.t);
  1142. fprintf(fp,"TrailLength=%d\n",(int)SI.TrailLength);
  1143. fprintf(fp,"ShowTime=%d\n",(int)SI.ShowTime);
  1144.  
  1145.  
  1146. fprintf(fp,"--- CM Body Data ---\n");
  1147. fprintf(fp,"#=name ;pen;fixed;Radius;Mass;x,y;Vx,Vy;Dir\n");
  1148. for(x=0 ; x<MAXBODYS ; x++)
  1149.    if(Bodys[x].real) {
  1150.       fprintf(fp,"%d=%s ;%d;%d;%ld;%.3e;%.3e,%.3e;%.3e,%.3e;%.3e\n",
  1151.         x,
  1152.         Bodys[x].name,
  1153.         (int)Bodys[x].pen,
  1154.                 (int)Bodys[x].fixed,
  1155.         Bodys[x].Radius,
  1156.         Bodys[x].Mass,
  1157.         Bodys[x].x,w->GZZHeight-Bodys[x].y+1,
  1158.         Bodys[x].Vx,Bodys[x].Vy,
  1159.         Bodys[x].Dir*180.0/PI);
  1160.         
  1161.    };
  1162.  
  1163. fclose(fp);
  1164.  
  1165. return(0);
  1166.  
  1167. }
  1168.  
  1169.  
  1170.  
  1171. DoLoadData()
  1172. {
  1173. int    n;
  1174. FILE    *fp;
  1175. char    buf[101],name[10];
  1176. ULONG    pen,fixed,Radius;
  1177. double    x,y,Mass,Vx,Vy,Dir;
  1178.  
  1179.  
  1180. CancelHit=0;
  1181. Request(&FileName,w);
  1182. Sleep(0L,100000L);
  1183. ActivateGadget(&fn,w,&FileName);
  1184. ReqActive = ReqFile;
  1185. DoIntuiEvents(NOWAIT);
  1186.  
  1187. if(CancelHit)
  1188.    return(0);
  1189.  
  1190.  
  1191. fp = fopen(fn_sbuf,"r");
  1192. if(!fp) {
  1193.    MSG("Can't open Data File!","OK!","OH WELL!");
  1194.    return(0);
  1195. };
  1196.  
  1197. fgets(buf,100,fp);    /* forget first line, it's just a header */
  1198. fgets(buf,100,fp);
  1199. if(sscanf(buf,"G=%le\n",&SI.G) != 1) {
  1200.    MSG("Bad data file (G)!","OK!","OOPS!");
  1201.    fclose(fp);
  1202.    return(0);
  1203. };
  1204.  
  1205. fgets(buf,100,fp);
  1206. if(sscanf(buf,"ds=%le\n",&SI.ds) != 1) {
  1207.    MSG("Bad data file (ds)!","OK!","OOPS!");
  1208.    fclose(fp);
  1209.    return(0);
  1210. };
  1211.  
  1212. fgets(buf,100,fp);
  1213. if(sscanf(buf,"dt=%le\n",&SI.dt) != 1) {
  1214.    MSG("Bad data file (dt)!","OK!","OOPS!");
  1215.    fclose(fp);
  1216.    return(0);
  1217. };
  1218.  
  1219. fgets(buf,100,fp);
  1220. if(sscanf(buf,"t=%d\n",&n) != 1) {
  1221.    MSG("Bad data file (t)!","OK!","OOPS!");
  1222.    fclose(fp);
  1223.    return(0);
  1224. };
  1225. SI.t = (UBYTE)n;
  1226.  
  1227. fgets(buf,100,fp);
  1228. if(sscanf(buf,"TrailLength=%d\n",&n) != 1) {
  1229.    MSG("Bad data file (TrailLength)!","OK!","OOPS!");
  1230.    fclose(fp);
  1231.    return(0);
  1232. };
  1233.  
  1234. if(n>MAXTRAILEN) {
  1235.    MSG("TrailLength too big","OK!","OOPS!");
  1236.    fclose(fp);
  1237.    return(0);
  1238. };
  1239. SI.TrailLength = (WORD)n;
  1240.  
  1241. fgets(buf,100,fp);
  1242. if(sscanf(buf,"ShowTime=%d\n",&n) != 1) {
  1243.    MSG("Bad data file (ShowTime)!","OK!","OOPS!");
  1244.    fclose(fp);
  1245.    return(0);
  1246. };
  1247. SI.ShowTime = (WORD)n;
  1248. if(n) {
  1249.    st.GadgetText = &yes_text;
  1250.    st.Flags |= SELECTED;
  1251. } else {
  1252.    st.GadgetText = &no_text;
  1253.    st.Flags &= ~SELECTED;
  1254. };   
  1255.  
  1256.  
  1257. G_txstr.NumChars  = sprintf(G_sbuf,"%.3e",SI.G);
  1258. dt_txstr.NumChars = sprintf(dt_sbuf,"%.3e",SI.dt);
  1259. t_txstr.NumChars  = sprintf(t_sbuf,"%d",SI.t);
  1260. t_txstr.LongInt   = (ULONG)SI.t;
  1261. ds_txstr.NumChars = sprintf(ds_sbuf,"%.3e",SI.ds);
  1262. tl_txstr.LongInt  = (LONG)SI.TrailLength; 
  1263. tl_txstr.NumChars = sprintf(tl_sbuf,"%d",SI.TrailLength);
  1264.  
  1265. ClearBodys();
  1266.  
  1267. fgets(buf,100,fp);
  1268. fgets(buf,100,fp);
  1269.  
  1270. while(fgets(buf,100,fp) != (char *)NULL) {
  1271.    if(sscanf(buf,"%d=%s;%d;%d;%ld;%le;%le,%le;%le,%le;%le",
  1272.              &n,name,&pen,&fixed,&Radius,&Mass,&x,&y,&Vx,&Vy,&Dir) != 11) {
  1273.       MSG("Bad Body in data file","OK!","OOPS!");
  1274.       fclose(fp);
  1275.       return(0);
  1276.    };
  1277.    if(n>MAXBODYS) {
  1278.       MSG("Bad Body # in data file","OK!","OOPS!");
  1279.       fclose(fp);
  1280.       return(0);
  1281.    };
  1282.  
  1283.    if(!Bodys[n].real) TotalBodys++; /* don't count same definition twice */
  1284.    Bodys[n].real   = 1;
  1285.    Bodys[n].pen    = pen;
  1286.    Bodys[n].fixed  = fixed;
  1287.    Bodys[n].Radius = Radius; 
  1288.    Bodys[n].Mass   = Mass;
  1289.    Bodys[n].x      = x;
  1290.    Bodys[n].y      = w->GZZHeight-y+1;
  1291.    Bodys[n].Vx     = Vx;
  1292.    Bodys[n].Vy     = Vy;
  1293.    Bodys[n].Dir    = Dir*PI/180.0;
  1294.    strcpy(Bodys[n].name,name);
  1295.  
  1296.    SetAPen(rp,pen);
  1297.    WritePixel(rp,(SHORT)(Bodys[n].x/SI.ds),(SHORT)(Bodys[n].y/SI.ds));
  1298.         
  1299. };
  1300.  
  1301. fclose(fp);
  1302.  
  1303. OnMenu(w,MN_ECreate);
  1304. OnMenu(w,MN_EMod);
  1305.  
  1306.  
  1307. return(0);
  1308.  
  1309. }
  1310.  
  1311.  
  1312. MSG(msg,p,n)
  1313. char    *msg,*p,*n;
  1314. {
  1315.  
  1316. struct IntuiText msg_txt = {
  1317.    BLKPEN,REDPEN,            /* FrontPen, BackPen */
  1318.    JAM1,                /* DrawMode */
  1319.    10,20,                  /* LeftEdge, TopEdge */
  1320.    &TxtAt_Plain,            /* TextAttr */
  1321.    0,                    /* IText */
  1322.    NULL                 /* NextText */
  1323. };
  1324.  
  1325. struct IntuiText pos_txt = {
  1326.    BLKPEN,REDPEN,            /* FrontPen, BackPen */
  1327.    JAM1,                /* DrawMode */
  1328.    3,3,                 /* LeftEdge, TopEdge */
  1329.    &TxtAt_Plain,            /* TextAttr */
  1330.    0,                    /* IText */
  1331.    NULL                 /* NextText */
  1332. };
  1333.  
  1334. struct IntuiText neg_txt = {
  1335.    BLKPEN,REDPEN,            /* FrontPen, BackPen */
  1336.    JAM1,                /* DrawMode */
  1337.    3,3,                 /* LeftEdge, TopEdge */
  1338.    &TxtAt_Plain,            /* TextAttr */
  1339.    0,                    /* IText */
  1340.    NULL                 /* NextText */
  1341. };
  1342.  
  1343. msg_txt.IText = msg;
  1344. pos_txt.IText = p;
  1345. neg_txt.IText = n;
  1346.  
  1347.  
  1348. return(AutoRequest(w,&msg_txt,&pos_txt,&neg_txt,
  1349.            NULL,NULL,40+IntuiTextLength(&msg_txt),80));
  1350.  
  1351. }
  1352.  
  1353.  
  1354.  
  1355.  
  1356.  
  1357.  
  1358. Sleep(secs,usecs)
  1359. ULONG    secs,usecs;
  1360. {
  1361.  
  1362. TR->tr_node.io_Command = TR_ADDREQUEST;
  1363. TR->tr_time.tv_secs = secs;
  1364. TR->tr_time.tv_micro = usecs;
  1365. DoIO(TR);
  1366.  
  1367. return(0);
  1368.  
  1369. }
  1370.  
  1371.  
  1372.  
  1373.  
  1374.  
  1375. CleanUp()
  1376. {
  1377.  
  1378. if(TimerPort) DeletePort(TimerPort);
  1379. if(TimerOpen) CloseDevice(TR);
  1380. if(TR) DeleteExtIO(TR,sizeof(struct timerequest));
  1381. if(w) {
  1382.    ClearMenuStrip(w);
  1383.    CloseWindow(w);
  1384. };
  1385. if(pw) CloseWindow(pw);
  1386. if(s) {
  1387.    CloseScreen(s);
  1388. /*   FreeColorMap(cm); */
  1389. };
  1390. if(GfxBase) CloseLibrary(GfxBase);
  1391. (void)OpenWorkBench();
  1392. if(IntuitionBase) CloseLibrary(IntuitionBase);
  1393. return(0);
  1394. }
  1395.  
  1396.  
  1397.  
  1398.  
  1399.  
  1400.  
  1401.  
  1402.  
  1403.  
  1404.  
  1405.