コンピュータを楽しもう!!

今、自分が面白くていろいろやってみたことを書き綴りたいと思います。連絡先はtarosa.yでgmail.comです。

LuaridaでSDメモリのファイルを読む

LuaridaのVer1.22Betaの公開と同時に、サンプルプログラムを別アプリとして公開してみました。今回別アプリとして公開したサンプルプログラムは、SDメモリカードに保存したデータを読み込むプログラムです。
特にLuaridaの関連コマンド機能ではなく、純粋にlua言語のファイル読み込み機能を使ったサンプルです。

io.open(ファイル名 [,モード])

io.openを用いてファイルを開くことができます。詳しくはLuaの説明サイトを見てください。
今回のサンプルはFileiosample.luaという名前で、CSVファイルを読み込むサンプルを作ってみました。下記のようなCSVファイルを読み込みます。

xtitle,Xの値
ytitle,Yの値
4,85
15,102
23,70
36,36
43,44
50,62
66,93
78,41
83,30
95,21
104,25
111,36
120,53

CSVファイルを読み込むサンプル

Xtitle と Ytitle と Value ={ X={}, Y={} } にCSVファイルから値を読み込むサンプルです。
str = fp:read("*l")とすると、1行ずつファイルを読み込みます。下記がサンプルプログラムです。

------------------------------------------
--CSVファイルを読み込みます
------------------------------------------
function readdata( filename )
local fp
local msg
local str
local t={}
local i = 1
 --ファイルを開きます
 fp,msg = io.open( filename, "r")
 if( not(fp) )then
   dialog( Path..Fname.."がオープンできません","プログラムを終了します", 0 )
   return
 end
 --CSVデータを読み込みます
 while(true)do
   str = fp:read("*l")                  --1行読み込み
   if( str==nil )then break end         --読込むデータが無ければ終了
   str = string.gsub( str,"\r","" )     --改行コードを外す
   t = split( str, "," )
   if( t[1]=="xtitle" )then Xtitle = t[2] end
   if( t[1]=="ytitle" )then Ytitle = t[2] end
   if( t[1]~="xtitle" and t[1]~="ytitle" )then
     Value.X[i] = t[1]
     Value.Y[i] = t[2]
     i = i + 1
    end
 end
 io.close(fp)
end

グラフを描く

ついでに、グラフも描いてみました。下記がグラフを描くサンプルです。drawLine等のグラフィックコマンドを使って、グラフを描いています。ちょっと、ポケコンぽいでしょ・・・。

------------------------------------------
--X-Yグラフを描きます
------------------------------------------
function drawXYgraph()
local DXg = 50
local DYg = 50
local DXg0 = DXg --X軸描画マージン
local DYg0 = DYg --Y軸描画マージン
local MX = 10    --X軸目盛の間隔
local MY = 10    --Y軸目盛の間隔
local i
local LXg = 400
local LYg = 230
local XdMax = 130
local XdMin = 0
local YdMax = 150
local YdMin = 0
local MXMax = math.modf(XdMax/MX) * MX                    --X軸の目盛の最大値を求める
local MXMin = MXMax - math.modf( (MXMax-XdMin)/MX ) * MX  --X軸の目盛の最小値を求める
local MYMax = math.modf(YdMax/MY) * MY                    --Y軸の目盛の最大値を求める
local MYMin = MYMax - math.modf( (MYMax-YdMin)/MY ) * MY  --Y軸の目盛の最小値を求める
local ATaX = LXg/( XdMax - XdMin )
local ATaY = LYg/( YdMax - YdMin )
local ms
local width, hight

 width, hight = canvas.getviewSize()
 --枠描画
 canvas.drawRect( DXg0, hight-DYg0, DXg0+LXg, hight-DYg0-LYg, Col.BLUE, 1 )
 canvas.drawRect( DXg0, hight-DYg0, DXg0+LXg, hight-DYg0-LYg, Col.WHITE )
 --X軸目盛りと目盛り数値のプロット
 i=MXMin
 while(true)do
   if( i>XdMax )then break end
   ms = (i-XdMin) * ATaX + DXg0
   canvas.drawLine( ms, hight-DYg0, ms, hight-DYg0-(LYg/40), Col.WHITE )
   canvas.drawLine( ms, hight-DYg0-LYg, ms, hight-DYg0-LYg+(LYg/40), Col.WHITE )
   local strmm = string.rep(" ", 5-string.len(i) )..i
   canvas.drawText( strmm, ms-20, hight-DYg0+4, 14, Col.WHITE )
   i = i + MX
 end
 canvas.drawTextCenter( Xtitle, DXg0+LXg/2, hight-DYg0+20, 20, Col.WHITE )

 --Y軸目盛りと目盛り数値のプロット
 i=MYMin
 while(true)do
   if( i>YdMax )then break end
   ms = hight - DYg0 - (i-YdMin)*ATaY
   canvas.drawLine( DXg0, ms, DXg0+(LYg/40),ms, Col.WHITE )
   canvas.drawLine( DXg0+LXg, ms, DXg0+LXg-(LYg/40), ms, Col.WHITE )
   local strmm = string.rep(" ", 5-string.len(i))..i
   canvas.drawText( strmm, DXg0-35, ms-5, 14, Col.WHITE )
   i = i + MY
 end
 canvas.drawTextBox( Ytitle, DXg0-48, hight-DYg0-LYg+80, 20, Col.WHITE, 25 )

 --グラフのプロット
 for i=1,#Value.X do
   canvas.drawCircle( DXg0+Value.X[i]*ATaX, hight-DYg0-Value.Y[i]*ATaY, 3, Col.WHITE, 1 )
 end
 --スプライト曲線の描画
 splineplot( XdMin, XdMax, DXg0, ATaX, hight-DYg0, ATaY )
