【问题标题】:Detect if mouse move in circle way检测鼠标是否以圆形方式移动
【发布时间】:2015-03-20 18:49:17
【问题描述】:

我尝试实现鼠标移动跟踪,当鼠标以圆形或矩形方式移动时显示特定消息。

bool IsWithinCircle(int centerX, int centerY, int mouseX, int mouseY, double radius) 
{
    int diffX = centerX - mouseX;
    int diffY = centerY - mouseY;
    return  (diffX * diffX + diffY * diffY) <= radius * radius;
}

我使用鼠标位置使用此功能检测圆形。 还有其他方法可以检测鼠标移动吗?
能否提供一些示例代码或链接?

【问题讨论】:

  • 您当前的代码没有做哪些您想做的事情?
  • @NextInLine 我的代码在很多情况下都不能正常工作
  • 'move in circle' 可以表示'在一个圆圈内移动'或'在圆周运动中移动'
  • @TaW 做圆周运动
  • @TaW 我尝试实现激光交互技术,我真的实现了每一个东西,但是当用户想要选择特定的东西时必须在它上面画一个圆形或矩形来执行他的动作

标签: c# computer-vision mouseevent mouse geometry


【解决方案1】:

您可能希望将鼠标移动跟踪为一系列线段,并使用这些线段创建一个近似圆。如果圆的中心保持相对一致,则说明用户在绕圈移动。

他们的关键是任何两个连续的线段都近似于圆弧。从中心到这些线段的法线(法线是垂直线)形成穿过圆心的线。当您有两个或更多法线时,您可以计算圆心。如果该中心在用户移动鼠标时保持相对一致,并且围绕圆心的法线的角度是顺时针或逆时针方向,那么你就有了一个圆。

举个例子:

  1. 用户从100,0 移动到104,2 到106,6,给你2 行
  2. 直线的斜率是 Δy/Δx。法线的斜率是 -Δx/Δy
  3. 第 1 行的法线从 102,1 开始,斜率为 -1/2(atan2(-1,2) 产生 -26°)
  4. 第 2 行的法线从 105,4 开始,斜率为 -2/1(atan2(-2,1) 产生 -63°)
  5. 这些线相交于99,7
  6. 如果所有后续线段的中心为 99±t,7±t,其中 t 是一些容差,则您有一个连续的弧
  7. 当用户连续通过一个圆的度数(或弧度)时,他们就画了一个圆

需要考虑的一些事项:

  • 由于鼠标移动事件通常会触发很多,从而导致许多相同的值或相邻的值,您必须等到有足够的移动来计算合理的正常值 - 您必须尝试看看什么适合你
  • 容差还取决于您的实验表明什么对您有效

【讨论】:

    【解决方案2】:

    下面的示例代码...这将跟踪连续的鼠标移动以确定是否绘制了一个圆圈。每次触发 MouseMove 事件时,都会将光标 Point 添加到集合中,并启动计时器来评估集合并重置。

    在评估集合时,它会首先确定中心Point,然后它会确保所有点都在距离中心一定距离内(在下图中的绿色区域内)并且在所有象限(一个完整的圆)。

    使用简单的 WPF 窗口:

    <Window x:Class="Shaping.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Canvas x:Name="ShapeCanvas" Background="Transparent" />
            <Ellipse Width="100" Height="100" Stroke="Black" StrokeThickness="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Grid>
    </Window>
    

    还有一些乱七八糟的代码:

    public partial class MainWindow : Window
    {
        List<Point> points;
        Timer reset;
    
        public MainWindow()
        {
            InitializeComponent();
    
            points = new List<Point>();
            reset = new Timer { AutoReset = false, Interval = 500 };
            reset.Elapsed += (s, e) =>
            {
                App.Current.Dispatcher.BeginInvoke((Action)(() =>
                {
                    ShapeCanvas.Children.Clear();
                }));
    
                if (points.Count > 10)
                {
    
                    double? max_x = null;
                    double? min_x = null;
                    double? max_y = null;
                    double? min_y = null;
    
                    // evaulate points to determine center
                    foreach (var point in points)
                    {
                        max_x = Math.Max(max_x ?? point.X, point.X);
                        min_x = Math.Min(min_x ?? point.X, point.X);
                        max_y = Math.Max(max_y ?? point.Y, point.Y);
                        min_y = Math.Min(min_y ?? point.Y, point.Y);
                    }
                    var center = new Point((((double)max_x - (double)min_x) / 2) + (double)min_x, (((double)max_y - (double)min_y) / 2) + (double)min_y);
    
                    var count_r = 0;
                    var sum_r = 0d;
                    var all_r = new List<double>();
                    var quadrands = new int[4];
    
                    // evaluate points again to determine quadrant and to get all distances and average distance
                    foreach (var point in points)
                    {
                        // distance
                        var r = Math.Sqrt(Math.Pow(point.X - center.X, 2) + Math.Pow(point.Y - center.Y, 2));
                        sum_r += r;
                        count_r += 1;
                        all_r.Add(r);
    
                        // quadrand
                        quadrands[(point.Y > center.Y ? 1 : 0) + (point.X > center.X ? 2 : 0)] += 1;
                    }
                    var r_avg = sum_r / count_r;
    
                    if (all_r.Count(r => Math.Abs(r - r_avg) < r_avg * .3) >= count_r * .8 && quadrands.All(q => q > 1))
                    {
                        // you made a circle
                        App.Current.Dispatcher.BeginInvoke((Action)(() =>
                        {
                            ShapeCanvas.Children.Clear();
                            ShapeCanvas.Children.Add(new Ellipse() { Fill = new SolidColorBrush(Colors.Red), Width = 15, Height = 15 });
                            reset.Start();
                        }));
                    }
                }
    
                points.Clear();
            };
    
            ShapeCanvas.MouseMove += (s, e) =>
            {
                points.Add(e.GetPosition((Canvas)s));
                reset.Stop();
                reset.Start();
            };
    
        }
    }
    

    关于 quadrands.All(q=&gt; q &gt; 1) 的注意事项 -- 我最初是在检查所有象限 quadrants.All(q=&gt; Math.Abs(q - avg_quad) &lt; avg_quad * .3 之间的 均匀 分布,但这只有在以恒定速度绘制圆时(或者如果计数是根据速度调整;速度由连续点之间的距离决定)

    .3 和 .8 只是我发现用来描述 roughly a circle 的数字——转换为:至少 80% 的点位于距中心平均距离的 +-15% 范围内。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-13
      • 1970-01-01
      相关资源
      最近更新 更多