Hit Testing WPF the easy way (Collision detection)
This is a task I recently had to accomplish, on the WPF platform, the problem was that where as most applications use the mouse cursor to interact with the WPF canvas, this particular application didn’t. It reads X-Y co-ordinates directly from a USB input device, this means there is no event to subscribe to, etc to make it easy.
In this case we have to run the hit-testing manually. Now you may think this sounds simple, well in truth under .NET it is. However there are very few examples available on the internet that you may struggle to find the correct information. If it is the first time you have had to do something like this then you may also find that some basic knowledge of what hit-testing is doing behind the scenes will really help.
Imagine a rectangle shaped object on the form, hit-testing this shape is very easy, simply apply:
if( (x > s.X && x < s.X + s.Width) && (y > s.Y && x < s.Y + s.Height) ) then the hit is true.
where x,y = co-ordinates, s.X = shapes position in X.
However this becomes a lot more difficult if the shape has had transformations applied to it, i.e. rotation, translation and scaling. In my application I wanted to rotate and image, zoom into it and move it so I was using all 3 of these transformations. The formula to calculate if the X,Y co-ordinates are within the bounds of the shape would be very complex indeed.
There is however an easy an efficient way to allow is to use the original formula, (if the shape is square / rectangle).
Simply apply the reverse transformation (that is rotating, scaling and translating the object) to the XY co-ordinate.
This orientates if you like the XY coordinate you are testing with the rotation and scaling of the object to be hit test, you are now hit-testing against an un-transformed rectangle again.
.NET WPF provides functions to do all this for you and I have written a small wrapper class that you can pass any visual element and hit test it against pixel XY co-ordinates, as long as the transformation is applied to its render transform property.
public static bool HitTestPoint(FrameworkElement Reference, Point P)
{
Point myPoint = Reference.RenderTransform.Inverse.Transform(P);
HitTestResult HTR = VisualTreeHelper.HitTest(Reference, myPoint);
if (HTR != null)
{
return true;
}
else
{
return false;
}
}