end

スプライン曲線の描画

ついでにグラフの点をスプライン曲線で引くプログラムも作ってみました。特に説明はしませんが、載せておきます。
lua言語では、関数の引数に配列を使え、呼び先で変更された内容に書き換わって戻ってきます。

下記にサンプルプログラムの全容を書きます。

------------------------------------------
--ファイルI/Oサンプル CSVデータの読み込み
------------------------------------------
--関数宣言--------------------------------
main={}          --mainメソッド
split={}        --文字の分解
readdata={}        --CSVファイルを読み込みます
drawXYgraph={}      --グラフを描きます
splineplot={}      --スプライン描画します
spline={}        -- スプライン補間
getSplineCoefficient={}  --スプライン補間係数を求めます
--グローバル変数宣言----------------------
Path = "/sdcard/luarida/fileiosample/"    --luaファイルを保存しているPath
Fname = "testdata.csv"
Xtitle = ""
Ytitle = ""
Value ={ X={}, Y={} }
------------カラー変数定義------------------
Col = { BLACK=color(0,0,0)      --黒
    ,WHITE=color(255,255,255)  --白
    ,DGRAY=color(128,128,128)  --深灰色
    ,LGRAY=color(192,192,192)  --明灰色
    ,DRED=color(128,0,0)    --暗赤
    ,RED=color(255,0,0)      --赤
    ,DYELLOW=color(128,128,0)  --暗黄色
    ,YELLOW=color(255,255,0)  --黄色
    ,DGREEN=color(0,64,0)    --深緑
    ,GREEN=color(0,255,0)    --緑
    ,CYAN=color(0,255,255)    --シアン
    ,BLUE=color(0,0,255)    --青
    ,MAGENTA=color(255,0,255)  --マゼンタ
    ,LYELLOW=color(255,255,128)  --明黄色
    ,LGREEN=color(0,255,128)  --明緑
    ,RMAGENTA=color(255,0,128)  --赤マゼンタ
    ,BROWN=color(128,64,0)    --茶色
    ,RYELLOW=color(255,128,64)  --明茶色
  }
------------------------------------------
mt={}
mt.__newindex=function(mtt,mtn,mtv)
  dialog( "Error Message", "宣言していない変数 "..mtn.." に値を入れようとしています", 0 )
  toast("画面タッチで実行を続けます", 1)
  touch(3)
end
mt.__index=function(mtt,mtn)
  dialog( "Error Message", "変数 "..mtn.." は宣言されていません", 0 )
  toast("画面タッチで実行を続けます", 1)
  touch(3)
end
setmetatable(_G,mt)
--------以下が実プログラム----------------
------------------------------------------
--文字の分解
------------------------------------------
function split(str, d)
local s = str
local t = {}
local p = "%s*(.-)%s*"..d.."%s*"
local f = function(v)  table.insert(t, v)  end
  if s ~= nil then
    string.gsub(s, p, f)
    f(string.gsub(s, p, ""))
  end
  return t
