C# Rectangles intersection returns unexpected result - c#

The constructor documentation states that
Rectangle(Int32, Int32, Int32, Int32) Initializes a new instance of
the Rectangle class with the specified location and size.
Where:
Parameters
x
Int32 The x-coordinate of the upper-left corner of the rectangle.
y
Int32 The y-coordinate of the upper-left corner of the rectangle.
width
Int32 The width of the rectangle.
height
Int32 The height of the rectangle.
With that in mind here's my couple of testing rectangles:
Rectangle1(25,43,11,9)
Rectangle2(35, 45, 9, 1)
As per MS documentation both x and y coordinates relate to the
upper-left corner
, that is:
Rectangles1 x coordinate goes from 25 to 36 and y goes from 43 down to 34
Rectangles2 x coordinate goes from 35 to 44 and y goes from 45 down to 44
That means they do not overlap, as Rectangle2 base (y = 44) is 1 unit above Rectangle1 top (y = 43)
As a matter of fact that conflicts with following simple test:
class Program
{
static void Main(string[] args)
{
Rectangle r1 = new Rectangle(25,43,11,9);
Rectangle r2 = new Rectangle(35, 45, 9, 1);
Rectangle r3 = new Rectangle();
r3 = Rectangle.Intersect(r1, r2);
if (!r3.IsEmpty)
{
Console.WriteLine("X = "+ r3.X);
Console.WriteLine("Y = " + r3.Y);
Console.WriteLine("Width = " + r3.Width);
Console.WriteLine("Height = " + r3.Height);
}
else
Console.WriteLine("r1 and r2 do not intersect");
Console.ReadLine();
}
}
I am quite confused now, as testing rectangles result to overlap at coordinate 35,45 for a unit. Which I can't explain.

It would seem, you are getting the y-axis wrong. R1 goes from 25, 43 to 35, 51, R2 goes from 35, 45 to 43, 45. My values are now INCLUSIVE bound, therefore it is x + width - 1 and y + height - 1. So, the intersect is exactly the pixel at 35, 45, with a size of 1x1 pixels. The calculation is therefore correct.

In the Windows Coordinate System:
The x-coordinates increase to the right; y-coordinates increase from
top to bottom.
Followed by:
For screen coordinates, the origin is the upper-left corner of the
screen.
So the upper left corner of your screen is (0, 0), and the Y values INCREASE as you go DOWN the screen from the top to the bottom.
Basically the Y-Axis has been flipped from what you're used to doing in standard math class graphing.
Here I am displaying the coordinates not only using Left and Top, but also the Right and Bottom properties:
Console.WriteLine(String.Format("r1: ({0}, {1}) --> ({2}, {3})", r1.Left.ToString(), r1.Top.ToString(), r1.Right.ToString(), r1.Bottom.ToString()));
Console.WriteLine(String.Format("r2: ({0}, {1}) --> ({2}, {3})", r2.Left.ToString(), r2.Top.ToString(), r2.Right.ToString(), r2.Bottom.ToString()));
This results in the following output:
r1: (25, 43) --> (36, 52)
r2: (35, 45) --> (44, 46)
Hopefully that helps you understand what is going on.

Related

Trouble multiplying a double with an int

So basically i'm making healthbars for my enemies in my C# XNA game. I am getting the percentage of health left so e.g. 80/100 = 0.8 = 80% so my game knows how big to draw the green portion of the health bar. So if there is 80% hp it will draw the healthbar to 80%. The problem I am having is as soon as the health goes down from 100, the percentage automatically gets dropped to 0.0/0% and nothing is drawn. Here is my code:
//calculate the width of the green portion of healbar
//zDay.Game1.hp_top.Width = Original size of image (35px)
float size = (hp/max_hp) * zDay.Game1.hp_top.Width;
//draw percentage of health
sb.DrawString(zDay.Game1.CourierNew, (hp/max_hp).ToString(), new Vector2(50, 80), Color.Black);
//draw size of green portion
sb.DrawString(zDay.Game1.CourierNew, (size).ToString(), new Vector2(50, 50), Color.Black);
//draw green portion of health bar
Rectangle bg = new Rectangle(x - 20, y - 30, (int)size, zDay.Game1.hp_top.Height);
sb.Draw(zDay.Game1.hp_top, bg, Color.White);
Any ideas as to why this is happening?
I would guess that the issue isn't with multiplication, but division; the statement:
(hp/max_hp)
is most likely being evaluated to zero (since you're diving by int's (I assume) and the result will be between 0 and 1, or in Integer terms, 0).
Try using
((float)hp/(float)max_hp)
Instead.

