Theory - How to Tell if Elements Overlap? - c++

I have a question, and I don't want an implementation. I just want a bit of help in my reasoning.
I want to determine if two objects overlap (their x and y coordinates, as well as their height and width are stored in a vector) and then, if they do, remove them from their current vector and add them to another with combined properties.
My question is, generally, how do you tell when something overlaps? Obviously, they can have the same x and not overlap due to differing y's, or vice versa. I am thinking I need information about the width and height in addition to the location of the edge of the object, but I don't even know how to turn this into pseudo code at present.
Any help in helping me figure this out would be greatly appreciated!
EDIT: The objects are strictly rectangular, and the coordinates follow a pixel monitor convention. i.e. 0,0 is the upper left corner of the object, and an increase in x corresponds to going right, while an increase in y means going downwards.

Consider two rectangles R1 and R2.
Overlap in x:
if (R2.x < R1.x + R1.width) AND (R1.x < R2.x + R2.width)
Overlap in y
if (R2.y < R1.y + R1.height) AND (R1.y < R2.y + R2.height)
PS. Note that Im using a pseudolanguage

Maybe a picture will help. This is your coordinate system with two objects.
Two objects overlap on x axis if the distance between x1 and x2 is smaller than the width of the object that's closer to the x axis (w1 in the case on the picture).
pseudocode:
w = width of leftmost object
if ( abs (x1-x2) < w ) /* overlap on x axis */
You need to do the same for y axis. If both checks return true, the objects overlap.

A particularly bad (but intuitive) way of doing this is along this line of reasoning:
If two 2D rectangles overlap, then definitely some of the sides of one of them intersects some of the sides of the other. Actually, even if one of the line segments making up one of them intersects one of the line segments of the other, then the rectangles overlap.
So, you can just loop over their sides and check their intersection pair by pair. Finding code or ideas for line segment intersection shouldn't be hard at all.
Important note: you need to define for yourself whether sharing a side between the rectangles constitutes overlapping or not. If it doesn't, then you have to be extra careful in the implementation of the above method.
For axis-aligned rectangles (rectangles with sides parallel to the axes,) the solution is quite simpler:
Assume the two rectangles are named A and B, and assume and their 4 sides are named left (minimum X coordinate) , right (maximum X coordinate), top (minimum Y coordinate) and bottom (maximum Y coordinate.) Then I think you can say that they overlap if (and only if) any of these is true:
A.right is less than B.left (A is completely to the left of B)
A.left is greater than B.right (A is completely to the right of B)
A.bottom is less than B.top (A is completely above B)
A.top is greater than B.bottom (A is completely below of B)
In (somewhat) pseudo code, you can write:
if (A.right < B.left || A.left > B.right || A.bottom < B.top || A.top > B.bottom)
/* don't overlap */
or written in another (more symmetrical and maybe easier to understand) form:
if (A.right < B.left || B.right < A.left || A.bottom < B.top || B.bottom < A.top)
/* don't overlap */
Again note that rectangles with touching sides need to be handled with a little care.

Related

How do I determine a rectangle on the basis of the given lengths?

