class MyMass:CMass { F64 radius; }; class MySpring:CSpring { }; CMathODE *ode=NULL; U0 DrawIt(CTask *,CDC *dc) { MyMass *tempm; MySpring *temps; dc->color=RED; temps=ode->next_spring; while (temps!=&ode->next_spring) { GrLine(dc,temps->end1->x,temps->end1->y, temps->end2->x,temps->end2->y); temps=temps->next; } dc->color=BLACK; tempm=ode->next_mass; while (tempm!=&ode->next_mass) { GrCircle(dc,tempm->x,tempm->y,tempm->radius); tempm=tempm->next; } } U0 MyDerivative(CMathODE *ode,F64,COrder2D3 *,COrder2D3 *) {//The forces due to springs and drag are //automatically handled by the ode code. //We can add new forces here. F64 d,dd; CD3 p; MyMass *tempm1,*tempm2; tempm1=ode->next_mass; while (tempm1!=&ode->next_mass) { tempm2=tempm1->next; while (tempm2!=&ode->next_mass) { D3Sub(&tempm2->state->x,&tempm1->state->x,&p); dd=D3NormSqr(&p); if (dd<=Sqr(tempm1->radius+tempm2->radius)) { d=Sqrt(dd)+0.0001; dd=10.0*Sqr(Sqr(Sqr(tempm1->radius+tempm2->radius)-dd)); D3MulEqu(&p,dd/d); D3AddEqu(&tempm2->DstateDt->DxDt,&p); D3SubEqu(&tempm1->DstateDt->DxDt,&p); } tempm2=tempm2->next; } tempm1=tempm1->next; } } U0 PlaceMass(I64 x, I64 y) { MyMass *tempm=CAlloc(sizeof(MyMass)); tempm->mass=1.0; tempm->drag_profile_factor=100.0; tempm->x=x; tempm->y=y; tempm->radius=10*(Rand+0.25); QueIns(tempm,ode->last_mass); } U0 PlaceSpring(MyMass *tempm1,MyMass *tempm2) { MySpring *temps=CAlloc(sizeof(MySpring)); temps->end1=tempm1; temps->end2=tempm2; temps->const=10000; temps->rest_len=100; QueIns(temps,ode->last_spring); } U0 Init() { ode=ODENew(0,1e-4,ODEF_HAS_MASSES); ode->derivative=&MyDerivative; ode->drag_v2=0.002; ode->drag_v3=0.00001; ode->acceleration_limit=5e3; QueIns(ode,Fs->last_ode); } U0 CleanUp() { QueRem(ode); QueDel(&ode->next_mass,TRUE); QueDel(&ode->next_spring,TRUE); ODEDel(ode); } U0 MassSpringDemo() { I64 msg_code,a1,a2; MyMass *tempm1=NULL,*tempm2=NULL; PopUpOk("Left-Click to place mas\n" "Right-Click and drag to\n" "connect with spring.\n\n" "Springs are 100 pixs long.\n"); SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$ AutoComplete; WinBorder; WinMax; DocCursor; DocClear; Fs->win_inhibit|=WIG_DBL_CLICK; MenuPush( "File {" " Abort(,CH_SHIFT_ESC);" " Exit(,CH_ESC);" "}" "Play {" " Restart(,'\n');" "}" ); Init; Fs->draw_it=&DrawIt; try { while (TRUE) { msg_code=GetMsg(&a1,&a2, 1<