修正版1のRK4で大ポカをやらかしていました…。
(全エネルギーが徐々に減っていたのは誤差なんかじゃなかった…。)
多分これで最後の修正になります。
修正版1のRK4で大ポカをやらかしていました…。
(全エネルギーが徐々に減っていたのは誤差なんかじゃなかった…。)
多分これで最後の修正になります。
#include "hsp3dish.as"
#packopt name "DPRK4"
/* モジュール認識 */
modDetect@mod_simuCfg
modDetect@mod_simu
/* 定数宣言 */
//#define hsproom
#define wsx 640 //("windowSizex") ウィンドウxサイズ
#define wsy 640
#packopt xsize wsx
#packopt ysize wsy
#define frmIntvl 16 //[ms] ("frameInterval") フレーム間隔
#define slfreq 2 //[ms] ("simulationLoopFrequency") シミュレーションループ周期
#define mtr2px 100.0 //[px/meter] ("meterToPixel") メートル→ピクセル 変換係数
#const Oxw wsx/2 //[px] ("OriginxOnWindow") 物理系原点のウィンドウ上でのx座標
#const Oyw wsy/2 //[px]
#define dt 0.01 //[s] タイムステップ
#const double hdt dt/2 //[s] ("half dt") dt/2
#define g 9.8 //[m/s^2]
#define σ 1.0 //[kg/m^2] 錘の面密度
#define mmin 0.1 //[kg] 質量の下限
#define mmax 25.0 //[kg] 〃上限
/* 変数初期化 */
/* エイリアス */
#define m1 m(0)
#define m2 m(1)
#define r1 r(0)
#define r2 r(1)
#define l1 l(0)
#define l2 l(1)
#define θ1 θ(0)
#define θ2 θ(1)
#define r1w rw(0)
#define r2w rw(1)
#define l1w lw(0)
#define l2w lw(1)
#define x1 x
#define x2 x(1)
#define y1 y
#define y2 y(1)
/* 物理系 */
m = 1.5,1.0 //[kg] m1,m2
r = sqrt(m1/σ/4/m_pi),sqrt(m2/σ/4/m_pi) //[m] おもり1,2の半径
l = 1.5,1.0 //[m] l1,l2
θ = deg2rad(45),deg2rad(90) //[rad] θ1,θ2
x = l1*sin(θ1),x+l2*sin(θ2)
y = l1*cos(θ1),y+l2*cos(θ2)
/* システム */
ddim PRESET,5,6
/* 起動 */
*boot
title "二重振り子シミュレーター"
exist "save/preset.dat" : if strsize = -1 : initPreset //プリセットデータが無ければ初期化する
goto *boot@mod_simuCfg
#module mod_simuCfg /* シミュレーション設定 */
#define wsx wsx@
#define wsy wsy@
#define frmIntvl frmIntvl@*3
#define mtr2px mtr2px@
#define Oxw Oxw@
#define Oyw Oyw@
//#define mmin mmin@
//#define mmax mmax@
#define m m@
#define m1 m@
#define m2 m@(1)
#define l1 l@
#define l2 l@(1)
#define θ1 θ@
#define θ2 θ@(1)
#define x1 x@
#define x2 x@(1)
#define y1 y@
#define y2 y@(1)
#define r r@
#define r1 r@
#define r2 r@(1)
#define rw rw@
#define r1w rw@
#define r2w rw@(1)
#define l1w lw@
#define l2w lw@(1)
#define x1w xw@
#define x2w xw@(1)
#define y1w yw@
#define y2w yw@(1)
#define fontsize 16
#define sxMS 300 //[px] ("sizexOfMassSlider") 質量調節スライダ(MS)の長さ
#define syMS 4 //[px] 〃太さ
#define sxMSK 8 //[px] ("sizexOfMassSliderKnob") MSつまみ(MSK)の横幅
#define syMSK 14 //[ps] 〃高さ
#deffunc local modDetect
return
*boot
LBTNDWN = 0 //汎用変数初期化
initUI
usrRqstStat = 0 //("userRequestStatus") ユーザーからの要求の状態。(0,1,2,3) = (通常,プリセットロード要求,プリセット保存要求,シミュレーション開始要求)
*main //メインループ
repeat
handleMassSlds //MS管理
handlePndlmDrg //おもりドラッグ管理
reflesh //画面更新
if usrRqstStat : break //ユーザーから新たなアクションの要求があるなら
await frmIntvl
loop
switch usrRqstStat
case 1
loadPreset
initUI
goto *boot
case 2
savePreset
initUI
goto *boot
swbreak
case 3
goto *boot@mod_simu
swbreak
default
fatalError
swend
stop
*btnIntrpt /* ボタン割り込みへの対応 */
usrRqstStat = 1+stat
return
#deffunc local initUI /* UI初期化 */
cls
font msgothic,fontsize
/* おもり */
r1w = r1*mtr2px : r2w = r2*mtr2px //[px] r1,r2の、ウィンドウ上での長さ
l1w = l1*mtr2px : l2w = l2*mtr2px //[px]
x1w = Oxw+x1*mtr2px : x2w = Oxw+x2*mtr2px //x1,x2の、ウィンドウ上での位置
y1w = Oyw+y1*mtr2px : y2w = Oyw+y2*mtr2px
/* MS */
MSV = m2MSV(m1),m2MSV(m2) ;MSの値。0.0~1.0。要素0,1はm1,m2のスライダに対応。
pxMSK = 140-sxMSK/2,pxMSK ;[px] MSつまみの左上x座標。要素0,1はm1,m2のスライダに対応。
pyMSK = wsy-5-fontsize*2+8+syMS/2-syMSK/2,pyMSK+fontsize ;〃y
/* 各種ボタン */
#define sxBtn 180 //("sizexOfButton") ボタンの横幅
#define syBtn 20
objsize sxBtn,syBtn
pos wsx-5-sxBtn,wsy-5-syBtn*3-2*2 : button gosub "プリセット読込",*btnIntrpt
pos wsx-5-sxBtn,wsy-5-syBtn*2-2 : button gosub "プリセット保存",*btnIntrpt
pos wsx-5-sxBtn,wsy-5-syBtn : button gosub "シミュレーション開始",*btnIntrpt
return
#deffunc local handleMassSlds /* MS管理ルーチン */
getkey LBTNDWN,1 : if LBTNDWN = 0 : return
repeat 2 /* MS1,2 */
if (pxMSK(cnt) <= mousex)&(mousex <= pxMSK(cnt)+sxMSK)&(pyMSK(cnt) <= mousey)&(mousey <= pyMSK(cnt)+syMSK) { //カーソルがつまみに重なっているなら
xofst = pxMSK(cnt)-mousex : yofst = pyMSK(cnt)-mousey //マウスカーソルに対するつまみの相対位置
lastmx = mousex //以前のマウスカーソルのx座標
cnt0 = cnt
repeat
getkey LBTNDWN,1 : if LBTNDWN = 0 : break
if mousex != lastmx { //マウスカーソルが横に動いたら
lastmx = mousex
pxMSK(cnt0) = limit(mousex+xofst, msv2pxMSK(0),msv2pxMSK(1)) //つまみ位置決定
MSV(cnt0) = pxMSK2msv(pxMSK(cnt0)) //MS値計算
m(cnt0) = MSV2m(MSV(cnt0)) //質量計算
r(cnt0) = m2r(m(cnt0)) : rw(cnt0) = r(cnt0)*mtr2px //半径計算
reflesh
}
await frmIntvl
loop
}
loop
return
#deffunc local handlePndlmDrg /* おもりドラッグ管理 */
getkey LBTNDWN,1 : if LBTNDWN = 0 : return
/* おもり2 */
if powf(x2w-mousex,2)+powf(y2w-mousey,2) <= powf(r2w,2) {
xmofst = x2w-mousex : ymofst = y2w-mousey
lastmx = mousex : lastmy = mousey
repeat
getkey LBTNDWN,1 : if LBTNDWN = 0 : break
if (mousex != lastmx)|(mousey != lastmy) {
lastmx = mousex : lastmy = mousey
x2w = mousex+xmofst : y2w = mousey+ymofst
calcPndlmPosFromUI
reflesh //画面更新
}
await frmIntvl
loop
}
/* おもり1 */
if powf(x1w-mousex,2)+powf(y1w-mousey,2) <= powf(r1w,2) { //マウスカーソルがおもりに重なっているなら
xmofst = x1w-mousex : ymofst = y1w-mousey //マウスカーソルに対するおもりの中心の相対位置
xRelPw = x2w-x1w : yRelPw = y2w-y1w //[px] おもり1に対する2の相対位置
lastmx = mousex : lastmy = mousey //以前のマウスカーソルの位置
repeat
getkey LBTNDWN,1 : if LBTNDWN = 0 : break
if (mousex != lastmx)|(mousey != lastmy) { //マウスカーソルが動いたら
lastmx = mousex : lastmy = mousey
x1w = mousex+xmofst : y1w = mousey+ymofst
x2w = x1w+xRelPw : y2w = y1w+yRelPw
calcPndlmPosFromUI
reflesh //画面更新
}
await frmIntvl
loop
}
return
#deffunc local calcPndlmPosFromUI /* ウィンドウ上でのおもりの位置からその他の位置情報をを計算 */
x1 = double(x1w-Oxw)/mtr2px : y1 = double(y1w-Oyw)/mtr2px
l1 = sqrt(x1*x1+y1*y1) : l1w = l1*mtr2px
θ1 = atan(x1,y1)
x2 = x1+double(x2w-x1w)/mtr2px : y2 = y1+double(y2w-y1w)/mtr2px
l2 = sqrt(powf(x2-x1,2)+powf(y2-y1,2)) : l2w = l2*mtr2px
θ2 = atan(x2-x1,y2-y1)
return
#deffunc local reflesh /* 再描画 */
redraw 0
color : boxf
drawCdntAx //座標軸
drawPndlms //振り子
drawInfos //各種情報
drawMassSlds //MS
redraw 1
return
#deffunc local drawMassSlds /* MS描画*/
repeat 2
ytmp = wsy-5-fontsize*(2-cnt)+8
color 100,100,100
boxf 140,ytmp, 140+sxMS,ytmp+syMS
pxMSK(cnt) = msv2pxMSK(MSV(cnt))
color 200,150,100
boxf pxMSK(cnt),pyMSK(cnt), pxMSK(cnt)+sxMSK,pyMSK(cnt)+syMSK
loop
return
#global
#module mod_simuCfg_2
//#define mtr2px mtr2px@
//#define Oxw Oxw@
//#define Oyw Oyw@
#define mmin mmin@
#define mmax mmax@
//#define θ1 θ@
//#define θ2 θ@(1)
//#define l1w lw@
//#define l2w lw@(1)
#define sxMS sxMS@mod_simuCfg //[px] ("sizexOfMassSlider") 質量調節スライダ(MS)の長さ
#define syMS syMS@mod_simuCfg //[px] 〃太さ
#define sxMSK sxMSK@mod_simuCfg //[px] ("sizexOfMassSliderKnob") MSつまみ(MSK)の横幅
#define syMSK syMSK@mod_simuCfg //[ps] 〃高さ
#defcfunc m2MSV double m //質量→MS値
return (m-mmin)/(mmax-mmin)
#defcfunc MSV2m double msv //MS値→質量
return mmin+msv*(mmax-mmin)
#defcfunc msv2pxMSK double msv //MS値→つまみの左上x座標
return 140+msv*sxMS-sxMSK/2
#defcfunc pxMSK2msv double pxMSK//MSつまみの左上座標→MS値
return double(pxMSK+sxMSK/2-140)/sxMS
#global
#module mod_commonCalc
#define σ σ@
#defcfunc m2r double m //質量→半径
return sqrt(m/σ/4/m_pi)
#global
#module mod_simu
#define wsx wsx@
#define wsy wsy@
#define slfreq slfreq@
#define frmIntvl frmIntvl@
#define mtr2px mtr2px@
#define Oxw Oxw@
#define Oyw Oyw@
#define dt dt@
#define hdt hdt@
#define g g@
#define m1 m@
#define m2 m@(1)
#define l1 l@
#define l2 l@(1)
#define θ1 θ@
#define θ2 θ@(1)
#define x1 x@
#define x2 x@(1)
#define y1 y@
#define y2 y@(1)
#define fontsize 16
#define numPtTrack 100 //("numberOfPointsOfTrack") おもり2軌跡点の記録数
#define TrkSmplngIntvl dt*2 //[s] ("TrackSamplingInterval") 軌跡サンプリング間隔
#deffunc local modDetect
return
*boot
initUI
usrRqstStat = 0 //("userRequestStatus") ユーザーからの要求の状態。(0,1) = (通常,シミュレーション終了要求)
simuStat = 1 //("simulationStatus") シミュレーションの状態。(0,1) = (停止,実行)
η = (m1+m2)/m2
ω1 = 0.0
ω2 = 0.0
x1 = l1*sin(θ1) : y1 = l1*cos(θ1)
x2 = x1+l2*sin(θ2) : y2 = y1+l2*cos(θ2)
/* おもり2の軌跡点 */
/*
おもり2の軌跡点は直近 numPtTRACK 個分を TRACK [numPtTRACK,2] 配列記録する。
フォーマットはリングバッファと同じ要領。frntTRACK に記録される位置を先頭とし、そこから numPtTRACK 個分描画する。
古い順に詰まっている。要素 (*,0),(*,1) はそれぞれ然るべき番号の軌跡点のx,y座標。
*/
ddim TRACK,numPtTrack,2
repeat numPtTrack : TRACK(cnt,0) = x2 : TRACK(cnt,1) = y2 : loop
frntTRACK = 0
*main
etls = 0.0 //[s] ("elapsedTimeFromLastStep") 前回ステップ計算からの経過時間
etlts = 0.0 //[s] ("elapsedTimeFromLastTrackSampling") 前回軌跡サンプリングからの経過時間
etlf = 0.0 //[ms] ("elapsedTimeFromLastFrame") 前回画面更新からの経過時間
repeat
if etls >= dt : step : etls = -0.001*slfreq //ステップ計算
if etlts >= TrkSmplngIntvl : handleTrack : etlts = -0.001*slfreq //軌跡サンプリング
if etlf >= frmIntvl : reflesh : etlf = -slfreq //画面更新
if usrRqstStat : break
await slfreq
if simuStat {
etls += 0.001*slfreq
etlts += 0.001*slfreq
}
etlf += slfreq
loop
goto *boot@mod_simuCfg
*btnIntrrpt /* ボタン割り込みへの対応 */
switch stat
case 0
simuStat = 0
objenable 0,0 : objenable 1,1
swbreak
case 1
simuStat = 1
objenable 0,1 : objenable 1,0
swbreak
case 2
usrRqstStat = 1
swend
return
#deffunc local initUI /* UI初期化 */
cls
font msgothic,fontsize
/* 各種ボタン */
#define sxBtn 180
#define syBtn 20
objsize sxBtn,syBtn
pos wsx-sxBtn-5,wsy-5-syBtn*3-2*2 : button gosub "停止",*btnIntrrpt
pos wsx-sxBtn-5,wsy-5-syBtn*2-2 : button gosub "再開",*btnIntrrpt : objenable 1,0
pos wsx-sxBtn-5,wsy-5-syBtn : button gosub "シミュレーション終了",*btnIntrrpt
return
#deffunc local step /* dt後の状態の計算 */
ξn = θ1,θ2,ω1,ω2 : k1 = f1(ξn),f2(ξn),f3(ξn),f4(ξn)
ξn2 = ξn+hdt*k1, ξn(1)+hdt*k1(1), ξn(2)+hdt*k1(2), ξn(3)+hdt*k1(3) : k2 = f1(ξn2),f2(ξn2),f3(ξn2),f4(ξn2)
ξn3 = ξn+hdt*k2, ξn(1)+hdt*k2(1), ξn(2)+hdt*k2(2), ξn(3)+hdt*k2(3) : k3 = f1(ξn3),f2(ξn3),f3(ξn3),f4(ξn3)
ξn4 = ξn+dt*k3, ξn(1)+dt*k3(1), ξn(2)+dt*k3(2), ξn(3)+dt*k3(3) : k4 = f1(ξn4),f2(ξn4),f3(ξn4),f4(ξn4)
θ1 += dt/6*(k1 + 2.0*k2 + 2.0*k3 + k4)
θ2 += dt/6*(k1(1) + 2.0*k2(1) + 2.0*k3(1) + k4(1))
ω1 += dt/6*(k1(2) + 2.0*k2(2) + 2.0*k3(2) + k4(2))
ω2 += dt/6*(k1(3) + 2.0*k2(3) + 2.0*k3(3) + k4(3))
x1 = l1*sin(θ1) : y1 = l1*cos(θ1)
x2 = x1+l2*sin(θ2) : y2 = y1+l2*cos(θ2)
return
#deffunc local reflesh /* 画面更新 */
redraw 0
color : boxf
drawCdntAx //座標軸
drawPndlms //振り子
drawTrack //軌跡
drawInfos : drawIndo2 //各種情報
redraw 1
return
#deffunc local drawIndo2 /* 各種情報の表示 */
color 200,200,200
U = calcU() : K = calcK() : E = U+K
pos 5,wsy-5-fontsize*9 : mes "U = "+strf("%6.2f", U)+" [J]"
pos 5,wsy-5-fontsize*8 : mes "K = "+strf("%6.2f", K)+" [J]"
pos 5,wsy-5-fontsize*7 : mes "E = "+strf("%6.2f", E)+" [J]"
return
#deffunc local handleTrack /* おもり2の軌跡の管理 */
TRACK(frntTRACK,0) = x2 : TRACK(frntTRACK,1) = y2
if frntTRACK = numPtTRACK-1 : frntTRACK = 0 : else : frntTRACK ++
return
#deffunc local drawTrack /* おもり2の軌跡の描画 */
i = frntTRACK
repeat numPtTrack
xtmp = Oxw+TRACK(i,0)*mtr2px-3,xtmp+6,xtmp+6,xtmp
ytmp = Oyw+TRACK(i,1)*mtr2px-3,ytmp,ytmp+6,ytmp+6
gmode 3, , ,256*cnt/numPtTRACK
color 50,100,255 : gsquare -1,xtmp,ytmp
if i = numPtTRACK-1 : i = 0 : else : i ++
loop
return
#defcfunc local calcU /* 全位置エネルギーの計算 */
return -(m1+m2)*g*l1*cos(θ1) - m2*g*l2*cos(θ2)
#defcfunc local calcK /* 全運動エネルギーの計算 */
return 0.5*(m1+m2)*l1*l1*ω1*ω1 + 0.5*m2*l2*l2*ω2*ω2 + m2*l1*l2*ω1*ω2*cos(θ1-θ2)
#global
#module mod_simu_2
#define dt dt@
#define hdt hdt@
#define g g@
#define l1 l@
#define l2 l@(1)
#define η η@mod_simu
#defcfunc f1 array ξ
return ξ(2)
#defcfunc f2 array ξ
return ξ(3)
#defcfunc f3 array ξ
θ1 = ξ : θ2 = ξ(1) : ω1 = ξ(2) : ω2 = ξ(3)
φ = θ1-θ2 : cosφ = cos(φ)
return (g*(cosφ*sin(θ2)-η*sin(θ1))-(l1*ω1*ω1*cosφ+l2*ω2*ω2)*sin(φ))/l1/(η-cosφ*cosφ)
#defcfunc f4 array ξ
θ1 = ξ : θ2 = ξ(1) : ω1 = ξ(2) : ω2 = ξ(3)
φ = θ1-θ2 : cosφ = cos(φ)
return (g*η*(cosφ*sin(θ1)-sin(θ2))+(η*l1*ω1*ω1+l2*ω2*ω2*cosφ)*sin(φ))/l2/(η-cosφ*cosφ)
#global
#module mod_commonDraw
#define wsx wsx@
#define wsy wsy@
#define Oxw Oxw@
#define Oyw Oyw@
#define m1 m@
#define m2 m@(1)
#define l1 l@
#define l2 l@(1)
#define θ1 θ@
#define θ2 θ@(1)
#define r1w rw@
#define r2w rw@(1)
#define l1w lw@
#define l2w lw@(1)
#deffunc local modDetect
return
#deffunc drawCdntAx /* ("drawCoordinateAxis") 座標軸の描画 */
color 100,100,100
line -1,Oyw,wsx,Oyw
line Oxw,-1,Oxw,wsy
return
#deffunc drawPndlms /* ("drawPendulums") 振り子の描画 */
// 注意 hsp3dish では circle で中空円が描けないので一旦塗り潰してから背景色で一回り小さい円を塗り潰して対応する。
/* おもり1 */
xtmp = Oxw+l1w*sin(θ1) : ytmp = Oyw+l1w*cos(θ1)
color 255,255,255 : circle xtmp-r1w,ytmp-r1w, xtmp+r1w,ytmp+r1w, 1
color : circle xtmp-r1w+1,ytmp-r1w+1, xtmp+r1w-1,ytmp+r1w-1, 1
color 255,255,255 : line Oxw,Oyw,xtmp,ytmp
/* おもり2 */
xtmp2 = xtmp + l2w*sin(θ2) : ytmp2 = ytmp + l2w*cos(θ2)
color 255,255,255 : circle xtmp2-r2w,ytmp2-r2w, xtmp2+r2w,ytmp2+r2w, 1
color : circle xtmp2-r2w+1,ytmp2-r2w+1, xtmp2+r2w-1,ytmp2+r2w-1, 1
color 255,255,255 : line xtmp,ytmp,xtmp2,ytmp2
return
#deffunc drawInfos /* 各種情報の表示 */
/* 注意
font 設定の影響を受ける。推奨は msgoshic,16 。
*/
fontsize = 16
color 200,200,200
pos 5,wsy-5-fontsize*6 : mes "l1 = "+strf("%3.2f",l1)+" [m]"
pos 5,wsy-5-fontsize*5 : mes "l2 = "+strf("%3.2f",l2)+" [m]"
pos 5,wsy-5-fontsize*4 : mes "θ1 = "+strf("%6.2f",rad2deg(θ1))+" [deg]"
pos 5,wsy-5-fontsize*3 : mes "θ2 = "+strf("%6.2f",rad2deg(θ2))+" [deg]"
pos 5,wsy-5-fontsize*2 : mes "m1 = "+strf("%3.2f",m1)+" [kg]"
pos 5,wsy-5-fontsize : mes "m2 = "+strf("%3.2f",m2)+" [kg]"
return
#global
#module mod_loadPreset
#define wsx wsx@
#define wsy wsy@
#define frmIntvl frmIntvl@*3
#define mtr2px mtr2px@
#define fontsize 16
#define PRESET PRESET@
#define σ σ@
#define m m@
#define m1 m@
#define m2 m@(1)
#define l l@
#define l1 l@
#define l2 l@(1)
#define θ θ@
#define θ1 θ@
#define θ2 θ@(1)
#define x1 x@
#define x2 x@(1)
#define y1 y@
#define y2 y@(1)
#define r1 r@
#define r2 r@(1)
#define r1w rw@
#define r2w rw@(1)
#define l1w lw@
#define l2w lw@(1)
#deffunc loadPreset
/*
プリセットからロードする処理をUIも含めて担当する。
戻り値 : (-1,other) : (ロードせず,ロードされたプリセット番号)
ウィンドウは cls されることに注意
*/
*boot
/* 未初期化変数警告回避 */
idSelPs = 0
/* 直前の設定をバックアップ */
mbak = m1,m2
lbak = l1,l2
θbak = θ1,θ2
loadPresetFile
initUI
usrRqstStat = 0 //("userRequestStatus") ユーザーからの要求の状態。(0,1,2) = (通常,選択プリセット読込要求,読込キャンセル要求)
*main
repeat
reflesh //画面更新
if usrRqstStat : break //ユーザーから新たなアクションの要求があるなら
await frmIntvl
loop
switch usrRqstStat
case 1
return idSelPs
case 2 /* キャンセル */
/* 設定復元 */
m = mbak,mbak(1)
l = lbak,lbak(1)
θ = θbak,θbak(1)
r1 = sqrt(m1/σ/4/m_pi) : r2 = sqrt(m2/σ/4/m_pi)
x1 = l1*sin(θ1) : y1 = l1*cos(θ1)
x2 = x1+l2*sin(θ2) : y2 = y1+l2*cos(θ2)
return -1
swend
*PsBtnIntrrpt /* プリセットボタン割り込みへの応答 */
idSelPs = stat
l1 = PRESET(stat,0) : l2 = PRESET(stat,1)
m1 = PRESET(stat,2) : m2 = PRESET(stat,3)
r1 = sqrt(m1/σ/4/m_pi) : r2 = sqrt(m2/σ/4/m_pi)
θ1 = PRESET(stat,4) : θ2 = PRESET(stat,5)
x1 = l1*sin(θ1) : y1 = l1*cos(θ1)
x2 = x1+l2*sin(θ2) : y2 = y1+l2*cos(θ2)
r1w = r1*mtr2px : r2w = r2*mtr2px
l1w = l1*mtr2px : l2w = l2*mtr2px
return
*ActBtnIntrpt /* アクションボタン割り込みへの対応 */
usrRqstStat = stat-4
return
#deffunc local initUI /* UI初期化 */
cls
font msgothic,fontsize
/* プリセットボタン */
#define sxPsBtn 50 //("sizexOfPresetButton") プリセットボタンの横幅
#define syPsBtn 30
objsize sxPsBtn,syPsBtn
numVPs = 5 //("numberOfValidPreset") 有効なプリセットの個数
repeat 5
pos 200+(sxPsBtn+5)*cnt,wsy-syPsBtn-5 : button gosub ""+cnt+"",*PsBtnIntrrpt
if PRESET(cnt,0) <= 0 : objenable cnt,0 : numVPs -- //プリセットが記録されていないならボタンを無効化
loop
/* アクションボタン */
#define sxActBtn 100
#define syActBtn 20
objsize sxActBtn,syActBtn
pos wsx-sxActBtn-5,wsy-(syActBtn+5)*2 : button gosub "読込",*ActBtnIntrpt
if numVPs = 0 : objenable stat,0
pos wsx-sxActBtn-5,wsy-syActBtn-5 : button gosub "キャンセル",*ActBtnIntrpt
/* 初期選択 */
if numVPs {
repeat 5 /* 最初に見つかった有効なプリセットを選択する */
if PRESET(cnt,0) > 0 {
idSelPs = cnt //選択されているプリセット番号
l1 = PRESET(cnt,0) : l2 = PRESET(cnt,1)
m1 = PRESET(cnt,2) : m2 = PRESET(cnt,3)
r1 = sqrt(m1/σ/4/m_pi) : r2 = sqrt(m2/σ/4/m_pi)
θ1 = PRESET(cnt,4) : θ2 = PRESET(cnt,5)
x1 = l1*sin(θ1) : y1 = l1*cos(θ1)
x2 = x1+l2*sin(θ2) : y2 = y1+l2*cos(θ2)
r1w = r1*mtr2px : r2w = r2*mtr2px
l1w = l1*mtr2px : l2w = l2*mtr2px
break
}
loop
}
return
#deffunc local reflesh /* 画面更新 */
redraw 0
color : boxf
drawCdntAx //座標軸
drawInfos2 //各種情報
if numVPs {
drawPndlms //振り子
drawInfos //各種情報
}
redraw 1
return
#deffunc local drawInfos2 /* 各種情報表示 */
color 200,200,200
pos 200,wsy-syPsBtn*2-15 : mes "プリセットを選択してください"
if numVPs {
color 200,150,100
pos 200+(sxPsBtn+5)*idSelPs+(sxPsBtn-fontsize)/2,wsy-syPsBtn*2+5 : mes "▼"
}
return
#deffunc loadPresetFile
/*
プリセットデータをファイルから読み込んでシステムに反映する。
戻り値 (0,1) : (成功,失敗)
*/
exist "save/preset.dat"
if strsize = -1 : return 1
bload "save/preset.dat", PRESET
return 0
#global
#module mod_savePreset
#define wsx wsx@
#define wsy wsy@
#define frmIntvl frmIntvl@*3
#define mtr2px mtr2px@
#define fontsize 16
#define PRESET PRESET@
#define σ σ@
#define m m@
#define m1 m@
#define m2 m@(1)
#define l l@
#define l1 l@
#define l2 l@(1)
#define θ θ@
#define θ1 θ@
#define θ2 θ@(1)
#define x1 x@
#define x2 x@(1)
#define y1 y@
#define y2 y@(1)
#define r1 r@
#define r2 r@(1)
#define r1w rw@
#define r2w rw@(1)
#define l1w lw@
#define l2w lw@(1)
#deffunc savePreset
/*
プリセットにセーブする処理をUIも含めて担当する。
戻り値 : (-1,other) : (セーブせず,セーブ先プリセット番号)
ウィンドウは cls されることに注意
*/
*boot
/* 未初期化変数警告回避 */
idSelPs = 0
/* 直前の設定をバックアップ */
mbak = m1,m2
lbak = l1,l2
θbak = θ1,θ2
loadPresetFile
initUI
usrRqstStat = 0 //("userRequestStatus") ユーザーからの要求の状態。(0,1,2) = (通常,選択プリセットへ保存要求,保存キャンセル要求)
*main
repeat
reflesh //画面更新
if usrRqstStat : break //ユーザーから新たなアクションの要求があるなら
await frmIntvl
loop
/* 設定復元 */
m = mbak,mbak(1)
l = lbak,lbak(1)
θ = θbak,θbak(1)
r1 = sqrt(m1/σ/4/m_pi) : r2 = sqrt(m2/σ/4/m_pi)
x1 = l1*sin(θ1) : y1 = l1*cos(θ1)
x2 = x1+l2*sin(θ2) : y2 = y1+l2*cos(θ2)
switch usrRqstStat
case 1
savePresetFile idSelPs
return idSelPs
case 2 //キャンセル
return -1
swend
stop
*PsBtnIntrrpt /* プリセットボタン割り込みへの応答 */
idSelPs = stat
if PRESET(idSelPs,0) > 0 { //選択プリセットのデータが有効なら
l1 = PRESET(idSelPs,0) : l2 = PRESET(idSelPs,1)
m1 = PRESET(idSelPs,2) : m2 = PRESET(idSelPs,3)
r1 = sqrt(m1/σ/4/m_pi) : r2 = sqrt(m2/σ/4/m_pi)
θ1 = PRESET(idSelPs,4) : θ2 = PRESET(idSelPs,5)
x1 = l1*sin(θ1) : y1 = l1*cos(θ1)
x2 = x1+l2*sin(θ2) : y2 = y1+l2*cos(θ2)
r1w = r1*mtr2px : r2w = r2*mtr2px
l1w = l1*mtr2px : l2w = l2*mtr2px
}
return
*ActBtnIntrpt /* アクションボタン割り込みへの対応 */
usrRqstStat = stat-4
return
#deffunc local initUI /* UI初期化 */
cls
font msgothic,fontsize
/* プリセットボタン */
#define sxPsBtn 50 //("sizexOfPresetButton") プリセットボタンの横幅
#define syPsBtn 30
objsize sxPsBtn,syPsBtn
repeat 5 : pos 200+(sxPsBtn+5)*cnt,wsy-syPsBtn-5 : button gosub ""+cnt+"",*PsBtnIntrrpt : loop
idSelPs = 0 //選択プリセット番号
/* アクションボタン */
#define sxActBtn 100
#define syActBtn 20
objsize sxActBtn,syActBtn
pos wsx-sxActBtn-5,wsy-(syActBtn+5)*2 : button gosub "保存",*ActBtnIntrpt
pos wsx-sxActBtn-5,wsy-syActBtn-5 : button gosub "キャンセル",*ActBtnIntrpt
return
#deffunc local reflesh /* 画面更新 */
redraw 0
color : boxf
drawInfos2
drawCdntAx //座標軸
if PRESET(idSelPs,0) > 0 { //選択プリセットが有効なら
drawPndlms //振り子
drawInfos //各種情報
}
redraw 1
return
#deffunc local drawInfos2 /* 各種情報表示 */
color 200,200,200
pos 200,wsy-syPsBtn*2-15 : mes "プリセットを選択してください"
color 200,150,100
pos 200+(sxPsBtn+5)*idSelPs+(sxPsBtn-fontsize)/2,wsy-syPsBtn*2+5 : mes "▼"
return
#deffunc savePresetFile int i
/*
選択プリセットに現在の設定を書き込んでファイルに保存する。
i : 選択プリセット番号
*/
PRESET(i,0) = l1 : PRESET(i,1) = l2
PRESET(i,2) = m1 : PRESET(i,3) = m2
PRESET(i,4) = θ1 : PRESET(i,5) = θ2
bsave "save/preset.dat",PRESET
#ifdef hsproom
devcontrol "syncfs"
#endif
return
#global
#module mod_initPreset
#define PRESET @PRESET@
#deffunc initPreset /* プリセットデータを初期化してファイルに保存 */
ddim PRESET,5,6
PRESET(0,0) = 1.3 : PRESET(0,1) = 2.05 : PRESET(0,2) = 0.68 : PRESET(0,3) = 1.26 : PRESET(0,4) = 0.115715 : PRESET(0,5) = 2.953097
PRESET(1,0) = 0.86 : PRESET(1,1) = 1.8 : PRESET(1,2) = 2.01 : PRESET(1,3) = 0.10 : PRESET(1,4) = -2.09148 : PRESET(1,5) = 1.82928
PRESET(3,0) = 2.5 : PRESET(3,1) = 1.5 : PRESET(3,2) = 1.0 : PRESET(3,3) = 3.0 : PRESET(3,4) = 1.570796 : PRESET(3,5) = -2.356194
PRESET(4,0) = 0.7 : PRESET(4,1) = 2.67 : PRESET(4,2) = 1.0 : PRESET(4,3) = 3.0 : PRESET(4,4) = 0.393746 : PRESET(4,5) = -1.99275
bsave "save/preset.dat",PRESET
#ifdef hsproom
devcontrol "syncfs"
#endif
return
#global
#module mod_fatalError
#deffunc fatalError
dialog "A fatal error occured.\nThis program will end on closing this window."
end
#global