none
マウスの動きに合わせてオブジェクトを回転させたい RRS feed

  • 質問

  • Ellipseをマウスの動きに合わせて、ぐるぐると回転させるPGを作っております。

    やり方としては、以下のサイトなどを参考に
    マウスの座標(始点と終点の2点座標)を取得し、
    Atan2メソッドで角度を求め、
    RotateTransformで回転するようにしております。
    http://www25.atwiki.jp/guru/pages/51.html
    http://hakuhin.hp.infoseek.co.jp/main/as/math.html#MATH_01


    ところが回転が1周もしないうちに途中で逆回転してしまうのです。
    逆回転した後、Ellipseの真ん中のラベルにマウスを当てると「正常」に回転する動きになるのですが・・・。
    ※ここで言う「正常」な動きとは、何周でもマウスに合わせて回転出来る動きです。


    原因がまったく分からず投稿させていただきました。


    どうかアドバイス宜しくお願い致します。

    <Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" 
        
        Height="511" Width="453">
        <Grid>
            <Ellipse 
                MouseEnter="myEllipse_MouseEnter"
                
                MouseMove="myEllipse_MouseMove"
               
                Margin="78,224,71,21" Name="myEllipse" Stroke="Black">
                <Ellipse.Fill>
                    <LinearGradientBrush  StartPoint="0,0.1" EndPoint="2,3">
                        <GradientStop Color="Yellow"/>
                        <GradientStop Color="Black" Offset="0.254"/>
                    </LinearGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
            <Label Height="42" Margin="185,12,126,0" Name="label1" VerticalAlignment="Top" FontSize="18" Background="RoyalBlue"></Label>
            <Label Background="RoyalBlue" FontSize="18" Height="42" Margin="185,60,126,0" Name="lblFirstPoint" VerticalAlignment="Top" />
            <Label Background="RoyalBlue" FontSize="18" Height="42" Margin="185,108,126,0" Name="lblLastPoint" VerticalAlignment="Top" />
            <Label Background="Gray" FontSize="12" Height="42" Margin="85,60,0,0" Name="label4" VerticalAlignment="Top" HorizontalAlignment="Left" Width="90">MouseEnter時座標</Label>
            <Label Background="Gray" FontSize="12" Height="42" Margin="85,108,0,0" Name="label5" VerticalAlignment="Top" HorizontalAlignment="Left" Width="90">MouseMove時座標</Label>
            <Label Background="RoyalBlue" FontSize="18" Height="31" Margin="198,0,186,112" Name="lblTarget" VerticalAlignment="Bottom">回転</Label>
            <Label Background="Gray" FontSize="12" Height="42" HorizontalAlignment="Left" Margin="84,12,0,0" Name="label2" VerticalAlignment="Top" Width="90">角度</Label>
        </Grid>
    </Window>
    


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    
    namespace WpfApplication1
    {
        /// <summary>
        /// Window1.xaml の相互作用ロジック
        /// </summary>
        public partial class Window1 : Window
        {
    
            Point FirstPoint;
            Point CurrentPoint;
    
            public Window1()
            {
                InitializeComponent();
            }
    
            private void myEllipse_MouseEnter(object sender, MouseEventArgs e)
            {
                //マウス座標
                FirstPoint = e.GetPosition(this);
                CurrentPoint = e.GetPosition(this);
    
                //debug
                lblFirstPoint.Content = FirstPoint.X + "," + FirstPoint.Y;
            }
    
            private void myEllipse_MouseMove(object sender, MouseEventArgs e)
            {
    
                //マウス座標
                CurrentPoint = e.GetPosition(this);
    
                //debug
                lblLastPoint.Content = CurrentPoint.X + "," + CurrentPoint.Y;
    
                
                //角度
                double dblKakudo = Math.Atan2(CurrentPoint.Y - FirstPoint.Y, CurrentPoint.X - FirstPoint.X) * 180 / Math.PI;
    
                //debug
                label1.Content = (int)dblKakudo + "度";
    
                //回転クラス生成
                RotateTransform myRotateTran1 = new RotateTransform();
                RotateTransform myRotateTran2 = new RotateTransform();
    
                //回転時の中心座標 円
                myRotateTran1.CenterX = myEllipse.ActualWidth / 2;
                myRotateTran1.CenterY = myEllipse.ActualHeight / 2;
                myRotateTran1.Angle = (int)dblKakudo;
    
                //回転時の中心座標 ラベル
                myRotateTran2.CenterX = lblTarget.ActualWidth / 2;
                myRotateTran2.CenterY = lblTarget.ActualHeight / 2;
                myRotateTran2.Angle = (int)dblKakudo;
    
    
                //変換実行
                myEllipse.RenderTransform = myRotateTran1;
                lblTarget.RenderTransform = myRotateTran2;
            }
    
            
    
        }
    }
    
    2010年2月2日 1:30

