読者です 読者をやめる 読者になる 読者になる

Powerpoint VBAを使おう!

Powerpoint VBAやExcelのVBAで遊んでいます。Word VBAも始めました。

波をVBAで描く方法 Collectionで各点の値を保持

Powerpoint VBA

また明日から忙しいんですが,波動をやろうというのはあきらめていません。

まぁ悩んでてうまいこと答えがしばらく出せていませんでした。

配列に波のポイントを入れようと思っていたわけですが,次々に始点のほうに値を追加する形でポイントを追加していかないと,波が逆行します。

以前配列で作ったときはそれに気づいていませんでしたが,配列は後に後に追加するんですが,波は波源の変位を常に最初のポイントに追加し,スライドしていかないといけない。

で,それを最初はShapeNodeでやっていたんですが,極めて重くなっていくので無理だったんです。

最初に追加するねぇ・・・と一回一回配列の中身をインデックスを1追加したものに放り込んでずらしておいて,インデックス1のところに波源の値を入れるかぁとか考えていました。

今日,職場でちょっとVBAHandBookを眺めていて,こんな文章がありました。

VBA provides two built-in data structures:arrays and collections.
Each has its good and bad points,
and there are compelling reasons to use each of these structures.
(VBA DEVELOPER'S HANDBOOK Second Edition p.432)

この短いフレーズなら著作権問題ない・・と思う。

Chapter 6: Creating Dynamic Data Structures Using Class Modules
ちょうど,この部分についてはMSDNに少しのってましたので,リンク貼っておきます。検索で出てきた。

compelling reasons っていう言い回しがカッコイイナァ!とか思いながら読んでいたんですが,

あぁ 最初に値を追加するとか Collectionなら簡単にデキルジャナイカ!とまたしてもお風呂で気づきました。いつもお風呂(;´▽`A``

配列に疎いだけで本当はあるのかもしれませんが,とりあえず最初にポイントを追加するという,私にとっての波のイメージに近い方法でばたばたとコレクションを使い組みました。

いつも持ち歩ているSDカードを持って帰り忘れたので,0からどたばた組んだのでコードはひどいですが,まぁ載せます。

見た目はまったく進歩していませんが,中身の考え方が変わっているので,少し進歩した気分です。

Option Explicit
Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwmiliseconds As Long)
Const dP As Currency = 2 * 3.1415 / 20
Const StartX As Long = 80
Const StartY As Long = 270
Const dX As Long = 5
Const a As Long = 100
Sub wavetest()
    ActivePresentation.SlideShowSettings.Run
    
    Dim WavePoints As Collection: Set WavePoints = New Collection
    Dim Y As Currency
    
    Dim phase As Currency
    Dim i As Long
    Dim drwWave As FreeformBuilder
    Dim ShpWave As Shape
    Dim TSlide As Slide: Set TSlide = ActivePresentation.Slides(1)
    Dim Shp波源 As Shape
    TSlide.Shapes.Range.Delete
    
    Set Shp波源 = TSlide.Shapes.AddShape(msoShapeOval, StartX - 5, StartY, 10, 10)
    Shp波源.Fill.ForeColor.RGB = vbRed
    Shp波源.Fill.Visible = msoTrue
    
    Do
        On Error Resume Next
            ShpWave.Delete
        On Error GoTo 0
        Y = a * Sin(phase)
        If WavePoints.Count >= 1 Then
            WavePoints.Add Y, before:=1
        Else
            WavePoints.Add Y
        End If
    
        phase = phase + dP
        If WavePoints.Count = 161 Then WavePoints.Remove 161
        
        If WavePoints.Count >= 2 Then
            Set drwWave = TSlide.Shapes.BuildFreeform(msoEditingAuto, StartX, StartY - WavePoints(1))
            Shp波源.Top = StartY - WavePoints(1) - 5
            For i = 2 To WavePoints.Count
                drwWave.AddNodes msoSegmentLine, msoEditingAuto, StartX + (i - 1) * dX, StartY - WavePoints(i)
            Next
            Set ShpWave = drwWave.ConvertToShape
            ShpWave.Line.Weight = 2
            ShpWave.Line.ForeColor.RGB = vbBlue
        End If
        
        Shp波源.TextFrame.TextRange = " "
        
        DoEvents
        Sleep 50
    Loop
End Sub

f:id:chemiphys:20170220222531g:plain

こんな感じです。
見た目は今までと変わらないですね。ただ,無理に逆行させないようにこじつけていた以前と違い,この挙動はわたしのイメージにとても近い。

次の悩みは波長λと周期Tをコードにどう絡めていくかです。
時間の代わりのカウンタは整数値でいきたい。横方向のピクセル間隔も5で固定し,160ポイント固定にしたい。

そこに波長,周期,速さとかの概念をきちんと表現していくにはどーしたらいいのか考えています。

なんとなくそれっぽい,を制御しやすくそれっぽい数式を与えやすくしたいとなると,きちんと自分なりに定義を加えていかないといけないので,ちょい難しいんですが,

ガンバロウ。

追記 書いてからしばらく考えてみましたが,やっぱりこの題材にはコレクションいいですね。

中途半端な地点に波源を置いて,そこでデータが発生していく場合もあるインデックスにデータを挿入していって,末尾を消していくとか,または始点を消していくことでX軸正・負どちらの方向に進む波も簡単にいける気がしてきました。

配列でこれらをやろうとすると,大変そうだもんな。

データをずらす,という用途に対してコレクションってものすごく便利な気がシテキタ

追記 止めるボタン入れ忘れていたので,Ctrl+Breakとかで止めてください。DoEventsとSleep入れているので,すぐ止まってくれると思います。