Reputation: 352
I try to implement mouse movement tracking, When the mouse move in circle way or rectangle way show specific message.
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;
}
I detect circle shape using this function using mouse location.
any other way to detect the mouse movement?
Could you give a bit of sample code or a link?
Upvotes: 4
Views: 2904
Reputation: 963
Sample code below... This will track consecutive mouse movements to determine if a circle was drawn. Each time the MouseMove event fires, the cursor Point
is added to a collection and a timer is started to evaluate the collection and reset.
When evaluating the collection, it will first determine the center Point
, then it will make sure that all points are within a certain distance from the center (within the green area in the image below) and that there are points in all quadrants (a full circle).
with a simple WPF window:
<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>
and some messy code behind:
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();
};
}
}
Note about quadrands.All(q=> q > 1)
-- I was originally checking for even distribution between all quadrants quadrants.All(q=> Math.Abs(q - avg_quad) < avg_quad * .3
but that's only going to work when the circle is drawn at a constant speed (or if counts are adjusted based on speed; speed determined by distance between consecutive points)
.3
and .8
are just the numbers I found to describe roughly a circle
-- translates to: at least 80% of points fall within +-15% of the average distance from the center.
Upvotes: 1
Reputation: 2204
You probably want to track the mouse movements as a series of line segments, and use those line segments to create an approximation of a circle. If the center of the circle stays relatively consistent, then the user is moving in a circle.
They key to this is that any two consecutive line segments approximate an arc of a circle. The normals from the center of to these line segments (normals are perpendicular lines) form lines that pass through the center of the circle. When you have two or more normals, you can calculate the center of the circle. If that center stays relatively consistent as the user moves the mouse around, and the angles of those normals around the center of the circle are proceeding clockwise or counter-clockwise, then you have a circle.
As an example:
100,0
to 104,2
to 106,6
, giving you 2 lines102,1
and has a slope of -1/2
(atan2(-1,2)
yields -26°
)105,4
and has a slope of -2/1
(atan2(-2,1)
yields -63°
)99,7
Some things to consider:
Upvotes: 2