end
------------------------------------------
--CSVファイルを読み込みます
------------------------------------------
function readdata( filename )
local fp
local msg
local str
local t={}
local i = 1
  --ファイルを開きます
  fp,msg = io.open( filename, "r")
  if( not(fp) )then
    dialog( Path..Fname.."がオープンできません","プログラムを終了します", 0 )
    return
  end
  --CSVデータを読み込みます
  while(true)do
    str = fp:read("*l")               --1行読み込み
    if( str==nil )then break end      --読込むデータが無ければ終了
    str = string.gsub( str,"\r","" )  --改行コードを外す

    t = split( str, "," )
    
    if( t[1]=="xtitle" )then Xtitle = t[2] end
    if( t[1]=="ytitle" )then Ytitle = t[2] end
    
    if( t[1]~="xtitle" and t[1]~="ytitle" )then
      Value.X[i] = t[1]
      Value.Y[i] = t[2]
      i = i + 1
    end
  end
  io.close(fp)
end
------------------------------------------
--X-Yグラフを描きます
------------------------------------------
function drawXYgraph()
local DXg = 50
local DYg = 50
local DXg0 = DXg    --X軸描画マージン
local DYg0 = DYg    --Y軸描画マージン
local MX = 10       --X軸目盛の間隔
local MY = 10       --Y軸目盛の間隔
local i
local LXg = 400     --X軸の長さ
local LYg = 230     --Y軸の長さ
local XdMax = 130
local XdMin = 0
local YdMax = 150
local YdMin = 0
local MXMax = math.modf(XdMax/MX) * MX                    --X軸の目盛の最大値を求める
local MXMin = MXMax - math.modf( (MXMax-XdMin)/MX ) * MX  --X軸の目盛の最小値を求める
local MYMax = math.modf(YdMax/MY) * MY                    --Y軸の目盛の最大値を求める
local MYMin = MYMax - math.modf( (MYMax-YdMin)/MY ) * MY  --Y軸の目盛の最小値を求める
local ATaX = LXg/( XdMax - XdMin )
local ATaY = LYg/( YdMax - YdMin )
local ms
local width, hight
  width, hight = canvas.getviewSize()
  --枠描画
  canvas.drawRect( DXg0, hight-DYg0, DXg0+LXg, hight-DYg0-LYg, Col.BLUE, 1 )
  canvas.drawRect( DXg0, hight-DYg0, DXg0+LXg, hight-DYg0-LYg, Col.WHITE )
  --X軸目盛りと目盛り数値のプロット
  i=MXMin
  while(true)do
    if( i>XdMax )then break end
    ms = (i-XdMin) * ATaX + DXg0
    canvas.drawLine( ms, hight-DYg0, ms, hight-DYg0-(LYg/40), Col.WHITE )
    canvas.drawLine( ms, hight-DYg0-LYg, ms, hight-DYg0-LYg+(LYg/40), Col.WHITE )
    local strmm = string.rep(" ", 5-string.len(i) )..i
    canvas.drawText( strmm, ms-20, hight-DYg0+4, 14, Col.WHITE )
    i = i + MX
  end
  canvas.drawTextCenter( Xtitle, DXg0+LXg/2, hight-DYg0+20, 20, Col.WHITE )
  --Y軸目盛りと目盛り数値のプロット
  i=MYMin
  while(true)do
    if( i>YdMax )then break end
    ms = hight - DYg0 - (i-YdMin)*ATaY
    canvas.drawLine( DXg0, ms, DXg0+(LYg/40),ms, Col.WHITE )
    canvas.drawLine( DXg0+LXg, ms, DXg0+LXg-(LYg/40), ms, Col.WHITE )
    local strmm = string.rep(" ", 5-string.len(i))..i
    canvas.drawText( strmm, DXg0-35, ms-5, 14, Col.WHITE )
    i = i + MY
  end
  canvas.drawTextBox( Ytitle, DXg0-48, hight-DYg0-LYg+80, 20, Col.WHITE, 25 )
  --グラフのプロット
  for i=1,#Value.X do
    canvas.drawCircle( DXg0+Value.X[i]*ATaX, hight-DYg0-Value.Y[i]*ATaY, 3, Col.WHITE, 1 )
  end
  --スプライン曲線のプロット  
  splineplot( XdMin, XdMax, DXg0, ATaX, hight-DYg0, ATaY )
