myBlog

IronPython, Silverlight, WPF, XAML, HTML5, ...

IronPythonで、お掃除ロボット( Xamloomba )を動かす!

2011-07-12 15:53:17 | Animation
WPF/IronPythonで、Silverlightアニメーション(お掃除ロボット)を実行できるようにする。

ネットを検索していると、このSilverlightプログラムが目にとまった。
さっそく、IronPythonで、動かすことにした。少しアレンジしています。

デザインツールで始めるSilverlightアニメ/グラフィック
Silverlight 2で.NET技術をカッコよく使おう(3)
http://www.atmarkit.co.jp/fwcr/rensai2/silverlight2_03/silverlight2_03_3.html

お部屋のXAML ⇒ room.xaml ⇒ フローリング
http://softgarden.lovepop.jp/myBlog/xaml/room.xaml
お掃除ロボットXAML ⇒ loomba.xaml ⇒ ザムルンバ(Xamloomba)君
http://softgarden.lovepop.jp/myBlog/xaml/loomba.xaml

フローリングの好きな位置をクリックすると、Xamloomba君がその方向に回転した後に目的地まで移動します。
この処理はStoryboardを動的に生成して実行して実現していますので、詳しくはソースを確認してください .…

Myloomba    


# myLoomba.py
#
import clr
clr.AddReferenceByPartialName("PresentationFramework")
clr.AddReferenceByPartialName("PresentationCore")
clr.AddReference('WindowsBase')  # for Point
from System import Object, TimeSpan, Math
from System.Windows.Markup import XamlReader
from System.Windows import ( 
        Window, Application, Point, Duration, PropertyPath,
        HorizontalAlignment, VerticalAlignment )
from System.Windows.Controls import Canvas, StackPanel
from System.Windows.Media.Animation import ( 
        Storyboard, RepeatBehavior, DoubleAnimation, 
        DoubleAnimationUsingKeyFrames, SplineDoubleKeyFrame, KeyTime )
from System.Windows.Media import RotateTransform

def LoadXamlNet(strUrl):
    import System
    request = System.Net.WebRequest.Create(strUrl)
    response = request.GetResponse()
    dataStream = response.GetResponseStream()
    try:
        element = XamlReader.Load(dataStream)
    finally:
        dataStream.Close()
        response.Close()
    return element

