Tuesday, August 31, 2010

Rect and Point Extension Methods

I'm currently working on multiple Windows Phone projects and don't have much time for longer blog posts, but I just wanted to get this out.
For one of the projects I need to calculate some simple vector arithmetics like the Euclidean distance. I also need other properties of the Point and Rect structs that aren't built-in the Silverlight framework. As you might know I'm a huge fan of extension methods for extending built-in functionality (12). That's why I wrote a few extension methods for the Point and Rect structs that might come handy.

Rect
public static class RectExtensions
{   
   // Calculates the center point of this rectangle.
   public static Point Center(this Rect rect)
   {
      return new Point(rect.X + rect.Width * 0.5, rect.Y + rect.Height * 0.5);
   }

   // Tests if this rectangle intersects with the other.
   public static bool IntersectsWith(this Rect rect, Rect other)
   {
      // Test for separating axis
      if (other.Bottom < rect.Top || other.Right < rect.Left 
       || other.Top > rect.Bottom || other.Left > rect.Right)
      {
         return false;
      }
      return true;
   }
}

The usage should be pretty obvious.
Rect r = new Rect(0, 0, 200, 300);
Point center = r.Center();

bool isIntersecting = r.IntersectsWith(new Rect(500, 600, 100, 50));


Point
public static class PointExtensions
{
   // Calculates the distance vector of the points.
   public static Point Distance(this Point p1, Point p2)
   {
      return new Point(p1.X - p2.X, p1.Y - p2.Y);
   }

   // Calculates the length of the vector.
   public static double Length(this Point p)
   {
      return Math.Sqrt(p.X * p.X + p.Y * p.Y);
   }

   // Calculates the square length of the vector.
   public static double LengthSquare(this Point p)
   {
      return p.X * p.X + p.Y * p.Y;
   }
}

The squared length saves some cycles if this information is only needed for comparison.
Point p1 = new Point(200, 300);
Point p2 = new Point(400, 500);
Point distance = p1.Distance(p2);

double length = distance.Length();
double lengthSq = distance.LengthSquare();
length = Math.Sqrt(lengthSq);

Source Code
You can download the two C# files from here.

4 comments:

  1. You can optimize that Intersect method a lot by inverting it to use && instead. That way you don't have to check all the cases. As soon as you know that the box is to the right of the other, you don't really care if it's above or below it, and so on.

    ReplyDelete
  2. Hi Morten,

    What you describe in the last sentence is what the above code does.

    In the worst case my code tests 4 conditions, but it's mostly less for my scenarios. If the first condition in the OR is true, the method returns. AND on the other hand would be slower most of the times, since all AND conditions have to be tested.

    ReplyDelete
  3. Rene, Morton,
    You are both right.

    The && (ANDALSO in VB.Net) and || (ORELSE in VB.Net) stop evaluating on the first conclusive result.
    That is || stops on the first true expression, && stops on the first false expression.

    ReplyDelete