Adding an arc to a rectangle using GraphicsPath

I am trying to draw a top view of an IC package, which should look like this (sorry I couldnt even draw it good enough using windows's paint!)
I am using a path obeject, but the result of my path object is no where near what I expect. Atleast the complete rectangle itself draws fine but I have problem to make that top arc you see in my example picture. Would be nice if you can point me to the right place. Here is my code:
private GraphicsPath DrawDilBounds(Size size)
{
var p = new GraphicsPath(FillMode.Alternate);
p.StartFigure();
p.AddLine(0, 0, 0, size.Height);
p.AddLine(0, size.Height, size.Width, size.Height);
p.AddLine(size.Width, size.Height, size.Width, 0);
p.AddLine(size.Width, 0, (size.Width/2) - 10, 0);
p.AddArc(size.Width/2 - 10, 0, 10, 10, 10, 10); //This arc looks like no arc!
p.AddLine((size.Width/2) + 10, 0, 0, 0);
p.CloseFigure();
return p;
}
So what I am doing here is starting some lines from top left corner , to bottom left corner, to right bottom corner and finaly to top right corner, then I added a line from top right corner to the middle of the top , minus 10 pixels then I want to add the arc with width of 20 pixels and then finish the drawing back to the top left corner.
You specify the arc by its bounding box. Using 10 as the radius gives a box of 20 x 20 (you used 10 x 10) whose upper left corner is located at (-10, -10) from the center of the arc (you used (-10, 0)). The last two arguments must be degrees, the starting and ending angle. Since you draw it from left-to-right that will be 0 and 180 degrees (you used 10 and 10). You also fumbled the lengths of the 2 lines at the top, they should be half the width -10 (you used +10). Fix:
p.AddLine(size.Width, 0, (size.Width / 2) + 10, 0);
p.AddArc(size.Width / 2 - 10, -10, 20, 20, 0, 180);
p.AddLine((size.Width / 2) - 10, 0, 0, 0);
Which gets you:

Need some math - Projecting Slope

I have a rectangle.
Its height (RH) is 400.
Its width (RW) is 500.
I have circle.
Its height (CH) is 10.
Its width (CW) is 10.
Its starting location (CX1, CY1) is 20, 20.
The circle has moved.
Its new location (CX2, CY2) is 30, 35.
Assuming my circle continues to move in a straight line.
What is the circle's location when its edge reaches the boundary?
Hopefully you can provide a reusable formula.
Perhaps some C# method with a signature like this?
point GetDest(size itemSize, point itemPos1, point itemPos2, size boundarySize)
I need to calculate what that location WILL be once it arrives - knowing that it is not there yet.
Thank you.
PS: I need this because my application is watching the accelerometer on my Windows Phone. I am calculating the target necessary to animate the motion of the circle inside the rectangle as the user is tilting their device.
It is 1 radius away from the boundar(y/ies).
The answer is X=270 Y=395
first define the slope V as dy/dx =(y2-y1)/(x2-x1). In your example: (35-20)/(30-20)=1.5
the line equation is
y = V * (x-x1) + y1. You are interested in the horizontal locations x at:
y= CH/2 OR y= H-CH/2
so (not code, just math)
if (y2-y1)<0:
x=(CH/2 -y1)/V +x1 10 for your example. OR
if (y2-y1)>0:
x=(H-CH/2 -y1)/V +x1 270 for your example
else (that is: y2==y1)
the upper or lower lines were not hit.
if CH/2 <= x <= W-CH/2 the circle did hit the that upper or lower side: since V>0, we use x=270 and that is within CH/2 and W-CH/2.
So the answer to your question is y=H-CH/2 = 395 , X=270
For the side lines it's similar:
(if (x2-x1)<0)
y=(CH/2 -x1)*V +y1
(if (x2-x1)>0)
y=(W-CH/2 -x1)*V +y1
else (that is: x2==x1)
the side lines were not hit.
if CH/2 <= y <= H-CH/2 the circle did hit that side at that y.
be careful with the trivial cases of completely horizontal or vertical movement so that you don't divide by zero. when calculating V or 1/V. Also deal with the case where the circle did not move at all.
Since you now asked, here's metacode which you should easily be able to convert to a real method. It deals with the special cases too. The input is all the variables you listed in your example. I here use just one symbol for the circle size, since it's a circle not an ellipse.
method returning a pair of doubles getzy(x1,y1,W,H,CH){
if (y2!=y1){ // test for hitting upper or lower edges
Vinverse=(x2-x1)/(y2-y1)
if ((y2-y1)<0){
xout=(CH/2 -y1)*Vinverse +x1
if (CH/2 <= y <= H-CH/2) {
yout=CH/2
return xout,yout
}
}
if ((y2-y1)>0){
xout=(H-CH/2 -y1)*Vinverse +x1
if (CH/2 <= y <= H-CH/2) {
yout=H-CH/2
return xout,yout
}
}
}
// reaching here means upper or lower lines were not hit.
if (x2!=x1){ // test for hitting upper or lower edges
V=(y2-y1)/(x2-x1)
if ((x2-x1)<0){
yout=(CH/2 -x1)*V +y1
if (CH/2 <= x <= W-CH/2) {
xout=CH/2
return xout,yout
}
}
if ((x2-x1)>0){
yout=(H-CH/2 -x1)*V +y1
if (CH/2 <= x <= W-CH/2) {
xout=H-CH/2
return xout,yout
}
}
}
// if you reach here that means the circle does not move...
deal with using exceptions or some other way.
}
It's easy; no calculus required.
Your circle has radius R = CW/2 = CH/2, since the diameter of the circle D = CW = CH.
In order to have the circle touch the vertical edge of the rectangle at a tangent point, you have to move the circle to the right by a distance (W - (CX1 + CW/2))
Likewise, the circle will touch the bottom edge of the rectangle at a tangent point when you move it down by a distance (H - (CY1 + CH/2)).
If you do this in two separate translations (e.g., first to the right by the amount given, then down by the amount given or visa versa), you'll see that the circle will touch both the right hand vertical and the bottom horizontal edges at tangent points.
When the moving circle arrives at a wall (boundary) then it will be tangent at one of four points on the circle, call them N, S, E, and W. You know their initial coordinates.
The points travel in a line with a slope known to you: m=(y2-y1)/(x2-x1); where in your example (x1, y1) - (20,20) and (x2, y2)= (30, 35).
Your problem is to find the trajectory of the first point N, S, E, or W which reaches any wall. The trajectory will be a line with slope m.
You can do this by adding (or subtracting) the direction vector for the line to the point N, S, E, or W, scaled by some t.
For example, N is (20, 15). The direction vector is (x2-x1,y2-y1) = (10, 15). Then (20, 15) + t * (10, 15) will hit the boundary lines at different t's. You can solve for these; for example 20 + t*10 = 0, and 20 + t*10 = 400, etc.
The t that is smallest in magnitude, over all four trajectories, gives you your tangent point.
Not sure its calculus..wouldn't it just be the following:
if y >= 390 then it reached the top edge of the rectangle
if x >= 490 then it reached the right edge of the rectangle
if y <= 0 then it reached the bottom edge of the rectangle
if x <= 0 then it reached the left edge of the rectangle

Calculate Width and Height from 4 points of a polygon

I have four points which form a rectangle, and I am allowing the user to move any point and to rotate the rectangle by an angle (which rotates each point around the center point). It stays in near-perfect Rectangle shape (as far as PointF precision allows). Here's an example of my "rectangle" drawn from four points:
However, I need to be able to get the width and height between the points. This is easy when the rectangle is not rotated, but once I rotate it my math returns the width and height shown by the red outline here:
Assuming I know the order of the points (clockwise from top-left for example), how do I retrieve the width and the height of the rectangle they represent?
If by "width" and "height", you just mean the edge lengths, and you have your 4 PointF structures in a list or array, you can do:
double width = Math.Sqrt( Math.Pow(point[1].X - point[0].X, 2) + Math.Pow(point[1].Y - point[0].Y, 2));
double height = Math.Sqrt( Math.Pow(point[2].X - point[1].X, 2) + Math.Pow(point[2].Y - point[1].Y, 2));
Just use the algorithm for the distance between two points.
If you have points A, B, C, D, you will get two distances.
sqrt((Bx-Ax)^2 + (By-Ay)^2) will be equal to sqrt((Dx-Cx)^2 + (Dy-Cy)^2)
sqrt((Cx-Bx)^2 + (Cy-By)^2) will be equal to sqrt((Ax-Dx)^2 + (Ay-Dy)^2)
Pick one to be your width and one to be your height.
Let's say top-most corner is A. Then name other edges anti-clockwise as ABCD
width of rectangle = distance between A and B
height of rectangle = distance between B and C
Formula to find distance between two points say A(x1,y1) and B(x2,y2) is:
d = sqrt( (x2 - x1)^2 + ( y2 - y1)^2 )
where d is distance.

How to join overlapping circles?

I want to visually join two circles that are overlapping so that
becomes
I already have methods for partial circles, but now I need to know how large the overlapping angle for earch circle is, and I don't know how to do that.
Anyone got an Idea?
Phi= ArcTan[ Sqrt[4 * R^2 - d^2] /d ]
HTH!
Edit
For two different radii:
Simplifying a little:
Phi= ArcTan[Sqrt[-d^4 -(R1^2 - R2^2)^2 + 2*d^2*(R1^2 + R2^2)]/(d^2 +R1^2 -R2^2)]
Edit
If you want the angle viewed from the other circle center, just exchange R1 by R2 in the last equation.
Here is a sample implementation in Mathematica:
f[center1_, d_, R1_, R2_] := Module[{Phi, Theta},
Phi= ArcTan[Sqrt[-d^4-(R1^2-R2^2)^2 + 2*d^2*(R1^2 + R2^2)]/(d^2 +R1^2 -R2^2)]
Theta=ArcTan[Sqrt[-d^4-(R1^2-R2^2)^2 + 2*d^2*(R1^2 + R2^2)]/(d^2 -R1^2 +R2^2)]
{Circle[{center1, 0}, R1, {2 Pi - Phi, Phi}],
Circle[{d, 0}, R2, {Pi - Theta, -Pi + Theta}]}
];
Graphics[f[0, 1.5, 1, 1]]
Graphics[f[0, 1.5, 1, 3/4]]
And...
ImageMultiply[
Binarize#FillingTransform[#],
ImageResize[Import#
"http://i305.photobucket.com/albums/nn235/greeneyedgirlox/blondebabybunny.jpg",
ImageDimensions##]] &#
Rasterize#Graphics[f[0, 1.5, 1, 1], Background -> Black]
:)
Now this will work 100% for you even the figure is ellipse and any number of figures
private void Form1_Paint(object sender, PaintEventArgs e)
{
Pen p = new Pen(Color.Red, 2);
Rectangle Fig1 = new Rectangle(50, 50, 100, 50); //dimensions of Fig1
Rectangle Fig2 = new Rectangle(100, 50, 100, 50); //dimensions of Fig2
. . .
DrawFigure(e.Graphics, p, Fig1);
DrawFigure(e.Graphics, p, Fig2);
. . .
//remember to call FillFigure after drawing all figures.
FillFigure(e.Graphics, p, Fig1);
FillFigure(e.Graphics, p, Fig2);
. . .
}
private void DrawFigure(Graphics g, Pen p, Rectangle r)
{
g.DrawEllipse(p, r.X, r.Y, r.Width, r.Height);
}
private void FillFigure(Graphics g, Pen p, Rectangle r)
{
g.FillEllipse(new SolidBrush(this.BackColor), r.X + p.Width, r.Y + p.Width, r.Width - 2 * +p.Width, r.Height - 2 * +p.Width); //Adjusting Color so that it will leave border and fill
}
Don't have the time to solve it right now. But I'll give you what you need to work it out:
http://en.wikipedia.org/wiki/Triangle#The_sine.2C_cosine_and_tangent_rules
In the picture on wikipedia you see the triangle A,B,C. Let A be the center of the left circle, B the center of the right circle. And AC the radius of the left circle and BC the radius of the right circle.
Then point C would be the top intersection point. The corner in A, α, is half the angle in the left circle.The corner in b, β, half the angle in the right circle. These are the angles you need, right?
Wikipedia explains further: 'If the lengths of all three sides of any triangle are known the three angles can be calculated.'
Pseudocode:
a=radius_a
b=radius_b
c=b_x - a_x
alpha=arccos((b^2 + c^2 - a^2) / (2*b*c)) //from wikipedia
left_angle=2*alpha
Good luck :)

Categories