I'm trying to find out if a point (mouse click) is within the boundaries of a box based on the top left x/y and bottom right x/y of the box. The position could be positive or negative. As you move up, y value increases, as you move down, y decreases. As you move right, x value increases, as you move left, x decreases.
Vector2 positions could be negative or positive depending on where is clicked.
I thought this would simply work but it doesn't seem to like negative numbers. Any suggestions? My brain is fried tonight after doing Vector arithmetic all night on other things. I wish I was one of you who seem to understand this without problem. ;)
if(point.x >= topLeft.x && point.y <= topLeft.y &&
point.x <= bottomRight.x && point.y >= bottomRight.y)
{
// is within box
}
Edit
Here is how the top left and bottom right are calculated. As it turns out, the problem was not with the above but rather I forgot to add the position.y to the top left calculation below.
Vector2 topLeft = new Vector2(transform.position.x - (transform.localScale.x/2),
transform.position.y + (transform.localScale.y/2));
Vector2 bottomRight = new Vector2(transform.position.x + (transform.localScale.x/2),
transform.position.y - (transform.localScale.y/2));
For anyone coming across this thread, the above check is correct.
Example 1:
Example 2:
I think you've wrongly inverted the boolean expression. It's easier to check for all cases where the click is outside the box.
Semantically, a certain point is outside of a rectangle if it is:
Higher than the highest point of the rectangle
Lower than the lowestpoint of the rectangle
More left than the left side of the rectangle
More right than the right side of the rectangle
If one of these is true, it's outside the box.
if(
clickPosition.x < topLeft.x
||
clickPosition.x > bottomRight.x
||
clickPosition.y < bottomRight.y
||
clickPosition.y > topLeft.y
)
{
//Now you're sure the click was outside the box.
}
Why not using a Rectangle and then check if it contains the point?
var rectangle = new Rectangle(-100,0,100,-100);
if(rectangle.Contains(-25,-25))
{
// is within box
}
For the rest, it appears your code should work. Then there may be a problem with the the assignment of the values of point, topLeft and bottomRight.
the problem with the negative numbers is that your top left isn't your top left
if you say
topY = max(corner1y, corner2y, corner3y)
bottomY = min (corner1y, corner2y, corner3y)
after that your check will work fine again.
I believe you're using the wrong signs on the Y checks.
If your topleft is 50, 100 and the bottom right is 100, 50, then 80 (y) still must be between 50 and 100, it doesn't matter which direction your Y is moving in relation to the screen, as long as you're also inverting your definition of top left.
if(point.x >= topLeft.x && point.y >= topLeft.y && //flipped sign in the second condition
point.x <= bottomRight.x && point.y <= bottomRight.y) //flipped sign in the second condition
{
// is within box
}
If you're not inverting your definition of top left, your original code is correct even for negative numbers.
Related
I'm using C# in Unity to make a game with a hexagonal grid. I'm trying to make the map in the shape of a hexagon rather than a rectangle. However, in order to do this with a grid, I need to apply 6 conditions (one for each side) to the rectangular grid to filter out the tiles which don't fall within the space we've determined to be within the hexagon. For instance, using pseudo-code:
foreach(tile in rectangle) { if((y <= 2/3*x + 0.5) && (condition2) && ...) { Debug.Log("It's a tile in the hexagon!") } }
I'm not great at trig, so I've been stumped on how to approach this for a while. In fact, I can't get a single condition down that would define a side of a hexagon (other than the top and the bottom stretches, which are done by default). Any help would be appreciated. Thanks!
(Additional information: the left and right sides are X and are 0.866 apart; top and bottom points are Z and are 1 apart but are fitted such that every other tile in a row is 0.25 closer to its adjacent row.)
I figured it out! I made a perfect hexagon in desmos: https://www.desmos.com/calculator/8tqplz09tt
Then, I converted this to code:
float standardUnitZ = ((mapSize.z * chunkSize.z) - 1f);
float normalUnitZ = standardUnitZ * (13f/15f);
float thisX = ((cz * mapSize.z) + hz);
float sqrt3 = (float)Math.Sqrt(3f);
if (
(theseFinalCoords.z >= (((1 - (13f / 15f)) * normalUnitZ) / 2))//1 BOTTOM
&& (theseFinalCoords.z <= normalUnitZ - (((1 - (13f/15f)) * normalUnitZ) / 2))//2 TOP
&& (theseFinalCoords.z <= sqrt3*thisX + (normalUnitZ / 2f))//3 TOP LEFT
&& (theseFinalCoords.z >= -sqrt3*thisX + (normalUnitZ / 2f))//4 BOTTOM LEFT
&& (theseFinalCoords.z <= -sqrt3*thisX + 2.2320508075f*normalUnitZ)//5 TOP RIGHT
&& (theseFinalCoords.z >= sqrt3*thisX - 1.2320508075*normalUnitZ)//6 BOTTOM RIGHT
)
A little more work to do possibly, but here's the final result:
Is there any ways around to find the index position of a curve, based on the current xPosition,
let's say I have a curve Item - MyCurve, which has 20k points and when the mouse moves I could get the mouse location & then I could get the x & y positions by simply using the following function.
double xPos=0, yPos=0;
this.zedGraphControl1.GraphPane.ReverseTransform(MouseLoc, out xPos, out yPos);
but I want to find the data points from the curve item, any suggestions...?
Thanks in advance....:)
Bear in mind that the following is only an approximation, it should be accurate especially when you the mouse gets closer to the point, but as you are looking at the mouse position you may not be directly on a point on your curve. It also assumes that your CurveItem Curve has points, and that they are evenly distributed.
double startPos = Curve.Points[0].X
double xStep = Curve.Points[Curve.NPts - 1].X / Curve.NPts;
int xIndex = (int)(xPos / xStep + startPos);
// Make sure it is in bounds
xIndex = xIndex < 0 ? 0 : xIndex > Curve.NPts - 1 ? Curve.NPts - 1 : xIndex;
OR you can use the following function:
CurveItem n_curve;
int index;
zedGraphControl1.GraphPane.FindNearestPoint(mousePt, out n_curve, out index);
But keep in mind that that will look for the nearest curve and the index of the nearest point within that curve.
If you are not concerned with using the positions programmatically, but only want to see the positions displayed in your graph, you can set zedGraphControl1.IsShowPointValues to true:
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
I'm working on an assignment for uni where I have to create a Breakout game in Visual Studio 2010 using C# Win Forms. At the moment, I am concentrating on there being only one brick to be destroyed so I have the mechanics down before expanding on it.
To clarify about my current program: I am using a picture box as a Graphics object and a timer to create the animation effect. The ball can skip, at each frame, between 1 and 10 pixels — this is part of creating a random starting vector for the ball.
This works fine until it comes to checking if the ball has 'hit' the brick I have drawn. What I have is an if statement that checks if the ball is at any of the coordinates on the picture box that corresponds to the outline of the brick. I know that the logic is fine because it works some of the time. However, because of the variation in the 'jumping' of the ball's position, I need to add a buffer area of +/- 5 pixels to my if statement.
This is where the problem arises, because my if statement (two, really) is really complicated as it is:
// Checks if ball hits left side or top of brick
if (((x >= brickX) && (x <= (brickX + 50)) && (y == brickY)) ||
((y >= brickY) && (y <= (brickY + 20)) && (x == brickX)))
{
brickHit = true;
}
// Check if ball hits right side or bottom of brick
else if ((((x >= brickX) && (x <= brickX + 50)) && (y == (brickY + 20))) ||
(((y >= brickY) && (y <= brickY + 20)) && (x == brickX + 50)))
{
brickHit = true;
}
For clarification: x and y are the coordinates of the ball and brickX and brickY are the coordinates of the top-left corner of the rectangle brick (which is 50 pixels wide, 10 pixels high).
Is there any way to simplify the above if statements? If I can make them simpler, I know it'll be much easier to add in the 'buffer' (which only needs to be 5 pixels either side of the brick's outline' to allow for the ball's change in position).
If further clarification is needed, please ask — I'm writing this question at 5:12am so I know I might be a little unclear.
One way you could possible simplify this (and I may be misunderstanding your spec), but you can make a Rectangle out of the bounds of the brick and check the Contains for your x,y point.
Rectangle rec = new Rectangle(brickX, brickY, 50, 20);
rec.Offset(-5, -5);
rec.Inflate(10, 10);
if (rec.Contains(new Point(x,y))
{
brickHit = true;
}
brickHit = new Rectangle(brickX,brickY,50,20).Contains(x,y);
Adding a buffer:
int buffer = 5;
brickHit = new Rectangle(brickX,brickY,50,20).Inflate(buffer,buffer).Contains(x,y);
The Rectagle class can come in handy sometimes.
This worked for me:
var rect1 = new System.Drawing.Rectangle(pictureBox1.Location,
pictureBox1.Size);
var rect2 = new System.Drawing.Rectangle(pictureBox2.Location,
pictureBox2.Size);
if (rect1.IntersectsWith(rect2))
{
//code when collided
}
I want to move through the pixels of an image, not by going line by line, column by column in the "normal" way. But begin at the center pixel and going outward in a spiral motion. But I'm not sure how to do this.
Any suggestions on how this can be done?
You can do this by using parametric functions, function for radius is r(t) = R, and x(t) = Rcos(t) and y(t)=Rsin(t).
Do you mean something like this?
It would be helpful to think about this in reverse.
For example, starting at the top left corner and moving in a clockwise direction you would move along the top row, then down the right hand side, along the bottom, and up the left edge to the pixel under the starting point.
Then move along the second row, and continue in a spiral.
Depending on the dimensions of the image you will end up with either a single column of pixels or a single row of pixels and will be moving either up/down or left/right.
From this finishing point you can then follow your steps backwards and process all the pixels as you need to.
To work out your starting position mathematically you would need to know the width/height of the image as well as which pixel you would like to end on and the direction you want to be travelling in when you get to the last pixel.
Something like this should do it:
int x = width / 2;
int y = height / 2;
int left = width * height;
int dir = 0;
int cnt = 1;
int len = 2;
int[] move = { 1, 0, -1, 0, 1 };
while (left > 0) {
if (x >= 0 && x < width && y >= 0 && y < height) {
// here you do something with the pixel at x,y
left--;
}
x += move[dir % 4];
y += move[(dir % 4) + 1];
if (--cnt == 0) {
cnt = len++ / 2;
dir++;
}
}
If the image is not square, the spiral will continue outside the coordinates of the image until the entire image has been covered. The condition in the if statement makes sure that only coordinates that are part of the image are processed.