none
wpf オブジェクトの重なりの判定 RRS feed

  • 質問

  • wpfでマウスを使わずに1つのオブジェクトを動かし、

    2つのオブジェクトのレイヤーが重なったときにイベントを発生させたいです。

    四角形では座標を指定することで出来たのですが、多角形でのやり方が分かりません。

    どうしたら良いでしょうか。ご回答よろしくお願いします。


    • 編集済み hk5122 2016年12月1日 3:04
    2016年12月1日 3:04

回答

  • オブジェクトというのがGeometry同士の重なりであるならば、Geometry.Combineで重なりを得られます。
    #Geometryでは無いなら、そのオブジェクトの外形と等価なGeometryを作れば

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Shapes;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            private System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
            private RectangleGeometry rect = new RectangleGeometry() { Rect = new Rect(0, 0, 100, 100) };
            private EllipseGeometry elli = new EllipseGeometry() { RadiusX = 30, RadiusY = 100 };
    
            public MainWindow()
            {
                InitializeComponent();
    
                // InitializeComponent() 呼び出しの後で初期化を追加します。
    
                TransformGroup rtran = new TransformGroup();
                rtran.Children.Add(new RotateTransform(0) { CenterX = 50, CenterY = 50 });
                rtran.Children.Add(new TranslateTransform(300, 100));
                rect.Transform = rtran;
    
                elli.Transform = new TranslateTransform(50, 100);
                var c = new Canvas();
    
                var pathRect = new Path() { Data = rect, Fill = Brushes.Red };
                var pathEllipse = new Path() { Data = elli, Fill = Brushes.Green };
                c.Children.Add(pathRect);
                c.Children.Add(pathEllipse);
    
                this.Content = c;
    
                timer.Interval = TimeSpan.FromMilliseconds(10);
                timer.Start();
    
                timer.Tick += timer_Tick;
            }
    
            void timer_Tick(object sender, EventArgs e)
            {
                ((TranslateTransform)elli.Transform).X += 5;
                ((RotateTransform)((TransformGroup)rect.Transform).Children[0]).Angle += 5;//回転
    
                PathGeometry intersect = Geometry.Combine(rect, elli, GeometryCombineMode.Intersect, null);
                if (!intersect.IsEmpty())
                {
                    MessageBox.Show("重なったよ");
    
                    //timer.Stop();
                }
            }
        }
    }

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2016年12月1日 4:07
  • VisualTreeHelper.HitTest(Visual, HitTestFilterCallback, HitTestResultCallback, HitTestParameters)

    でヒットテストするとか。

    2016年12月1日 3:58

すべての返信

  • VisualTreeHelper.HitTest(Visual, HitTestFilterCallback, HitTestResultCallback, HitTestParameters)

    でヒットテストするとか。

    2016年12月1日 3:58
  • オブジェクトというのがGeometry同士の重なりであるならば、Geometry.Combineで重なりを得られます。
    #Geometryでは無いなら、そのオブジェクトの外形と等価なGeometryを作れば

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Shapes;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            private System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
            private RectangleGeometry rect = new RectangleGeometry() { Rect = new Rect(0, 0, 100, 100) };
            private EllipseGeometry elli = new EllipseGeometry() { RadiusX = 30, RadiusY = 100 };
    
            public MainWindow()
            {
                InitializeComponent();
    
                // InitializeComponent() 呼び出しの後で初期化を追加します。
    
                TransformGroup rtran = new TransformGroup();
                rtran.Children.Add(new RotateTransform(0) { CenterX = 50, CenterY = 50 });
                rtran.Children.Add(new TranslateTransform(300, 100));
                rect.Transform = rtran;
    
                elli.Transform = new TranslateTransform(50, 100);
                var c = new Canvas();
    
                var pathRect = new Path() { Data = rect, Fill = Brushes.Red };
                var pathEllipse = new Path() { Data = elli, Fill = Brushes.Green };
                c.Children.Add(pathRect);
                c.Children.Add(pathEllipse);
    
                this.Content = c;
    
                timer.Interval = TimeSpan.FromMilliseconds(10);
                timer.Start();
    
                timer.Tick += timer_Tick;
            }
    
            void timer_Tick(object sender, EventArgs e)
            {
                ((TranslateTransform)elli.Transform).X += 5;
                ((RotateTransform)((TransformGroup)rect.Transform).Children[0]).Angle += 5;//回転
    
                PathGeometry intersect = Geometry.Combine(rect, elli, GeometryCombineMode.Intersect, null);
                if (!intersect.IsEmpty())
                {
                    MessageBox.Show("重なったよ");
    
                    //timer.Stop();
                }
            }
        }
    }

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2016年12月1日 4:07