检测鼠标是否以圆形方式移动

4
我尝试实现鼠标移动跟踪,当鼠标以圆形或矩形方式移动时,显示特定消息。
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 我的代码在许多情况下无法正常工作。 - mbugr
  1. 你需要考虑时间因素。
  2. 你需要跟踪方向的变化。
  3. 你需要决定运动应该多接近一个圆。变化必须绕着360°旋转,保持变化的符号,例如:40-70-150-170-220-300-350-10-50 完成!当然,为了识别形状,你还需要测量的点。你可以使用mousemove,并在距离/变化太小的时候跳过。
- TaW
你能告诉我们更多关于你想要实现什么的背景信息吗? - TaW
1
@TaW 我尝试实现激光交互技术,我已经完成了所有的操作,但是当用户想要选择特定物体时,必须在其上绘制圆圈或矩形以执行相应操作。 - mbugr
对于圆形:使用Hough算法来检查由鼠标绘制的形状。对于矩形:更容易,使用算法来检查由鼠标绘制的形状的四个角点。 - Rashed DIP
显示剩余4条评论
2个回答

2
您可能想要将鼠标移动跟踪作为一系列线段,并使用这些线段来创建一个圆的近似图形。如果圆心保持相对稳定,则用户正在绕着圆走。
关键在于任何两个连续的线段近似于一个圆弧。从圆心到这些线段的法线(法线是垂直线)形成通过圆心的线。当您有两个或更多法线时,可以计算圆的中心。如果该中心随着用户移动鼠标而保持相对稳定,并且围绕圆心的这些法线的角度顺时针或逆时针进行,则表示存在一个圆。
例如:
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. 当用户连续经过一圈的角度(或弧度)时,他们制作了一个圆。
需要考虑一些问题:
- 由于鼠标移动事件通常会频繁触发,导致很多相同的值或紧挨着的值,您必须等待足够的移动来计算合理的法线——您必须进行实验以查看什么适合您; - 容差也将取决于您的实验结果显示什么适合您。

1
以下是示例代码... 这将跟踪连续的鼠标移动以确定是否绘制了一个圆。每次MouseMove事件触发时,光标Point将被添加到一个集合中,并启动计时器来评估集合并重置。
在评估集合时,它将首先确定中心Point,然后确保所有点都在与中心的一定距离内(在下面的图像中的绿色区域内),并且在所有象限中都有点 (一个完整的圆)。

enter image description here

使用一个简单的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=> q > 1) -- 我最初是在检查所有象限之间的均匀分布 quadrants.All(q=> Math.Abs(q - avg_quad) < avg_quad * .3,但这只有在圆以恒定速度绘制时(或者如果根据速度调整计数;速度由连续点之间的距离确定)才起作用。 .3.8只是我找到的描述大致为圆形的数字--转换为:至少80%的点落在中心平均距离的+-15%范围内。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接