end
------------------------------------------
--スプライン描画します
------------------------------------------
function splineplot( XdMin, XdMax, DXg, ATaX, DYg, ATaY )
local sp1={}
local sp2={}
local sp3={}
local y
local x
local x1, y1
local sosu = #Value.X

  --スプライン補間係数を求めます
  getSplineCoefficient( sp1, sp2, sp3 )
  x1 = tonumber(Value.X[1])
  y1 = tonumber(Value.Y[1])
  for x=XdMin, XdMax do
    if( x<tonumber(Value.X[sosu]) and x>tonumber(Value.X[1]) )then
      y = spline( x, sp1, sp2, sp3 )
      canvas.drawLine( DXg+x1*ATaX, DYg-y1*ATaY-1, DXg+x*ATaX, DYg-y*ATaY-1, Col.GREEN )
      canvas.drawLine( DXg+x1*ATaX, DYg-y1*ATaY, DXg+x*ATaX, DYg-y*ATaY, Col.GREEN )
      canvas.drawLine( DXg+x1*ATaX, DYg-y1*ATaY+1, DXg+x*ATaX, DYg-y*ATaY+1, Col.GREEN )
      x1 = x
      y1 = y
    end
  end
  canvas.drawLine( DXg+x1*ATaX, DYg-y1*ATaY-1, DXg+tonumber(Value.X[sosu])*ATaX, DYg-tonumber(Value.Y[sosu])*ATaY-1, Col.GREEN )
  canvas.drawLine( DXg+x1*ATaX, DYg-y1*ATaY, DXg+tonumber(Value.X[sosu])*ATaX, DYg-tonumber(Value.Y[sosu])*ATaY, Col.GREEN )
  canvas.drawLine( DXg+x1*ATaX, DYg-y1*ATaY+1, DXg+tonumber(Value.X[sosu])*ATaX, DYg-tonumber(Value.Y[sosu])*ATaY+1, Col.GREEN )
end
------------------------------------------
--スプライン補間係数を求めます
------------------------------------------
function getSplineCoefficient( sp1, sp2, sp3 )
local i
local sp4
local sp5
local sp6
local sp7
local sp8
local sp9
local sp10
local sp11
local sp={}
local sosu = #Value.X
  i = 2
  sp8 = (Value.Y[i]-Value.Y[i-1])/(Value.X[i]-Value.X[i-1])
  sp9 = (Value.Y[i+1]-Value.Y[i])/(Value.X[i+1]-Value.X[i]) - sp8
  sp10= sp9/(Value.X[i+1]-Value.X[i-1])
  sp11= sp8 - sp10*(Value.X[i]+Value.X[i-1])
  sp[i] = 2*sp10*Value.X[i] + sp11
  i = 1
  sp[i] = 2*sp10*Value.X[i] + sp11
  for i=3, sosu-1 do
    sp8 = (Value.Y[i]-Value.Y[i-1])/(Value.X[i]-Value.X[i-1])
    sp9 = (Value.Y[i+1]-Value.Y[i])/(Value.X[i+1]-Value.X[i]) - sp8
    sp10= sp9/(Value.X[i+1]-Value.X[i-1])
    sp11= sp8 - sp10*(Value.X[i]+Value.X[i-1])
    sp[i] = 2*sp10*Value.X[i] + sp11
  end
  i = sosu
  sp[i] = 2*sp10*Value.X[i] + sp11
  for i=1,sosu-1 do
    sp4 = Value.X[i+1] - Value.X[i]
    sp5 = sp[i] * sp4
    sp6 = 3*Value.Y[i+1] - sp[i+1]*sp4 - 3*Value.Y[i] - 2*sp5
    sp7 = Value.Y[i+1] - Value.Y[i] - sp5 - sp6
    sp1[i] = sp5 / sp4
    sp2[i] = sp6/( sp4*sp4 )
    sp3[i] = sp7/( sp4*sp4*sp4 )
  end
end
------------------------------------------
-- スプライン補間
------------------------------------------
function spline( x, sp1, sp2, sp3 )
local i
local g
local v
  for i=1, #Value.X-1 do
    g = i
    if( x<tonumber(Value.X[i+1]) )then
      break
    end
  end
  i = g
  v = x - Value.X[i]
  return( Value.Y[i] + sp1[i]*v + sp2[i]*v*v + sp3[i]*v*v*v )
end

------------------------------------------
--メインプログラム
------------------------------------------
function main()
local i
  --CSVファイルを読み込みます
  readdata( Path..Fname )
  canvas.drawCls( color(0,0,0) )
  --グラフを描きます
  drawXYgraph()
  toast( "タッチ待ちしています", 0 )
  touch(3)
end
main()