振り子の支点を振り回す 4 of 4

-- では振り子の支点に加速度をかけて振り回してみる
timerTicking = false

cursor.set("drag grab")

screenW = platform.window:width()
screenH = platform.window:height()
unitLen = screenW/4             -- 1メートルの、画面上での画素数

posTwoAgoX    = 0
posTwoAgoY    = 0
posOneAgoX    = 0
posOneAgoY    = 0
posZeroAgoX   = 0
posZeroAgoY   = 0
speedOneAgoX  = 0
speedOneAgoY  = 0
speedZeroAgoX = 0
speedZeroAgoY = 0
accelX        = 0
accelY        = 0

len         = 1                                            -- 振り子の棒の長さ〔m〕
ax          = 0                                            -- 振り子の支点の加速度 x 〔m/sec^2〕
ay          = 0                                            -- 振り子の支点の加速度 y 〔m/sec^2〕
angleIni    = 0                                            -- 初期角度 〔rad〕
velIni      = 0                                            -- 初期速度 〔rad/sec〕
radiusPend  = screenW/30                                   -- 分銅半径の描画画素数
posNowX     = 0--screenW/2                                 -- 支点の初期描画座標 x
posNowY     = 0--screenH/2                                 -- 支点の初期描画座標 y
xP          = posNowX + unitLen * len * math.sin(angleIni) -- 分銅の初期座標 x
yP          = posNowY + unitLen * len * math.cos(angleIni) -- 分銅の初期座標 y
fontSize    = math.floor(screenW/25)                       -- フォントサイズ
step        = 1/60                                         -- Δt 〔sec〕
elapsedTime = 0                                            -- シム内の経過時間 〔sec〕

function on.paint(gc)
   drawPend(posNowX, posNowY, xP, yP, radiusPend, gc)
   gc:setFont("sansserif", "r", fontSize)
   gc:drawString(round(elapsedTime, 1), 1, 1)
   if timerTicking == false then condString = "stopped" elseif timerTicking == true then condString = "running" end
   gc:drawString(condString, 1, fontSize + fontSize)

   gc:drawString("1 [m]", 10, screenH - fontSize - 5, "bottom")
   gc:setColorRGB(255,0,0)
   gc:setPen("thick")
   gc:drawLine(10, screenH - fontSize, 10 + unitLen, screenH - fontSize)
   platform.window:invalidate()
end
function on.mouseMove(x, y)
   posZeroAgoX = x
   posZeroAgoY = y
   posNowX = x
   posNowY = y
   xP = posNowX + unitLen * len * math.sin(angleIni)
   yP = posNowY + unitLen * len * math.cos(angleIni)
   platform.window:invalidate()
end
function on.timer()
   speedOneAgoX  = (posOneAgoX    - posTwoAgoX)   / unitLen / step
   speedOneAgoY  = (posOneAgoY    - posTwoAgoY)   / unitLen / step
   speedZeroAgoX = (posZeroAgoX   - posOneAgoX)   / unitLen / step
   speedZeroAgoY = (posZeroAgoY   - posOneAgoY)   / unitLen / step
   accelX        = (speedZeroAgoX - speedOneAgoX) / step
   accelY        = (speedZeroAgoY - speedOneAgoY) / step
   posTwoAgoX    = posOneAgoX
   posTwoAgoY    = posOneAgoY
   posOneAgoX    = posZeroAgoX
   posOneAgoY    = posZeroAgoY

   var.store("len"     , len)
   var.store("ax"      , accelX)
   var.store("ay"      , accelY)
   var.store("angleini", angleIni)
   var.store("velini"  , velIni)
   var.store("step"    , step)   
   local temp = math.eval("pend(len, ax, ay, angleini, velini, step)")

   angleIni = temp[1]
   velIni   = temp[2]
   xP       = posNowX + unitLen * temp[3]
   yP       = posNowY + unitLen * temp[4]

   elapsedTime = elapsedTime + step
   platform.window:invalidate()
end
function on.enterKey()
   if     timerTicking == false then timer.start(step) timerTicking = true
   elseif timerTicking == true  then timer.stop()      timerTicking = false
   end
end
---------------------------------------------------
---------------------------------------------------
---------------------------------------------------
---------------------------------------------------
-- 振り子描画函数(支点の描画座標, 分銅の座標, 分銅半径, gc)
function drawPend(x0, y0, x1, y1, radius, gc) gc:drawLine(x0, y0, x1, y1) gc:fillArc(x1 - radius, y1 - radius, radius + radius, radius + radius, 0, 360) end
-- 四捨五入函数(小数点数, 小数点以下の桁数)
function round(number, digits) return math.eval("round("..number..", "..digits..")") end

参考文献版元の動画:

グルグルトンボの実演

参考:

新 Excelコンピュータシミュレーション -数学モデルを作って楽しく学ぼう-

新 Excelコンピュータシミュレーション -数学モデルを作って楽しく学ぼう-

pp.71-84