I have a program in C# (Windows Forms) which draws some rectangles on a picturebox. They can be drawn at an angle too (rotated).
I know each of the rectangles' start point (upper-left corner), their size(width+height) and their angle. Because of the rotation, the start point is not necessarely the upper-left corner, but that does not matter here.
Then when I click the picturebox, I need to check in which rectangle (if any) I have clicked.
So I need some way of checking if a point is in a rectangle, but I also need to take into account the rotation of each rectangle.
Does anybody know of a way to do this in C#?
Is it possible to apply the same rotation applied to the rectangle to the point in reverse?
For example, Rectangle A is rotated 45 degrees clockwise from its origin (upper left corner), you would then just rotate point B around the same origin 45 degrees COUNTER clockwise, then check to see if it falls within Rectangle A pre-rotation
You could keep a second, undisplayed image where you draw duplicates of the rectangles, each uniquely colored. When the user clicks on the picturebox, find the color of the corresponding pixel in the 2nd image, which will identify which rectangle was clicked.
Edit: After looking back, I'm using MonoGame and the OP is using Windows Forms. The following is for MonoGame.
I've been messing this for a while now and have found a couple answers, just none of them actually worked. Here is a C# function that does exactly as OP describes, if not for OP then other people Googling like I was.
It was a headache to figure this out. A lot of the typical guesswork.
bool PointIsInRotatedRectangle(Vector2 P, Rectangle rect, float rotation)
{
Matrix rotMat = Matrix.CreateRotationZ(-rotation);
Vector2 Localpoint = P - (rect.Location).ToVector2();
Localpoint = Vector2.Transform(Localpoint, rotMat);
Localpoint += (rect.Location).ToVector2();
if (rect.Contains(Localpoint)) { return true; }
return false;
}
And here it is in a single line of code. Probably faster to use.
bool PointIsInRotatedRectangle(Vector2 P, Rectangle rect, float rotation)
{
return rect.Contains(Vector2.Transform(P - (rect.Location).ToVector2(), Matrix.CreateRotationZ(-rotation)) + (rect.Location).ToVector2());
}
I know this was already answered but I had to do something similar a while ago. I created an extension method for the System.Windows.Point class that helped do exactly what Neil suggested:
public static double GetAngle(this Point pt)
{
return Math.Atan2(pt.X, -pt.Y) * 180 / Math.PI;
}
public static Point SetAngle(this Point pt, double angle)
{
var rads = angle * (Math.PI / 180);
var dist = Math.Sqrt(pt.X * pt.X + pt.Y * pt.Y);
pt.X = Math.Sin(rads) * dist;
pt.Y = -(Math.Cos(rads) * dist);
return pt;
}
This would allow me to work with the angles of points around 0, 0. So if you know the center of the rect that you are testing you would offset the point by the negative of this value (for example: pt.X -= 32; pt.Y -= 32) And then you would apply the negative rotation of the rectangle (as suggested by Neil: pt.SetAngle(-45);)...
Now if the point is within 64, 64 you know you hit the rectangle. More specifically I was checking a pixel of a rotated image to make sure I hit a pixel of a specific color.
Would the rectangles be allowed to overlap?
If so, would you want all the rectangles in a point, or just the one in the top layer?
If you know the coordinates of the corners of the rectangle, this is an fast, elegant solution that merely involves a couple of dot and scalar products: https://math.stackexchange.com/a/190373/178768
See the rectangle edges as a list of vectors linking a corner to the next, sorting corners clockwise. If the point is in the square, it must be to the right with respect to all of the edge vectors.
This can be solved by vector products, but it boils down to the following:
Iterate over rectangle corners:
the point to be checked is P=[px,py]
the current corner is C=[cx,cy] and the next corner is N=[nx,ny]
if px*ny+cx*py+nx*cy<py*nx+cy*px+ny*cx, the point is outside the square.
this would actually work for every convex polygon.
Related
I have a slider for rotating the line. When the slider is slide I want to rotate the line. The slider value is set as an angle. When the page initial loading the line shape is placed as horizontal. The slider value is binded from getting the angle. I have used the below code to calculate the angle between two points.
const double Rad2Deg = 180.0 / Math.PI;
private double Angle(Point start, Point end)
{
return Math.Atan2(start.Y - end.Y, end.X - start.X) * Rad2Deg;
}
Now I want to calculate the two points using angle. Please give me a suggestion.
Let's say we have a line beginning in a point (0,0) and ending in point (x,y). And we want to rotate it to the angle a.
So, the (x,y) point will translate into (x', y') point, where
x' = x*cos(a)-y*sin(a)
y' = x*sin(a)+y*cos(a)
And the whole line will be from (0,0) to (x', y')
To start with, I have a simple class, Line;
public class Line
{
public Vector2 P1 = Vector2.Zero;
public Vector2 P2 = Vector2.Zero;
public Line(Vector2 p1, Vector2 p2)
{
P1 = p1;
P2 = p2;
}
}
A list of all lines in the game, and my sprites bounding rectangle. I'm trying to find whether or not this rectangles bottom middle is below the point on the line it's directly above, and update it to the point on the line it's at. This picture might help you understand what I mean;
The rectangle is moving down, passes it's intersection point, then updates accordingly.
Any ideas on how you could go about this? I can easily find which line it's currently above, but I don't know how to get the point on the line it's above and keep it from falling past that point.
Code samples or references would be great.
If you know the locations of the endpoints of the line, then it's pretty trivial to get the equation of that line in the form y = mx + c. Then you need to find the midpoint of the bottom of that rectangle - seeing as the XNA rectangle gives you its height, width and centre point location, this is also trivial. From there, you take the x co-ordinate of your rectangle centre point, use the y = mx + c equation to work out the y co-ordinate of your line at that point. Then you just need to check whether the rectangle's bottom centre is below that point, and if it is, use your rectangle's height value to work out how far above that y co-ordinate you need to put the rectangle so that it appears to sit on the line. Should be simple enough.
I'm writing a little test project. I have an object (with a position and bounding box) at an origin, and when something happens (say a mouse click/touch on phone), I want a line to be drawn from the origin object to the point.
Using a texture, I realise I'm going to have to use the rotation here, but have no idea how to work out how much to rotate the texture by. Any help would be appreciated.
So far, I have:
Vector2 Origin
Vector2 TouchPoint
and that's about it.
Thanks all!
Theres a simple formula for calculating an angle based on the X and Y coordinates:
float angle = Math.Atan2(TouchPoint.Y - Origin.Y, TouchPoint.X - Origin.X);
You can use this angle in an overload of the SpriteBatch.Draw() that accept an angle for the rotation.
See this for reference:
http://msdn.microsoft.com/en-us/library/ff433992.aspx
You may want to convert between degrees and radians:
float rad = deg * Math.PI/180;
float deg = rad * 180/Math.PI;
I have a small rectangle, with a point at the center. I also have another point, just outside of the rectangle, 10 pixels to the left of the rectangle's center point when the rectangle is sitting vertically, not rotated. How would i go about keeping this outside point in the same place relative to the rectangle when the rectangle is rotated about its center?
thanks
Here is an example of how to rotate one point around another point in XNA:
public Vector2 RotatePoint(Vector2 pointToRotate, Vector2 centerOfRotation, float angleOfRotation)
{
Matrix rotationMatrix = Matrix.CreateRotationZ(angleOfRotation);
return Vector2.Transform(pointToRotate - centerOfRotation, rotationMatrix);
}
Start the "point" at the center point of your rectangle, then translate it out to where you want it, and then rotate it from there.
Background:
I was recently playing around with GDI+ to draw a "Disc" displaying a sweeping color change through 360 degrees. (I dug up some HSL to RGB code to loop through HSL(1,1,1) -> HSL(360,1,1))
Regarding the disc, I first drew a full solid circle using the above, and then a second circle in Grey over the center to give the following
So this is all fine... but I realised that GDI+ is insulating us from a lot of the tricky match that's going on here by way of the FillPie method. Also, FillPie requires you to supply a bounding rectangle for the pie as opposed to a Radius Length. It also does a full segment fill and doesnt allow you to specify a part of that segment only.
Question:
Can anyone point me in the direction of some Math functions or give any explanation on what forumla I would need to calculate the area & plot points of the following "Green Filled Area" given:
Point `c` - an x,y co-ordinate
Angle `A` - an angle from horizontal
Angle `B - an angle from horizontal where `B` - `A` == the sweep angle
Length `r` - a distance from `c`
Length `r2` - a distance from `c` where `r2` - `r` == the `height` of the segment to be filled.
Links to Math sources are fine but I've had a quick google & look at Wolfram Math and could find what I was looking for. Also, if there was some way to generate a sequence of bounding (x,y) co-or's that could be passed as a Point[] to Graphics.FillPolygon, that'd be cool too.
The area is the difference of the outer and inner disc parts. The area of a disc part is proportional to the angle sweep:
area = (b-a)*((r+r2)^2-r^2)/2
a and b must be expressed in radians.
For b-a = 2*Pi, area = Pi*(r+r2)^2 - Pi*r^2 is the difference of the areas of the outer and inner discs.
You can generate points on the inner / outer circle using
x = cx + r * cos(t) / x = cx + (r+r2) * cos(t)
y = cy + r * sin(t) / y = cy + (r+r2) * sin(t)
Where t varies from a to b.
Hope this helps. The second part provides a method for calculating the area of a sector of a circle
http://www.wikihow.com/Calculate-the-Area-of-a-Circle
The area of a segment of a circle is simply the angle of the arc (in radians) times the radius. So the area of the green circle is obviously:
(B-A) * r2
You need to draw lines (this pseudo code):
for aa from A to B
set color to required color // you could use aa in an equation with HSL to get something like your sample
x1=r*cos(aa)+x
y1=r*sin(aa)+y
x2=r1*cos(aa)+x
y2=r1*sin(aa)+y
draw line between (x1,y1) and (x2,y2)
for a small-enough increment in the angles, and small-enough radii, this should be OK.
The points you're looking for are (x1,y1) and (x2,y2) for each angle aa