回答

  • 回答済みになったのでヒントではなく動作確認したプログラムをUPします。

        public partial class Window1 : Window
        {
            Point CenterPoint;
            Point FirstPoint;
            Point CurrentPoint;
            double FirstKakudo;
    
            public Window1()
            {
                InitializeComponent();
            }
    
            private void myEllipse_MouseEnter(object sender, MouseEventArgs e)
            {
                Rect rect = myEllipse.RenderedGeometry.Bounds;
                Point center = myEllipse.PointToScreen(new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2));
                CenterPoint = this.PointFromScreen(center);
                FirstKakudo = Math.Atan2(FirstPoint.Y - CenterPoint.Y, FirstPoint.X - CenterPoint.X) * 180 / Math.PI;
    
                //マウス座標
                FirstPoint = e.GetPosition(this);
                CurrentPoint = e.GetPosition(this);
    
                //debug
                lblFirstPoint.Content = FirstPoint.X + "," + FirstPoint.Y;
            }
    
            private void myEllipse_MouseMove(object sender, MouseEventArgs e)
            {
                //マウス座標
                CurrentPoint = e.GetPosition(this);
    
                //debug
                lblLastPoint.Content = CurrentPoint.X + "," + CurrentPoint.Y;
    
                //角度
                double dblKakudo = Math.Atan2(CurrentPoint.Y - CenterPoint.Y, CurrentPoint.X - CenterPoint.X) * 180 / Math.PI;
                dblKakudo = dblKakudo - FirstKakudo;
    
                //debug
                label1.Content = (int)dblKakudo + "度";
    
                //回転クラス生成
                RotateTransform myRotateTran1 = new RotateTransform();
                RotateTransform myRotateTran2 = new RotateTransform();
    
                //回転時の中心座標 円
                myRotateTran1.CenterX = myEllipse.ActualWidth / 2;
                myRotateTran1.CenterY = myEllipse.ActualHeight / 2;
                myRotateTran1.Angle = (int)dblKakudo;
    
                //回転時の中心座標 ラベル
                myRotateTran2.CenterX = lblTarget.ActualWidth / 2;
                myRotateTran2.CenterY = lblTarget.ActualHeight / 2;
                myRotateTran2.Angle = (int)dblKakudo;
    
                //変換実行
                myEllipse.RenderTransform = myRotateTran1;
                lblTarget.RenderTransform = myRotateTran2;
            }
        }
    


    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2010/12
    • 回答としてマーク sumi_sumi 2010年2月10日 0:46
    2010年2月9日 8:48
  • くるくる回したいのであれば FirstPoint と myEllipse の中心を結ぶ線、CurrentPoint と  myEllipse の中心を結ぶ線、2つの線の角度を求めなければいけないと思います。

    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2010/12
    2010年2月2日 6:21

