修正版1のRK4で大ポカをやらかしていました…。
(全エネルギーが徐々に減っていたのは誤差なんかじゃなかった…。)
多分これで最後の修正になります。
修正版1のRK4で大ポカをやらかしていました…。
(全エネルギーが徐々に減っていたのは誤差なんかじゃなかった…。)
多分これで最後の修正になります。
#include "hsp3dish.as"#packopt name "DPRK4"/* モジュール認識 */modDetect@mod_simuCfgmodDetect@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,m2r = 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,θ2x = l1*sin(θ1),x+l2*sin(θ2)y = l1*cos(θ1),y+l2*cos(θ2)/* システム */ddim PRESET,5,6/* 起動 */*boottitle "二重振り子シミュレーター"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 modDetectreturn*bootLBTNDWN = 0 //汎用変数初期化initUIusrRqstStat = 0 //("userRequestStatus") ユーザーからの要求の状態。(0,1,2,3) = (通常,プリセットロード要求,プリセット保存要求,シミュレーション開始要求)*main //メインループrepeathandleMassSlds //MS管理handlePndlmDrg //おもりドラッグ管理reflesh //画面更新if usrRqstStat : break //ユーザーから新たなアクションの要求があるならawait frmIntvlloopswitch usrRqstStatcase 1loadPresetinitUIgoto *bootcase 2savePresetinitUIgoto *bootswbreakcase 3goto *boot@mod_simuswbreakdefaultfatalErrorswendstop*btnIntrpt /* ボタン割り込みへの対応 */usrRqstStat = 1+statreturn#deffunc local initUI /* UI初期化 */clsfont 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 20objsize sxBtn,syBtnpos wsx-5-sxBtn,wsy-5-syBtn*3-2*2 : button gosub "プリセット読込",*btnIntrptpos wsx-5-sxBtn,wsy-5-syBtn*2-2 : button gosub "プリセット保存",*btnIntrptpos wsx-5-sxBtn,wsy-5-syBtn : button gosub "シミュレーション開始",*btnIntrptreturn#deffunc local handleMassSlds /* MS管理ルーチン */getkey LBTNDWN,1 : if LBTNDWN = 0 : returnrepeat 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 = cntrepeatgetkey LBTNDWN,1 : if LBTNDWN = 0 : breakif mousex != lastmx { //マウスカーソルが横に動いたらlastmx = mousexpxMSK(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 frmIntvlloop}loopreturn#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-mouseylastmx = mousex : lastmy = mouseyrepeatgetkey LBTNDWN,1 : if LBTNDWN = 0 : breakif (mousex != lastmx)|(mousey != lastmy) {lastmx = mousex : lastmy = mouseyx2w = mousex+xmofst : y2w = mousey+ymofstcalcPndlmPosFromUIreflesh //画面更新}await frmIntvlloop}/* おもり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 //以前のマウスカーソルの位置repeatgetkey LBTNDWN,1 : if LBTNDWN = 0 : breakif (mousex != lastmx)|(mousey != lastmy) { //マウスカーソルが動いたらlastmx = mousex : lastmy = mouseyx1w = mousex+xmofst : y1w = mousey+ymofstx2w = x1w+xRelPw : y2w = y1w+yRelPwcalcPndlmPosFromUIreflesh //画面更新}await frmIntvlloop}return#deffunc local calcPndlmPosFromUI /* ウィンドウ上でのおもりの位置からその他の位置情報をを計算 */x1 = double(x1w-Oxw)/mtr2px : y1 = double(y1w-Oyw)/mtr2pxl1 = sqrt(x1*x1+y1*y1) : l1w = l1*mtr2pxθ1 = atan(x1,y1)x2 = x1+double(x2w-x1w)/mtr2px : y2 = y1+double(y2w-y1w)/mtr2pxl2 = sqrt(powf(x2-x1,2)+powf(y2-y1,2)) : l2w = l2*mtr2pxθ2 = atan(x2-x1,y2-y1)return#deffunc local reflesh /* 再描画 */redraw 0color : boxfdrawCdntAx //座標軸drawPndlms //振り子drawInfos //各種情報drawMassSlds //MSredraw 1return#deffunc local drawMassSlds /* MS描画*/repeat 2ytmp = wsy-5-fontsize*(2-cnt)+8color 100,100,100boxf 140,ytmp, 140+sxMS,ytmp+syMSpxMSK(cnt) = msv2pxMSK(MSV(cnt))color 200,150,100boxf pxMSK(cnt),pyMSK(cnt), pxMSK(cnt)+sxMSK,pyMSK(cnt)+syMSKloopreturn#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 modDetectreturn*bootinitUIusrRqstStat = 0 //("userRequestStatus") ユーザーからの要求の状態。(0,1) = (通常,シミュレーション終了要求)simuStat = 1 //("simulationStatus") シミュレーションの状態。(0,1) = (停止,実行)η = (m1+m2)/m2ω1 = 0.0ω2 = 0.0x1 = 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,2repeat numPtTrack : TRACK(cnt,0) = x2 : TRACK(cnt,1) = y2 : loopfrntTRACK = 0*mainetls = 0.0 //[s] ("elapsedTimeFromLastStep") 前回ステップ計算からの経過時間etlts = 0.0 //[s] ("elapsedTimeFromLastTrackSampling") 前回軌跡サンプリングからの経過時間etlf = 0.0 //[ms] ("elapsedTimeFromLastFrame") 前回画面更新からの経過時間repeatif etls >= dt : step : etls = -0.001*slfreq //ステップ計算if etlts >= TrkSmplngIntvl : handleTrack : etlts = -0.001*slfreq //軌跡サンプリングif etlf >= frmIntvl : reflesh : etlf = -slfreq //画面更新if usrRqstStat : breakawait slfreqif simuStat {etls += 0.001*slfreqetlts += 0.001*slfreq}etlf += slfreqloopgoto *boot@mod_simuCfg*btnIntrrpt /* ボタン割り込みへの対応 */switch statcase 0simuStat = 0objenable 0,0 : objenable 1,1swbreakcase 1simuStat = 1objenable 0,1 : objenable 1,0swbreakcase 2usrRqstStat = 1swendreturn#deffunc local initUI /* UI初期化 */clsfont msgothic,fontsize/* 各種ボタン */#define sxBtn 180#define syBtn 20objsize sxBtn,syBtnpos wsx-sxBtn-5,wsy-5-syBtn*3-2*2 : button gosub "停止",*btnIntrrptpos wsx-sxBtn-5,wsy-5-syBtn*2-2 : button gosub "再開",*btnIntrrpt : objenable 1,0pos wsx-sxBtn-5,wsy-5-syBtn : button gosub "シミュレーション終了",*btnIntrrptreturn#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 0color : boxfdrawCdntAx //座標軸drawPndlms //振り子drawTrack //軌跡drawInfos : drawIndo2 //各種情報redraw 1return#deffunc local drawIndo2 /* 各種情報の表示 */color 200,200,200U = calcU() : K = calcK() : E = U+Kpos 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) = y2if frntTRACK = numPtTRACK-1 : frntTRACK = 0 : else : frntTRACK ++return#deffunc local drawTrack /* おもり2の軌跡の描画 */i = frntTRACKrepeat numPtTrackxtmp = Oxw+TRACK(i,0)*mtr2px-3,xtmp+6,xtmp+6,xtmpytmp = Oyw+TRACK(i,1)*mtr2px-3,ytmp,ytmp+6,ytmp+6gmode 3, , ,256*cnt/numPtTRACKcolor 50,100,255 : gsquare -1,xtmp,ytmpif i = numPtTRACK-1 : i = 0 : else : i ++loopreturn#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 modDetectreturn#deffunc drawCdntAx /* ("drawCoordinateAxis") 座標軸の描画 */color 100,100,100line -1,Oyw,wsx,Oywline Oxw,-1,Oxw,wsyreturn#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, 1color : circle xtmp-r1w+1,ytmp-r1w+1, xtmp+r1w-1,ytmp+r1w-1, 1color 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, 1color : circle xtmp2-r2w+1,ytmp2-r2w+1, xtmp2+r2w-1,ytmp2+r2w-1, 1color 255,255,255 : line xtmp,ytmp,xtmp2,ytmp2return#deffunc drawInfos /* 各種情報の表示 *//* 注意font 設定の影響を受ける。推奨は msgoshic,16 。*/fontsize = 16color 200,200,200pos 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,m2lbak = l1,l2θbak = θ1,θ2loadPresetFileinitUIusrRqstStat = 0 //("userRequestStatus") ユーザーからの要求の状態。(0,1,2) = (通常,選択プリセット読込要求,読込キャンセル要求)*mainrepeatreflesh //画面更新if usrRqstStat : break //ユーザーから新たなアクションの要求があるならawait frmIntvlloopswitch usrRqstStatcase 1return idSelPscase 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 -1swend*PsBtnIntrrpt /* プリセットボタン割り込みへの応答 */idSelPs = statl1 = 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*mtr2pxl1w = l1*mtr2px : l2w = l2*mtr2pxreturn*ActBtnIntrpt /* アクションボタン割り込みへの対応 */usrRqstStat = stat-4return#deffunc local initUI /* UI初期化 */clsfont msgothic,fontsize/* プリセットボタン */#define sxPsBtn 50 //("sizexOfPresetButton") プリセットボタンの横幅#define syPsBtn 30objsize sxPsBtn,syPsBtnnumVPs = 5 //("numberOfValidPreset") 有効なプリセットの個数repeat 5pos 200+(sxPsBtn+5)*cnt,wsy-syPsBtn-5 : button gosub ""+cnt+"",*PsBtnIntrrptif PRESET(cnt,0) <= 0 : objenable cnt,0 : numVPs -- //プリセットが記録されていないならボタンを無効化loop/* アクションボタン */#define sxActBtn 100#define syActBtn 20objsize sxActBtn,syActBtnpos wsx-sxActBtn-5,wsy-(syActBtn+5)*2 : button gosub "読込",*ActBtnIntrptif numVPs = 0 : objenable stat,0pos 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*mtr2pxl1w = l1*mtr2px : l2w = l2*mtr2pxbreak}loop}return#deffunc local reflesh /* 画面更新 */redraw 0color : boxfdrawCdntAx //座標軸drawInfos2 //各種情報if numVPs {drawPndlms //振り子drawInfos //各種情報}redraw 1return#deffunc local drawInfos2 /* 各種情報表示 */color 200,200,200pos 200,wsy-syPsBtn*2-15 : mes "プリセットを選択してください"if numVPs {color 200,150,100pos 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 1bload "save/preset.dat", PRESETreturn 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,m2lbak = l1,l2θbak = θ1,θ2loadPresetFileinitUIusrRqstStat = 0 //("userRequestStatus") ユーザーからの要求の状態。(0,1,2) = (通常,選択プリセットへ保存要求,保存キャンセル要求)*mainrepeatreflesh //画面更新if usrRqstStat : break //ユーザーから新たなアクションの要求があるならawait frmIntvlloop/* 設定復元 */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 usrRqstStatcase 1savePresetFile idSelPsreturn idSelPscase 2 //キャンセルreturn -1swendstop*PsBtnIntrrpt /* プリセットボタン割り込みへの応答 */idSelPs = statif 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*mtr2pxl1w = l1*mtr2px : l2w = l2*mtr2px}return*ActBtnIntrpt /* アクションボタン割り込みへの対応 */usrRqstStat = stat-4return#deffunc local initUI /* UI初期化 */clsfont msgothic,fontsize/* プリセットボタン */#define sxPsBtn 50 //("sizexOfPresetButton") プリセットボタンの横幅#define syPsBtn 30objsize sxPsBtn,syPsBtnrepeat 5 : pos 200+(sxPsBtn+5)*cnt,wsy-syPsBtn-5 : button gosub ""+cnt+"",*PsBtnIntrrpt : loopidSelPs = 0 //選択プリセット番号/* アクションボタン */#define sxActBtn 100#define syActBtn 20objsize sxActBtn,syActBtnpos wsx-sxActBtn-5,wsy-(syActBtn+5)*2 : button gosub "保存",*ActBtnIntrptpos wsx-sxActBtn-5,wsy-syActBtn-5 : button gosub "キャンセル",*ActBtnIntrptreturn#deffunc local reflesh /* 画面更新 */redraw 0color : boxfdrawInfos2drawCdntAx //座標軸if PRESET(idSelPs,0) > 0 { //選択プリセットが有効ならdrawPndlms //振り子drawInfos //各種情報}redraw 1return#deffunc local drawInfos2 /* 各種情報表示 */color 200,200,200pos 200,wsy-syPsBtn*2-15 : mes "プリセットを選択してください"color 200,150,100pos 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) = l2PRESET(i,2) = m1 : PRESET(i,3) = m2PRESET(i,4) = θ1 : PRESET(i,5) = θ2bsave "save/preset.dat",PRESET#ifdef hsproomdevcontrol "syncfs"#endifreturn#global#module mod_initPreset#define PRESET @PRESET@#deffunc initPreset /* プリセットデータを初期化してファイルに保存 */ddim PRESET,5,6PRESET(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.953097PRESET(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.82928PRESET(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.356194PRESET(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.99275bsave "save/preset.dat",PRESET#ifdef hsproomdevcontrol "syncfs"#endifreturn#global#module mod_fatalError#deffunc fatalErrordialog "A fatal error occured.\nThis program will end on closing this window."end#global