To test for intersection of a rectangle and a line you can either use one of the many methods from the Wikipedia article or use a GDI+ trick involving GraphicsPaths
and Regions
..:
using System.Drawing.Drawing2D;
..
bool Intersects(Point a, Point b, Rectangle r)
{
if (Math.Min(a.X, b.X) > r.Right) return false; // *
if (Math.Max(a.X, b.X) < r.Left) return false; // *
if (Math.Min(a.Y, b.Y) > r.Bottom) return false; // *
if (Math.Max(a.Y, b.Y) < r.Top) return false; // *
if (r.Contains(a)) return true; // **
if (r.Contains(b)) return true; // **
using (GraphicsPath gp = new GraphicsPath())
using (Pen pen = new Pen(Color.Empty, 0.5f))
using (Region reg = new Region(r))
using (Graphics g = CreateGraphics())
{
gp.AddLine(a,b);
gp.Widen(pen); // we need to widen the line path just a little
reg.Intersect(gp);
if (reg.IsEmpty(g)) return false;
}
return true;
}
Here is a small test result:
Since Region.IsEmpty
is probably not very fast I have prepended the call with a few trivial tests for better speed. For a discussion of performance issues with Region see here. From this I guess one can conclude that testing with a simple rectangle will in fact still be reasonably fast..
For a truely fast test you may need to implement a real clipping method. This looks nice..
But the GDI+ trick with the region has one big advantage over the analytical methods: I will work with any shapes you can put into a GraphicsPath
, including circles, ellipes, polygons, all sorts of combinations and also complex tracing paths. And since the Region
supports all set operations, your imagination is the limit..
This allows you to test complex shapes of spaceships or monsters; and with a few extra tricks you can even test rotated shapes.
Note that if you go for testing complex shapes you will want to:
- pass in the
GraphicsPath
- use its bounding rectangle (
gp.GetBounds()
) for the first four tests (*)
- remove the other two tests (**) since the bounding rectangle will not work now; in fact they only work with rectangles; I had to remove them for the following ellipse demo.
Here is the same example, simply replacing the rectangle with an ellipse:
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…