すべての返信

  • くるくる回したいのであれば FirstPoint と myEllipse の中心を結ぶ線、CurrentPoint と  myEllipse の中心を結ぶ線、2つの線の角度を求めなければいけないと思います。

    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2010/12
    2010年2月2日 6:21
  • えムナウ様

    お返事有難う御座います。

    おっしゃる意味は分かりましたが、
    実装手順がさっぱり分かりません(;_;)

    最初にやることは
    「myEllipse の中心座標を求める」
    ことでしょうか・・・・?

     

    >FirstPoint と myEllipse の中心を結ぶ線
    実際に直線を引くわけではないですよね・・・?
    ここからもどうして良いか分かりません・・・。


    すみませんが、あと少しヒントを頂けませんでしょうか?
    理解力がなくて本当にすいません。。。

    2010年2月3日 7:17
  • Point CenterPoint; を Window1 クラスのローカル変数に定義されているとして中心点は以下のコードでもとまります。
    最初の点と中心点の角度を myEllipse_MouseEnter で求めておいて、myEllipse_MouseMove では CurrentPoint と中心点の角度を求めて、角度の差を Angle に入れればいいです。

                Rect rect = myEllipse.RenderedGeometry.Bounds;
                Point center = myEllipse.PointToScreen(new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2));
                CenterPoint = this.PointFromScreen(center);

    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2010/12
    • 回答としてマーク 高橋 春樹 2010年2月9日 8:40
    • 回答としてマークされていない sumi_sumi 2010年2月10日 0:46
    2010年2月3日 7:25
  • フォーラムオペレーターの高橋春樹です。

    えムナウさん、いつもお世話になっております。
    サンプルコードも出して頂き、有難うございました。

    sumi_tanaさん、初めまして。
    MSDNフォーラムのご利用有難うございます。
    えムナウさんからアドバイスを頂いたと思うのですが、試して頂けたでしょうか?

    えムナウさんからのアドバイスが、有用な情報と思いましたので
    勝手ながら、回答マークを付けさせて頂きました。

    sumi_tanaさんの現在の状況も気になるので、
    えムナウさんの投稿に、返信して頂けると助かります(^_^)


    マイクロソフト株式会社 フォーラム オペレーター 高橋春樹
    2010年2月9日 8:43
  • 回答済みになったのでヒントではなく動作確認したプログラムをUPします。

        public partial class Window1 : Window
        {
            Point CenterPoint;
            Point FirstPoint;
            Point CurrentPoint;
            double FirstKakudo;
    
            public Window1()
            {
                InitializeComponent();
            }
    
            private void myEllipse_MouseEnter(object sender, MouseEventArgs e)
            {
                Rect rect = myEllipse.RenderedGeometry.Bounds;
                Point center = myEllipse.PointToScreen(new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2));
                CenterPoint = this.PointFromScreen(center);
                FirstKakudo = Math.Atan2(FirstPoint.Y - CenterPoint.Y, FirstPoint.X - CenterPoint.X) * 180 / Math.PI;
    
                //マウス座標
                FirstPoint = e.GetPosition(this);
                CurrentPoint = e.GetPosition(this);
    
                //debug
                lblFirstPoint.Content = FirstPoint.X + "," + FirstPoint.Y;
            }
    
            private void myEllipse_MouseMove(object sender, MouseEventArgs e)
            {
                //マウス座標
                CurrentPoint = e.GetPosition(this);
    
                //debug
                lblLastPoint.Content = CurrentPoint.X + "," + CurrentPoint.Y;
    
                //角度
                double dblKakudo = Math.Atan2(CurrentPoint.Y - CenterPoint.Y, CurrentPoint.X - CenterPoint.X) * 180 / Math.PI;
                dblKakudo = dblKakudo - FirstKakudo;
    
                //debug
                label1.Content = (int)dblKakudo + "度";
    
                //回転クラス生成
                RotateTransform myRotateTran1 = new RotateTransform();
                RotateTransform myRotateTran2 = new RotateTransform();
    
                //回転時の中心座標 円
                myRotateTran1.CenterX = myEllipse.ActualWidth / 2;
                myRotateTran1.CenterY = myEllipse.ActualHeight / 2;
                myRotateTran1.Angle = (int)dblKakudo;
    
                //回転時の中心座標 ラベル
                myRotateTran2.CenterX = lblTarget.ActualWidth / 2;
                myRotateTran2.CenterY = lblTarget.ActualHeight / 2;
                myRotateTran2.Angle = (int)dblKakudo;
    
                //変換実行
                myEllipse.RenderTransform = myRotateTran1;
                lblTarget.RenderTransform = myRotateTran2;
            }
        }
    


    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2010/12
    • 回答としてマーク sumi_sumi 2010年2月10日 0:46
    2010年2月9日 8:48
  • 高橋 春樹 様

    >えムナウさんからアドバイスを頂いたと思うのですが、試して頂けたでしょうか?
    当然です。
    試したとしても、完全に「解決」ではないですよね。
    中心点を求めた後の部分にとりかかっておりました。


    えムナウ様にいただいたアドバイスを元に実装中でした。
    というよりは、三角形の勉強からしておりました。
    角度を求めるには必要と思いまして。


    いつの間にか「解決」になってて驚きました。
    2010年2月10日 0:40
  • えムナウ 様

    いつも本当に有難う御座います。

    せっかくヒントいただいたのに中心点を求めた後からを実装出来ませんでした・・・。
    あれ以降、三角形の勉強が必要と思い色々なサイトでサイン・コサインなど勉強しておりました。
    まったく覚えておらず泣きそうでした(;_;)

    途中結果を報告すれば良かったです。

    最終的に答え(コード)まで書いていただき申し訳ないです。

    本当に有難う御座います。

    2010年2月10日 0:46