If I have 4 sides given to me, How do I determine if those 4 sides form a rectangle?
Currently, what I am doing is:
Taking 4 sides of sides as an input in an array of size 4;
sort(array,array+4) sorting the array
for(int i=0;i<2;i+=2)
{
if(a[i] != a[i+1])
{
flag = false;
break;
}
}
But, Here I am just checking if the 4 sides are parallelogram or not. How do I change my algorithm such that it checks if it's a rectangle or not
I think you can get it by
First checking if there are only four unique points given.
Secondly, calculating all pair distance you must get maximum three distinct value. One for each diagonal and two for two sides.
Then the sides must fulfill Pythagorean relation.
Rectangle (unlike triangle) in not a rigid polygone; that's why if you are given four length only, you have infinitely many possible figures. E.g. in the simplest [1, 1, 1, 1] case we can have either quadrate (which is rectangle) or one of numerous rhombs (which are not). If we state the problem as
If any rectangle can be constructed with given lengths (lengths can be used in arbitrary order)
we can solve it in this way
Obtain all four lengths
Sort them in ascending order
Check length[0] > 0 (all lengths are positive)
Check length[0] == length[1] && length[2] == length[3]
In case order should be preserved (we can't rearrange lengths):
Obtain all four lengths
Check (in loop) that length[i] > 0 (all lengths are positive)
Check length[0] == length[2] && length[1] == length[3]
For a rectangle, you have to check that the opposite sides (no common vertex) are equal length, and also that both diagonals (no common vertex also) are similar. If you check all the possibilities, you'll find that the common property is that all the possibilities of segments between vertices with no common points have to be same length (pairs of sides and both diagonals)
Another simpler way is to check that all vertices are in a common circle (with center in the rectangle center), which is the point in common of both diagonals, assume you have vertices at P1, P2, P3, and P4: you get the midpoint C1 = (P1 + P3)/2 and C2 = (P2 + P4)/2 (C1 must be equal C2). If your figure is a rectangle, all four vertices must lie in a circle with center C1 == C2 == C. Also, all points must be in a circle. So dist(Pi, C) must be the same. I think this is the most direct way to check if they form a rectangle.
NOTE
With only the side lengths you cannot determine that a cuadrilateral is a rectangle, as a rhomb has all four sides equal, but is not a rectangle (it fails the test of having all vertices in a circle, as both diagonals are not the same size) and the same is true for a rhomboid (it has sides equals two by two, but diagonals are not the same size, and the vertices don't fall in a common circle)
If you have four sides and also the two diagonals, the sides must be equals by alternate pairs and the diagonals must be equal length for them to form a rectangle.

How to determine if a point is within an polygon consist of horizontal and vertical lines only?

I want to find a best way because all coordinates are integer values and polygons consist of horizontal and vertical lines only. I think there may be a simple and fast method to do this.
From an asymptotic complexity point of view, a rectilinear polygon is not really simpler to process than a general one: O(N) without preprocessing, and O(Log N) after O(N Log N) preprocessing (but using a complicated procedure).
For the case of no preprocessing, the procedure is simple: consider every vertical side in turn and count those that cross the horizontal half-line from the given point (+1 upward, -1 downward). The point is inside if the final count is nonzero.
The status of points on the outline is application-dependent.
For rectilinear poygons with not too large integer coordinates, you can anyway do a little better, by "compressing" them. By two independent sorts on X and Y, you can obtain a mapping from X (or Y) to integer indexes in range [0,N). This gives the shrunk polygon below, of size NxN.
Now you can embed the polygon in an image and preprocess to label the pixels as inside/outside (by seed-filling). After filling two lookup-tables for coordinate conversion, you can obtain the status of any point in constant time O(1).
This will take O(N²+M) preprocessing time and storage, where M is the range of X and Y values.
Consider any polygon, not necessary convex, formed only with horizontal and vetical lines:
Take a point (I've drawn A,B,C,D) and draw horizontal and vertical lines passing through the point.
Let's take point A. You see the horizontal line through it crosses four (vertical) segments. Note one segment is at left and the others are at right.
For point B its horizontal line crosses also four segments, but two at left and two at right.
The conditions that a point must fulfill to be inside a polygon are:
At least one segment is horizontaly crossed at left of the point.
At least one segment is horizontaly crossed at right of the point.
Both numbers of crosses left, right must be odd.
Same three conditions for vertical lines.
So, in pseudocode it goes like this:
let nL = 0, nR = 0 //left/right counters
let nA = 0, nU = 0 //above/under counters
for each segment s(sx1,sy1, sx2, sy2) in polygon
if point is on segment
return true //or false, your choice
else if segment is vertical and pointY is inside of (sy1,sy2)
if pointX > min(sx1,sx2)
nL = nL + 1
else
nR = nR + 1
else if segment is horizontal and pointX is inside of (sx1,sx2)
if pointY > min(sy1,sy2)
nU = nU + 1
else
nA = nA + 1
//Check conditions
if nL > 0 and nR > 0 and nL is odd and nR is odd
return true
if nA > 0 and nU > 0 and nA is odd and nU is odd
return true
return false

Point inside rectangle given sides and center

I'm given rectangle by it's height(h) and width(w), and it's center O(x0,y0). I need to calculate if given point A(x,y) is inside that rectangle. It is parallel to x and y axis. All values are real.
I came up with following test but for some reason website on which I'm testing the code is not working for all examples. Could someone point me in the right direction.
#include <iostream>
#include <cmath>
using namespace std;
int main(){
long x,y,x0,y0,r,h,w;
scanf("%ld",&x);
scanf("%ld",&y);
scanf("%ld",&x0);
scanf("%ld",&y0);
scanf("%ld",&h);
scanf("%ld",&w);
if((x0+w/2.0>=x)&&(x0-w/2.0<=x)&&(y0+h/2.0>=y)&&(y0-h/2.0<=y))
printf("inside a rectangle");
else
printf("outside a rectangle");
}
Thanks in advance.
After OP's Edit:
The rectangle's side are parallel to x axis and y-axis. Then also it is possible to get the co-ordinates and apply the below mentioned algorithm.
Centre -- (x0,y0)
A -- (x0-w/2,y0-h/2)
B -- (x0-w/2.y0+h/2)
C -- (x0+w/2,y0+h/2)
D -- (x0+w/2,y0-h/2)
So all you have to do is, Apply the algorithms provided below.
More simply we can do this,
if( 2*x <= 2*x0+w && 2*x >= 2*x0-w && 2*y <= 2*y0+h && 2*y >= 2*y0-h)
// it's inside
Before OP's edit
Your logic is wrong. It may say a point inside rectangle to be outside of it.
(For any rectangle this is wrong - OP didn't mention the condition of being sides parallel to x-y axes)
There is a simple way and cleaner way to do this for rectangle. Find the Area of the rectangle.
Suppose it's A.
Now if the point P lies inside ABCD then
area of PAB+PBC+PCD+PDA = A
For better thing do this with ,
AB.Bc+BC.CD+CD.DA+DA.AB = 2*AB*BC
or even better make a square of both side
LHS^2 = 4*AB^2*BC^2
Now you will just multiply and check it. One drawback of this solution is for large values of side length you have a chance of overflow.
Another method would be to consider the projections.
If point is inside of the rectangle then the projection of the corner of rectangle to point, on two of it's side must be less than the corresponding sides. You can check the projection length using dot products.
For example if P is the point and ABCD is rectangle check,
if AP's projection on AB has greater than zero length but less than the length of AB. Check the same with BC and BP and check if length is greater than zero and less than BC or not.
This two condition makes sure that your point lies inside the rectangle.

Determine if point is in frustum

I'm trying to work out the best way to determine whether a point is inside a frustum. I have something working, but not sure whether it is too cumbersome, and perhaps there is a more elegant / efficient way I should be doing this.
Suppose I want to find out whether point 'x' is inside a frustrum:
Once I have the locations of the 8 points of the frustrum (4 near points, four far points), I am calculating the normal for each plane of the frustum based on a triangle made from three of the points. For example (as in the diagram above), for the right side, I am making two vectors from three of the points:
Vector U = FBR - NBR
Vector V = FTR - NBR
Then I am making the cross product between these two vectors, ensuring that the winding order is correct for the normal to be pointing inside the frustum, in this case V x U will give the correct normal.
Right_normal = V x U
Once I have the normal for each plane, I am then checking whether point x is in front of or behind the plane by drawing a vector from x to one of the plane's points:
Vector xNBR = x - NBR
Then I am doing the dot product between this vector and the normal and testing whether the answer is positive, confirming whether point x is the correct side of that plane of the frustrum:
if ( xNBR . Right_normal < 0 )
{
return false;
}
else continue testing x against other planes...
If x is positive for all planes, then it is inside the frustum.
So this seems to work, but I'm just wondering whether I'm doing this in a stupid way. I didn't even know what 'cross product' meant until yesterday, so it's all rather new to me and I might be doing something rather silly.
To adapt the approach you have taken, rather than change it totally, you can make use of the fact that 2 of the pairs of planes are parallel. Create only one normal for that pair of planes. You already have the test for the point being "in front" of one of the planes, but assuming you know the depth of the frustum, you can use the same distance to test the point against the other parallel face.
double distancePastFrontPlane = xNBR . Right_normal;
if (distancePastFrontPlane < 0 )
{
// point is in front of front plane
return false;
if(distancePastFrontPlane > depthFaceRtoFaceL)
{
// point is behind back plane
return false;
}
}
If you have multiple points to test against the same frustum you can benefit because you only calculate the frustum depth once (per pair of parallel planes).

How to make sure that a given set of points lie on the boundary of a possible square?

Given a set of integral coordinates, check whether all the points given lie on side of a possible square such that axis of the square so formed lie parallel to both X-axis and Y-axis. If such a square is possible give the minimum possible side of the square.
Suppose points are (0,0), (1,1), (2,2).
Answer : square is not possible .
Suppose points are (0,0), (0,2), (0,5), (0,7), `(3,0).
Answer : square is possible and minimum length of the side is 7.
I tried it and came up with many corner cases and it seemed impossible to tackle them individually. I was wondering if anyone can give a more generalized approach towards this kind of problem and how to think in the right direction.
Thanks in advance.
Range of coordinates: -1000 <= x ,y <= 1000
The number of points is <= 50.
New edit :
One more corner case :
(2,0) , (0,4) , (1,5) , (5,3)
Answer : Square is possible with length 5 . Corner points of the square are (0,0) , (0,5) ,(5,5) ,(5,0)
If you define the square through xmin, xmax, ymin and ymax, then all points must lie on one of these coordinates. I.e. the square is valid, if for all vertices v:
v.x == xmin || v.x == xmax || v.y == ymin || v.y == ymax
Candidates for the bounds are the points' bounding rectangle's bounds. If you compute these boundaries, maintain a list of vertices for each edge.
If you can't assign every vertex to an edge, it is not possible to create the square.
Now it is very likely that the rectangle is not a square. So we need to enlarge its shortest side. If we have chosen the side, we need to choose whether to move the min or max edge. That's where the list of associated vertices comes into play. For the edge to move check whether all associated vertices are also associated with another edge. Then it is safe to move this edge. If we can move neither the min nor the max edge, it is impossible to create the square.
The resulting minimal side length is the distance of the edges.
I'm trying to think of a way to do this in a single pass, but it's late at night here and I'm tired, so...
Run through all the elements once and record the minimum and maximum x and y values of the whole set. The side length of the square (if it exists) will be max(xmax-xmin, ymax-ymin).
Run through the points again. To describe a square parallel to the axes, each point must have
x == xmin || x == xmax || y == ymin || y == ymax,
that is, at least one coordinate must be on the side of the square. If any point fails, then you don't have a square.
I'm pretty sure this is sufficient, but doing it in two steps seems less than optimal. This is an interesting problem though, good luck.
The requirement of the axis helps us make following observations
Every such square is bounded by two parallel vertical lines and every point on that vertical line has same X-coordinate. Let's call those coordinates maxX and minX. (One of them is smaller than other)
Every such square is bounded by two parallel horizontal lines and every point on that vertical line has same Y-coordinate. Let's call those coordinates maxY and minY.
This is crucial: Every point in input list must have a X-coordinate matching maxX or minX OR a Y-coordinate matching maxY or minY. (Notice the OR. If there is a point that matches neither, like (1, 1) in your earlier example, you have a counterexample).
Here is a c++-like pseudocode to compute these quantities. Assume you have an appropriate Point structure.
bool isSquare(vector<Point> points) {
double maxX = points[0].X;
double minX = points[0].X;
double maxY = points[0].Y;
double minY = points[0].Y;
// set maxX, minX, maxY, minY
for(int i = 0; i < points.size(); i++) {
maxX = max(points[i].X, maxX);
minX = min(points[i].X, minX);
maxY = max(points[i].Y, maxY);
minY = min(points[i].Y, minY);
}
// Finally, find a point which matches neither {maxX, minX, maxY, minY}
for(int i = 0; i < points.size(); i++) {
if (points[i].X != maxX && points[i].X != minX && points[i].Y != maxY && points[i].Y != minY) return false;
}
// We are not done yet!
}
Now passing the check in this code makes sure that the points at least form a rectangle and there is no point inside the rectangle. Making sure that the rectangle is a square is the harder part. For that part, you must check that:
A point is on the corner of the rectangle., i.e., both its X-coordinate matches {maxX, minX} AND its Y-coordinate matches {maxY, minY}. If found, you then need to find the largest distance of such point from any other point on the corresponding edges.
If no such corner exists, you are much better off!. In that case, length of the square-side is simply max(maxX-minX, maxY-minY).
You need to be careful while writing pseudocode for this corner-finding part and consider all cases. But I think once done, this would ultimately give the answer.
You can tackle this with the common concept of Axis Aligned Bounding Box (ABB). Given a set of points, compute ABB:
Loop once through all points and find minimum x, minimum y, maximum x and maximum y. Then the box defined by two corners, lower left corner (min_x,min_y) and upper right corner (max, max y) will need to be checked against all the points to see if they lie on its perimeter. Since coordinates are integral (no floating point errors) its fairly easy to do: for each point, either the x-coordinate or the y-coordinate must match with the corresponding coordinates of the AAB, and the other coordinate has to be within range of the other coordinates. Hope that makes sense.