class Loomba(Object):
    SpeedPerSec = 100
    SpeedTurn = 2
    def __init__(self):
        self.Content = uc =  LoadXamlNet("http://softgarden.lovepop.jp/myBlog/xaml/loomba.xaml")
        self.loomba = uc.FindName('loomba')    
        setattr(self, "turnLeft", uc.FindName('turnLeft'))   
        setattr(self, "turnRight", uc.FindName('turnRight'))  
        setattr(self, "flushlight", uc.FindName('flushlight'))
        setattr(self, "loombaRotate", uc.FindName('loombaRotate'))

    def StopCurrentAction(self):
        self.turnLeft.Pause()
        self.turnRight.Pause()

    def Move(self, dest):
        self.StopCurrentAction()
        original = self.GetOriginalPosition()
        current = self.GetCurrentPosition()
        distance = self.GetDistanceTo(dest)
        angle = self.GetAngleTo(dest)
        currentAngle = self.GetCurrentAngle()

        angle2 = angle # 0.0 ~ 360.0 へ
        if (angle < 0.0 ):
            angle2 = 360.0 + angle
        currentAngle2 = currentAngle % 360.0
        by = angle2 - currentAngle2
        if by > 180.0 :
            by -= 360.0
        elif by < -180.0 :
            by += 360.0

        #//回転に要する時間
        #turnTime = TimeSpan.FromSeconds(Math.Abs(self.GetCurrentAngle() - angle) * 2 / 360)
        turnTime = TimeSpan.FromSeconds( ( Math.Abs(by) *  2.0 ) / 360.0 )

        #//目的地までの所要時間
        time = TimeSpan.FromSeconds(distance / self.SpeedPerSec)

        #//ストーリーボードを作成
        sb = Storyboard()

        #//ストーリーボードの所要時間を設定
        sb.Duration = time.Add(turnTime)

        #//回転用のアニメーション
        turnAnimation = DoubleAnimation()
        #turnAnimation.To = angle
        turnAnimation.By = by
        turnAnimation.Duration = Duration(turnTime)
        sb.Children.Add(turnAnimation)

        Storyboard.SetTarget(turnAnimation, self.loomba)
        Storyboard.SetTargetProperty(turnAnimation, 
            PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"))
  
        #//縦方向移動アニメーション
        topAnimation = DoubleAnimationUsingKeyFrames()
        topAnimation.BeginTime = turnTime #//回転終了後に開始
        topKf = SplineDoubleKeyFrame()
        topKf.KeyTime = KeyTime.FromTimeSpan(time)
        topKf.Value = dest.Y - original.Y
        topAnimation.KeyFrames.Add(topKf)
        sb.Children.Add(topAnimation)

        Storyboard.SetTarget(topAnimation, self.loomba);
        Storyboard.SetTargetProperty(topAnimation,
            PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"))

        #//横方向移動アニメーション
        leftAnimation = DoubleAnimationUsingKeyFrames()
        leftAnimation.BeginTime = turnTime #//回転終了後に開始
        leftKf = SplineDoubleKeyFrame()
        leftKf.KeyTime = KeyTime.FromTimeSpan(time)
        leftKf.Value = dest.X - original.X
        leftAnimation.KeyFrames.Add(leftKf)
        sb.Children.Add(leftAnimation)

        Storyboard.SetTarget(leftAnimation, self.loomba)
        Storyboard.SetTargetProperty(leftAnimation, 
            PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"))
        #//ストーリーボードを実行
        sb.Begin();

    def GetOriginalPosition(self):
        this=self.Content 
        original = Point(Canvas.GetLeft(this), Canvas.GetTop(this))
        return original
    def GetCurrentPosition(self):
        original = self.GetOriginalPosition()
        trans = (self.loomba.RenderTransform).Children[3]
        current = Point(original.X + trans.X, original.Y + trans.Y)
        return current
    def GetCurrentAngle(self):
        trans = (self.loomba.RenderTransform).Children[2]
        return trans.Angle
    def GetDistanceTo(self,dest):
        current = self.GetCurrentPosition()
        dx = current.X - dest.X;
        dy = current.Y - dest.Y;
        return Math.Sqrt(dx * dx + dy * dy)
    def GetAngleTo(self,dest):
            current = self.GetCurrentPosition()
            dx = current.X - dest.X
            dy = current.Y - dest.Y
            return Math.Atan2(dy, dx) * 180 / Math.PI - 90

class ExWindow(Object):
    def __init__(self, Content=None, **keywords):
        self.Root = win = Window(**keywords)
        aUserControl = LoadXamlNet("http://softgarden.lovepop.jp/myBlog/xaml/room.xaml")
        aUserControl.FindName('floor').MouseLeftButtonDown+=self.Border_MouseLeftButtonDown
        aUserControl.FindName('leftButton').Click+=self.leftButton_Click
        aUserControl.FindName('startFlush').Click+=self.startFlush_Click
        aUserControl.FindName('rightButton').Click+=self.rightButton_Click
        setattr(self, "floor", aUserControl.FindName('floor'))
        self.swFlush = 0
        
        self.myLoomba = Loomba()
        self.myLoomba.Content.RenderTransformOrigin = Point(0.5,0.5)
        self.myLoomba.Content.HorizontalAlignment = HorizontalAlignment.Center
        self.myLoomba.Content.VerticalAlignment = VerticalAlignment.Center
 
        self.myLoomba.Content.Width = 100
        self.myLoomba.Content.Height = 100
        Canvas.SetLeft(self.myLoomba.Content,250)
        Canvas.SetTop(self.myLoomba.Content,200)

        canvas=aUserControl.FindName('myLoombaCanvas')
        canvas.AddChild(self.myLoomba.Content)

        win.Content = aUserControl

    def Border_MouseLeftButtonDown(self,sender, e):
        #//マウス位置を取得
        mouse = e.GetPosition(self.floor)
        #//マウス位置は左上のため、中心点を取得
        dest = Point(mouse.X - 50, mouse.Y - 50)
        #//XamLoombaの移動
        self.myLoomba.Move(dest)
 
    def leftButton_Click(self,sender, e):
        #//左へ回転
        self.myLoomba.turnLeft.Begin()

    def rightButton_Click(self,sender, e):
        #//右へ回転
        self.myLoomba.turnRight.Begin()

    def startFlush_Click(self,sender, e):
        #//RepeatBehavior.Foreverを設定することにより、動作を永遠に続けます
        self.myLoomba.flushlight.RepeatBehavior = RepeatBehavior.Forever
        if self.swFlush == 0:
            #//フラッシュを開始
            self.myLoomba.flushlight.Begin()
            self.swFlush = 3
        elif self.swFlush == 1:
            #//フラッシュを中断
            self.myLoomba.flushlight.Pause()
            self.swFlush = 2
        elif self.swFlush == 2:
            #//フラッシュを再開
            self.myLoomba.flushlight.Resume()
            self.swFlush = 1
        else:
            #//フラッシュを停止
            self.myLoomba.flushlight.Stop()
            self.swFlush = 0

if __name__ == "__main__":
    win = ExWindow( Width=608, Height=432 ,Title="myLoomba.py")
    Application().Run(win.Root)




IronPythonの世界 (Windows Script Programming)
荒井 省三
ソフトバンク クリエイティブ
エキスパートPythonプログラミング
Tarek Ziade
アスキー・メディアワークス
Pythonスタートブック
辻 真吾
技術評論社

最新の画像もっと見る

コメントを投稿