F64 SpanTime()
{
if (run_bttn.state)
return a.elapsed_t+tS-a.start_wall_t;
else
return a.elapsed_t;
}
F64 Cost(CMathODE *ode)
{
MyMass *tmpm;
MySpring *tmps;
F64 res=0;
tmpm=ode->next_mass;
while (tmpm!=&ode->next_mass) {
res+=tmpm->cost;
tmpm=tmpm->next;
}
tmps=ode->next_spring;
while (tmps!=&ode->next_spring) {
res+=tmps->cost;
tmps=tmps->next;
}
return res;
}
U0 DrawIt(CTask *task,CDC *dc)
{
MyMass *tmpm;
MySpring *tmps;
tmps=ode->next_spring;
while (tmps!=&ode->next_spring) {
if (!(tmps->flags&SSF_INACTIVE)) {
dc->color=tmps->color;
dc->thick=tmps->thick;
GrLine3(dc,tmps->end1->x,tmps->end1->y,0,
tmps->end2->x,tmps->end2->y,0);
}
tmps=tmps->next;
}
if (cursor_mass) {
dc->color=RED;
dc->thick=2;
GrLine3(dc,ms.pos.x-task->pix_left-task->scroll_x,
ms.pos.y-task->pix_top-task->scroll_y,0,
cursor_mass->x,cursor_mass->y,0);
}
tmpm=ode->next_mass;
while (tmpm!=&ode->next_mass) {
if (!(tmpm->flags&MSF_INACTIVE)) {
dc->color=BLACK;
GrCircle(dc,tmpm->x,tmpm->y,tmpm->radius);
GrFloodFill(dc,tmpm->x,tmpm->y,TRUE);
dc->color=tmpm->color;
GrCircle(dc,tmpm->x,tmpm->y,tmpm->radius);
GrFloodFill(dc,tmpm->x,tmpm->y,TRUE);
dc->color=BLACK;
GrCircle(dc,tmpm->x,tmpm->y,tmpm->radius);
}
tmpm=tmpm->next;
}
dc->color=BLACK;
GrPrint(dc,90,0,"Cost:%12.2,f",Cost(ode));
GrPrint(dc,90,FONT_HEIGHT,"Time:%12.2f",SpanTime);
}
MyMass *PlaceMass(I64 x, I64 y)
{
MyMass *tmpm=CAlloc(sizeof(MyMass));
tmpm->drag_profile_factor=1.0;
tmpm->x=x;
tmpm->y=y;
tmpm->mass=MASS_MASS;
tmpm->radius=MASS_RADIUS;
tmpm->cost=25.0*COST_SCALE;
tmpm->color=YELLOW;
QueIns(tmpm,ode->last_mass);
return tmpm;
}
U0 NullSpring(MySpring *tmps,F64 scale)
{
F64 d=D3Dist(&tmps->end1->x,&tmps->end2->x);
tmps->rest_len=d*scale;
tmps->compression_strength=
tmps->base_compression_strength/(tmps->rest_len+1.0);
tmps->tensile_strength=tmps->base_tensile_strength/(tmps->rest_len+1.0);
tmps->const=tmps->base_const/(tmps->rest_len+1.0);
tmps->cost=tmps->base_cost*tmps->rest_len;
}
U0 MoveMass(MyMass *tmpm,I64 x, I64 y)
{
MySpring *tmps;
tmpm->x=x;
tmpm->y=y;
tmpm->DxDt=0;
tmpm->DyDt=0;
tmps=ode->next_spring;
while (tmps!=&ode->next_spring) {
if (tmps->end1==tmpm || tmps->end2==tmpm) {
if (tmps->flags&SSF_NO_COMPRESSION)
NullSpring(tmps,WIRE_PERCENT);
else
NullSpring(tmps,1.0);
}
tmps=tmps->next;
}
}
U0 DelSpring(MySpring *tmps)
{
QueRem(tmps);
Free(tmps);
}
U0 DelMass(MyMass *tmpm)
{
MySpring *tmps,*tmps1;
tmps=ode->next_spring;
while (tmps!=&ode->next_spring) {
tmps1=tmps->next;
if (tmps->end1==tmpm || tmps->end2==tmpm)
DelSpring(tmps);
tmps=tmps1;
}
QueRem(tmpm);
Free(tmpm);
}
U0 DrawSpring(CDC *dc,MyMass *tmpm,I64 x,I64 y)
{
switch (mode_bttn.state) {
case MD_CONCRETE:
dc->color=LTGRAY;
dc->thick=2;
break;
case MD_STEEL:
dc->color=DKGRAY;
dc->thick=2;
break;
case MD_WIRE:
dc->color=RED;
dc->thick=1;
break;
}
GrLine3(dc,tmpm->x,tmpm->y,0,x,y,0);
}
U0 PlaceSpring(MyMass *tmpm1,MyMass *tmpm2)
{
MySpring *tmps=CAlloc(sizeof(MySpring));
tmps->end1=tmpm1;
tmps->end2=tmpm2;
switch (mode_bttn.state) {
case MD_CONCRETE:
tmps->base_const = 3.00*SPRING_SCALE;
tmps->base_compression_strength=10.00*STRENGTH_SCALE;
tmps->base_tensile_strength = 0.35*STRENGTH_SCALE;
tmps->base_cost = 0.30*COST_SCALE;
NullSpring(tmps,1.0);
tmps->color=LTGRAY;
tmps->thick=2;
break;
case MD_STEEL:
tmps->base_const = 1.00*SPRING_SCALE;
tmps->base_compression_strength= 1.00*STRENGTH_SCALE;
tmps->base_tensile_strength = 1.00*STRENGTH_SCALE;
tmps->base_cost = 1.00*COST_SCALE;
NullSpring(tmps,1.0);
tmps->color=DKGRAY;
tmps->thick=2;
break;
case MD_WIRE:
tmps->base_const = 0.25*SPRING_SCALE;
tmps->base_compression_strength= 0.00;
tmps->base_tensile_strength = 0.50*STRENGTH_SCALE;
tmps->base_cost = 0.10*COST_SCALE;
NullSpring(tmps,WIRE_PERCENT);
tmps->color=RED;
tmps->thick=1;
tmps->flags|=SSF_NO_COMPRESSION;
break;
}
QueIns(tmps,ode->last_spring);
}
U0 AnimateTask(SpanAnimateStruct *a)
{
MySpring *tmps,*tmps1;
Bool old_run=FALSE;
F64 f;
while (TRUE) {
tmps=ode->next_spring;
while (tmps!=&ode->next_spring) {
tmps1=tmps->next;
f=tmps->f;
if (f>0 && f>tmps->compression_strength &&
!(tmps->flags&SSF_NO_COMPRESSION)||
f<0 && -f>tmps->tensile_strength &&
!(tmps->flags&SSF_NO_TENSION))
tmps->flags|=SSF_INACTIVE;
tmps=tmps1;
}
AdjustLoads(ode);
Refresh; //CMathODE updated once per refresh.
if (old_run!=run_bttn.state) {
if (run_bttn.state) {
if (!a->elapsed_t || !a->saved_ode) {
Free(a->saved_ode);
a->saved_ode=SpanSave(ode);
}
a->start_wall_t=tS;
ODEPause(ode,OFF);
} else {
ODEPause(ode);
a->elapsed_t+=tS-a->start_wall_t;
}
old_run=run_bttn.state;
}
}
}
U0 Init(SpanAnimateStruct *a)
{
SpanDel(ode);
ode=SpanNew;
run_bttn.state=0;
Refresh(2); //Allow stop to reg in animate task.
if (a->saved_ode)
SpanLoad(ode,a->saved_ode);
else
SpanBridge1Init(ode);
a->elapsed_t=0;
cursor_mass=NULL;
}
U0 SongTask(I64)
{//Song by Terry A. Davis
Fs->task_end_cb=&SndTaskEndCB;
MusicSettingsRst;
music.tempo= 3.636;
music.stacatto_factor= 0.902;
while (TRUE) {
Play("5q.EeDqED4G5DhE");
Play("5q.EeDqED4G5DhE");
Play("5q.FeEFEqF4G5EhF");
Play("5q.FeEFEqF4G5EhF");
}
}
U0 Span()
{
I64 msg_code,arg1,arg2;
MyMass *tmpm1=NULL,*tmpm2=NULL;
MySpring *tmps;
CCtrl *bt_run,*bt_mode;
U8 *src;
CDC *dc=DCAlias;
SettingsPush; //See SettingsPush
Fs->text_attr=BROWN<<4+BLACK;
AutoComplete;
WinBorder;
WinMax;
DocCursor;
Fs->song_task=Spawn(&SongTask,NULL,"Song",,Fs);
bt_run =CtrlBttnNew(0,0, 80,,
2,"Stopped\0Running\0",run_colors,&run_bttn);
bt_mode=CtrlBttnNew(0,3.0*FONT_HEIGHT,80,,
MD_MODES_NUM,Define("ST_SPAN_MODES"),mode_colors,&mode_bttn);
a.saved_ode=NULL;
Fs->win_inhibit|=WIG_DBL_CLICK;
MenuPush(
"File {"
" New(,CH_CTRLN);"
" Open(,CH_CTRLO);"
" SaveAs(,CH_CTRLA);"
" Abort(,CH_SHIFT_ESC);"
" Exit(,CH_ESC);"
"}"
"Play {"
" Restart(,'\n');"
" RunStop(,CH_SPACE);"
" Mass(,'m');"
" Concrete(,'c');"
" Steel(,'s');"
" Wire(,'w');"
" Move(,'v');"
" Delete(,'d');"
"}"
);
ode=NULL;
Init(&a);
Fs->animate_task=Spawn(&AnimateTask,&a,"Animate",,Fs);
Fs->draw_it=&DrawIt;
PopUpOk(
"Build a bridge to hold-up the\n"
"red masses.Test your design\n"
"by pressing run/stop.\n\n"
"The lowest cost bridge that\n"
"stays standing wins.\n\n"
"For a variation, try without\n"
"using the center base point.\n"
"\n"
"Use\n"
"\t$GREEN$'m'$FG$ass\n"
"\t$GREEN$'c'$FG$oncrete\n"
"\t$GREEN$'s'$FG$teel\n"
"\t$GREEN$'w'$FG$ire\n"
"\nto sel materials.\n");
try {
while (TRUE) {
msg_code=GetMsg(&arg1,&arg2,1<<MSG_MS_L_DOWN|1<<MSG_MS_R_DOWN|
1<<MSG_MS_L_UP|1<<MSG_KEY_DOWN|1<<MSG_MS_MOVE);
DCFill(dc);
switch (msg_code) {
case MSG_MS_L_DOWN:
cursor_mass=tmpm1=tmpm2=NULL;
switch (mode_bttn.state) {
case MD_MASS:
PlaceMass(arg1,arg2);
break;
case MD_CONCRETE:
case MD_STEEL:
case MD_WIRE:
tmpm1=MassFind(ode,arg1,arg2);
break;
case MD_MOVE:
if (run_bttn.state)
cursor_mass=MassFind(ode,arg1,arg2);
else
if (tmpm1=MassFind(ode,arg1,arg2))
MoveMass(tmpm1,arg1,arg2);
break;
case MD_DELETE:
MassOrSpringFind(ode,&tmpm1,&tmps,arg1,arg2);
if (tmpm1)
DelMass(tmpm1);
if (tmps)
DelSpring(tmps);
break;
}
break;
case MSG_MS_L_UP:
switch (mode_bttn.state) {
case MD_CONCRETE:
case MD_STEEL:
case MD_WIRE:
if (tmpm1 && (tmpm2=MassFind(ode,arg1,arg2)) && tmpm1!=tmpm2)
PlaceSpring(tmpm1,tmpm2);
break;
case MD_MOVE:
if (!run_bttn.state && tmpm1)
MoveMass(tmpm1,arg1,arg2);
break;
}
cursor_mass=tmpm1=tmpm2=NULL;
break;
case MSG_MS_MOVE:
switch (mode_bttn.state) {
case MD_MOVE:
if (!run_bttn.state && tmpm1)
MoveMass(tmpm1,arg1,arg2);
break;
case MD_CONCRETE:
case MD_STEEL:
case MD_WIRE:
if (tmpm1) {
DrawSpring(dc,tmpm1,arg1,arg2);
}
break;
}
break;
case MSG_MS_R_DOWN:
mode_bttn.state++;
if (mode_bttn.state>=MD_MODES_NUM)
mode_bttn.state=0;
cursor_mass=tmpm1=tmpm2=NULL;
break;
case MSG_KEY_DOWN:
switch (arg1) {
case '\n':
if (!SpanTime || !a.saved_ode) {
Free(a.saved_ode);
a.saved_ode=SpanSave(ode);
}
Init(&a);
break;
case CH_CTRLN:
Free(a.saved_ode);
a.saved_ode=NULL;
Init(&a);
break;
case CH_CTRLO:
if (src=SpanRead) {
Free(a.saved_ode);
a.saved_ode=src;
Init(&a);
}
break;
case CH_CTRLA:
if (!SpanTime || !a.saved_ode) {
Free(a.saved_ode);
a.saved_ode=SpanSave(ode);
}
Init(&a);
SpanWrite(ode);
break;
case CH_SPACE:
run_bttn.state=!run_bttn.state;
break;
case 'c':
mode_bttn.state=MD_CONCRETE;
break;
case 's':
mode_bttn.state=MD_STEEL;
break;
case 'w':
mode_bttn.state=MD_WIRE;
break;
case 'm':
mode_bttn.state=MD_MASS;
break;
case 'v':
mode_bttn.state=MD_MOVE;
break;
case 'd':
mode_bttn.state=MD_DELETE;
break;
case CH_ESC:
if (!SpanTime || !a.saved_ode) {
Free(a.saved_ode);
a.saved_ode=SpanSave(ode);
}
Init(&a);
SpanWrite(ode);
case CH_SHIFT_ESC:
goto span_done;
}
break;
}
}
span_done: //Don't goto out of try
GetMsg(,,1<<MSG_KEY_UP);
} catch
PutExcept;
DocClear;
SettingsPop;
CtrlBttnDel(bt_run);
CtrlBttnDel(bt_mode);
SpanDel(ode);
DCFill(dc);
DCDel(dc);
MenuPop;
}