class MyMass:CMass { F64 radius; }; class MySpring:CSpring { }; CMathODE *ode=NULL; U0 DrawIt(CTask *,CDC *dc) { MyMass *tmpm; MySpring *tmps; dc->color=RED; tmps=ode->next_spring; while (tmps!=&ode->next_spring) { GrLine(dc,tmps->end1->x,tmps->end1->y,tmps->end2->x,tmps->end2->y); tmps=tmps->next; } dc->color=BLACK; tmpm=ode->next_mass; while (tmpm!=&ode->next_mass) { GrCircle(dc,tmpm->x,tmpm->y,tmpm->radius); tmpm=tmpm->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 *tmpm1,*tmpm2; tmpm1=ode->next_mass; while (tmpm1!=&ode->next_mass) { tmpm2=tmpm1->next; while (tmpm2!=&ode->next_mass) { D3Sub(&p,&tmpm2->state->x,&tmpm1->state->x); dd=D3NormSqr(&p); if (dd<=Sqr(tmpm1->radius+tmpm2->radius)) { d=Sqrt(dd)+0.0001; dd=10.0*Sqr(Sqr(Sqr(tmpm1->radius+tmpm2->radius)-dd)); D3MulEqu(&p,dd/d); D3AddEqu(&tmpm2->DstateDt->DxDt,&p); D3SubEqu(&tmpm1->DstateDt->DxDt,&p); } tmpm2=tmpm2->next; } tmpm1=tmpm1->next; } } U0 PlaceMass(I64 x, I64 y) { MyMass *tmpm=CAlloc(sizeof(MyMass)); tmpm->mass=1.0; tmpm->drag_profile_factor=100.0; tmpm->x=x; tmpm->y=y; tmpm->radius=10*(Rand+0.25); QueIns(tmpm,ode->last_mass); } U0 PlaceSpring(MyMass *tmpm1,MyMass *tmpm2) { MySpring *tmps=CAlloc(sizeof(MySpring)); tmps->end1=tmpm1; tmps->end2=tmpm2; tmps->const=10000; tmps->rest_len=100; QueIns(tmps,ode->last_spring); } U0 Init() { ode=ODENew(0,1e-4,ODEF_HAS_MASSES); ode->derive=&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,arg1,arg2; MyMass *tmpm1=NULL,*tmpm2=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 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(&arg1,&arg2, 1<<MSG_MS_L_DOWN|1<<MSG_MS_R_DOWN|1<<MSG_MS_R_UP|1<<MSG_KEY_DOWN); switch (msg_code) { case MSG_MS_L_DOWN: PlaceMass(arg1,arg2); break; case MSG_MS_R_DOWN: tmpm1=MassFind(ode,arg1,arg2); tmpm2=NULL; break; case MSG_MS_R_UP: if (tmpm1 && (tmpm2=MassFind(ode,arg1,arg2)) && tmpm1!=tmpm2) PlaceSpring(tmpm1,tmpm2); tmpm1=tmpm2=NULL; break; case MSG_KEY_DOWN: switch (arg1) { case '\n': CleanUp; Init; break; case CH_SHIFT_ESC: case CH_ESC: goto ms_done; } break; } } ms_done: //Don't goto out of try GetMsg(,,1<<MSG_KEY_UP); } catch PutExcept; SettingsPop; CleanUp; MenuPop; } MassSpringDemo;