Check point within polygon - c++

int pnpoly(int npol, float *xp, float *yp, float x, float y)
{
int i, j, c = 0;
for (i = 0, j = npol-1; i < npol; j = i++) {
if ((((yp[i] <= y) && (y < yp[j])) ||
((yp[j] <= y) && (y < yp[i]))) &&
(x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
c = !c;
}
return c;
}
This function checks if a point is within a polygon. How do I deal with a polygon coordinate that is negative? For example,
float x[3] = { 0.16, 1.2, -10 };
float y[3] = { 1.8, 10, -5.5 };
I tried checking a valid point within the polygon and it returns 0.

There are pretty good implementations from the iSurfer
The two methods used in most cases (and the two I know of) are crossing number and winding number. Both of them are not affected by the signs of the polygon/point coordinates. So it must be a bug in your code.
For completeness I'm placing the code for a crossing number test which seems to be what you're trying to do in your code
// a Point is defined by its coordinates {int x, y;}
// isLeft(): tests if a point is Left|On|Right of an infinite line.
// Input: three points P0, P1, and P2
// Return: >0 for P2 left of the line through P0 and P1
// =0 for P2 on the line
// <0 for P2 right of the line
// See: Algorithm 1 "Area of Triangles and Polygons"
inline int isLeft( Point P0, Point P1, Point P2 )
{
return ( (P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y) );
}
//===================================================================
// cn_PnPoly(): crossing number test for a point in a polygon
// Input: P = a point,
// V[] = vertex points of a polygon V[n+1] with V[n]=V[0]
// Return: 0 = outside, 1 = inside
// This code is patterned after [Franklin, 2000]
int cn_PnPoly( Point P, Point* V, int n )
{
int cn = 0; // the crossing number counter
// loop through all edges of the polygon
for (int i=0; i<n; i++) { // edge from V[i] to V[i+1]
if (((V[i].y <= P.y) && (V[i+1].y > P.y)) // an upward crossing
|| ((V[i].y > P.y) && (V[i+1].y <= P.y))) { // a downward crossing
// compute the actual edge-ray intersect x-coordinate
float vt = (float)(P.y - V[i].y) / (V[i+1].y - V[i].y);
if (P.x < V[i].x + vt * (V[i+1].x - V[i].x)) // P.x < intersect
++cn; // a valid crossing of y=P.y right of P.x
}
}
return (cn&1); // 0 if even (out), and 1 if odd (in)
}
//===================================================================
A special case that can arise with the crossing number number test, is when the ray overlaps an edge of the polygon. In that case it becomes somewhat fuzzy how to count intersections. That's why it's not the actual number of intersections we count, but the number we crossed over semiplanes defined by the ray.
The winding number test is more robust to this respect

Note that if your polygon N and N+1 have the same y value then this test can fail computing vt. For example: determining if a point is inside an axis aligned square.
You need to deal with lines parallel on y

Related

Is it possible generate normal map from heightmap texture from math point of view?

My view is that you can not generate normal map only from height map texture?
Am I right or not?
Math Arguments:
Assume that surface is given a continuous bijection from
S = [0,1]
T = [0,1]
Let's call SxT as image space.
It can be proved from differentional geometry that normal to that parametric surface is
If assume that mapping from SxT image space to geometric euclidian space is very simple then we can retrive:
Then you can calculate such partial derivatives with some difference scheme.
We came to that simple formula, only with bold suggestion and this suggestion is absolutely not true.
Sample of the problem from graphics.
Let assume we have triangle in geometric eclidian space with 3 vertices.
Terms are:
normalmap --
it is normal for point with (u,v,1-u-v) barycentric coordinates fetched from (u,v) from suitable 2d texture, and it is in local coord. system relative to triangle.
heihtmap --
it is geometric offset for point with (u,v,1-u-v) barycentric coordinates in normal direction relative to triangle localspace fetched from (u,v) from suitable 2d texture.
During building normalmap we absolutely ignore how heightmap is distributed near (u,v,1-u-v) eculidian point. And we retrive only some approximation of normal map.
Ohh, looks like my comment was too brief.
It's easier to write a full answer with code to describe the method.
I'm going to use a pseudocode mix of C++ and GLSL.
constexpr int width = 32, height = 32;
constexpr float height_scale = 16.0f; // Change if necessary.
float hmap[W][H] = {...};
float normalmap[W][H];
vec3 GetPoint(ivec2 a)
{
a.x %= W;
a.y %= H;
return {a.x, a.y, hmap[a.x][a.y] * height_scale};
}
vec3 GetNormal(ivec2 a, bool loop_hmap)
{
vec3 o = GetPoint(a),
a = GetPoint({a.x + 1, a.y}),
b = GetPoint({a.x, a.y + 1}),
c = GetPoint({a.x - 1, a.y}),
d = GetPoint({a.x, a.y - 1});
vec3 n1 = normalize(cross(a-o, b-o));
vec3 n2 = normalize(cross(b-o, c-o));
vec3 n3 = normalize(cross(c-o, d-o));
vec3 n4 = normalize(cross(d-o, a-o));
if (loop_hmap)
return normalize(n1+n2+n3+n4);
else
{
vec3 sum = {0,0,0};
bool b1 = (a.x+1 >= 0 && a.y >= 0 && a.x+1 < W && a.y < H);
bool b2 = (a.x >= 0 && a.y+1 >= 0 && a.x < W && a.y+1 < H);
bool b3 = (a.x-1 >= 0 && a.y >= 0 && a.x-1 < W && a.y < H);
bool b4 = (a.x >= 0 && a.y-1 >= 0 && a.x < W && a.y-1 < H);
if (b1 && b2) sum += n1;
if (b2 && b3) sum += n2;
if (b3 && b4) sum += n3;
if (b4 && b1) sum += n4;
return normalize(sum);
}
}
int main()
{
for (int i = 0; i < H; i++)
for (int j = 0; j < W; j++)
normalmap[j][i] = GetNormal(j, i, 0);
}
loop_hmap argument of GetNormal() changes how the function computes normals for edge pixels. 1 should be used for tiled textures, like sand and water. 0 should be used for nontiled textures, like items, mobs, trees.
For me my own initial question is invalid and it has a bug!!!
I – original parametric surface with domain as cartesian product of [0,1] and range of it as euclidean space
II - normal to original surface
III - modified original surface with heightmap
IV - normal map which we want to receive with even ignoring geometric modification of the surface by “III”
Final step IV includes a lot of stuff to differentiate: H(s,t) and original definition of the function...I don't perform futher analytic of that equations...But as for me you can't generate normalmap only from (heightmap)...
P.S. To perform futher analytics if you want to do it retrive *.docx file from that place https://yadi.sk/d/Qqx-jO1Ugo3uL As I know it impossible to convert formulas in ms word to latex, but in any case please use it asa draft.

Problems with a simple raytracer in c++

What it does is basically checking for collisions against an array of triangles and drawing an image based on the color of the triangle it hits. I think my problem lies in the collision detection. Code here:
for (int i = 0; i < triangles.size(); i++){
vec3 v0 = triangles[i].v0;
vec3 v1 = triangles[i].v1;
vec3 v2 = triangles[i].v2;
vec3 e1 = v1 - v0;
vec3 e2 = v2 - v0;
vec3 b = start - v0;
mat3 A(-dir, e1, e2);
vec3 x = glm::inverse(A) * b;
if (x.x > 0 && x.y > 0 && (x.x + x.y < 1) && (x.z - start.z>= 0)){
return true;
}
}
...where "dir" is the direction of the ray coming from the camera, calculated as "x - SCREEN_WIDTH / 2, y - SCREEN_HEIGHT / 2, focalLength". SCREEN_WIDTH, SCREEN_HEIGHT and focalLength are constants. Start is the position of the camera, set to 0,0,0.
What I'm not sure about is what x really is and what I should check for before returning true. "x.x > 0 && x.y > 0 && (x.x + x.y < 1)" is supposed to check if the ray hits not only on the same plane but actually inside the triangle, and the last part ("x.z - start.z>= 0", the one I'm least sure about), if the collision happened in front of the camera.
I get images, but no matter how much I try it's never right. It's supposed to be a classic TestModel of a room with different colored walls and two shapes in it. The closest I think I've been is getting four of five walls right, with the far one missing and a part of one of the shapes on the other side of it.
I'm not familiar with the matrix formulation for triangle intersection - it sounds quite expensive.
My own code is below, where my e1 and e2 are equivalent to yours - i.e. they represent the edge vectors from v0 to v1 and v2 respectively:
// NB: triangles are assumed to be in world space
vector3 pvec = vector3::cross(ray.direction(), e2);
double det = e1.dot(pvec);
if (::fabs(det) < math::epsilon) return 0;
double invDet = 1.0 / det;
vector3 tvec(p0, ray.origin());
double u = tvec.dot(pvec) * invDet;
if (u < 0 || u > 1) return 0;
vector3 qvec = vector3::cross(tvec, e1);
double v = ray.direction().dot(qvec) * invDet;
if (v < 0 || u + v > 1) return 0;
double t = e2.dot(qvec) * invDet;
if (t > math::epsilon) { // avoid self intersection
// hit found at distance "t"
}
I suspect the problem is in your calculation of the ray vector, which should be normalised.

Determine whether an infinite straight line (one direction) from a point intersects with a line segment in 2D

I'm trying to find an algorithm that is optimized for finding whether an intersection exists between a (infinite) line and a line segment.
Here on SO and other sites I've seen many line segment - line segment intersections and line - line intersection algorithms, yet finding a 'simpler?' version for one infinite line (from a point in one direction) and a line segment is very hard.
I currently have something like (line segment - line segment intersection):
bool lineSegmentsIntersect(float pX, float pY, float p2X, float p2Y, float qX, float qY, float q2X, float q2Y)
{
// p and p2 define the first line segment
Point2D p(pX, pY);
Point2D p2(p2X, p2Y);
// q and q2 define the second line segment
Point2D q(qX, qY);
Point2D q2(q2X, q2Y);
Point2D r = p2 - p;
Point2D s = q2 - q;
float uNumerator = (q-p)*r;
float denominator = r*s;
if (uNumerator == 0 && denominator == 0) {
// co-linear, so do they overlap?
return ((q.x - p.x < 0) != (q.x - p2.x < 0) != (q2.x - p.x < 0) != (q2.x - p2.x < 0)) ||
((q.y - p.y < 0) != (q.y - p2.y < 0) != (q2.y - p.y < 0) != (q2.y - p2.y < 0));
}
if (denominator == 0) {
// lines are parallel
return false;
}
float u = uNumerator / denominator;
float t = ((q-p)*s) / denominator;
return (t >= 0) && (t <= 1) && (u >= 0) && (u <= 1);
}
Where the * operator is defined as:
float Point2D::operator*(const Point2D &rhs)
{
return x*rhs.y - y*rhs.x;
}
Though I'm looking for something simpler/faster. I'm trying to check whether a point is within a closed shape (the shape is defined by some points and (linear interpolation) straight lines between them.)
From the point I shoot a ray in a predefined direction.
Preferrably [1, 0] or [0, 1] (this could be used as a constant given) if that makes the math easier which I think it might.
Then I check if the ray intersects with each line segments and if that is an odd number it is inside the shape.
Some things I'm thinking of:
If we decide to always shoot a ray straight up then if both of the points of the line segment are below the point we already know that it doesn't intersect.
See Hormann and Agathos, "The point in polygon problem for arbitrary polygons", Computational Geometry 20 (2001) 131–144. for an efficient implementation of the winding algorithm.

Determine if angle lies between 2 other angles

I am trying to figure out whether a angle lies between 2 other angles. I have been trying to create a simple function to perform this but none of my techniques will work for all possible values of the angles.
Can you help me edit my function to correctly determine if a angle lies between 2 other angles?
In the above picture; I use the green point as the central point, then I determine the angle of each line to the green point. I then calculate the angle of the black point to the green point. I am trying to check if the angle of the black dot is BETWEEN the 2 lines' angles.
NOTE: In my case; an angle(targetAngle) is said to lie between 2 other angles IF the difference between the 2 angles is < 180 degrees AND the targetAngle lies in the cavity made by those 2 angles.
The following code should work but it fails for these(which do lie between the angle):
- is_angle_between(150, 190, 110)
- is_angle_between(3, 41, 345)
bool is_angle_between(int target, int angle1, int angle2)
{
int rAngle1 = ((iTarget - iAngle1) % 360 + 360) % 360;
int rAngle2 = ((iAngle2 - iAngle1) % 360 + 360) % 360;
return (0 <= rAngle1 && rAngle1 <= rAngle2);
}
// Example usage
is_angle_between(3, 41, 345);
Another technique I attempted which also doesn't work:
int is_angle_between(int target, int angle1, int angle2)
{
int dif1 = angle1-angle2;
int dif2 = angle2-angle1;
int uDif1 = convert_to_positive_angle( dif1 ); // for eg; convert -15 to 345
int uDif2 = convert_to_positive_angle( dif2 );
if (uDif1 <= uDif2) {
if (dif1 < 0) {
return (target <= angle1 && target >= angle2);
}
else return (in_between_numbers(iTarget, iAngle1, iAngle2));
}
else {
if (dif2 < 0) {
return (target <= angle1 && target >= angle2);
}
else return (in_between_numbers(iTarget, iAngle1, iAngle2));
}
return -1;
}
bool is_angle_between(int target, int angle1, int angle2)
{
// make the angle from angle1 to angle2 to be <= 180 degrees
int rAngle = ((angle2 - angle1) % 360 + 360) % 360;
if (rAngle >= 180)
std::swap(angle1, angle2);
// check if it passes through zero
if (angle1 <= angle2)
return target >= angle1 && target <= angle2;
else
return target >= angle1 || target <= angle2;
}
Inspired by a post about Intervals in modular arithmetic:
static bool is_angle_between(int x, int a, int b) {
b = modN(b - a);
x = modN(x - a);
if (b < 180) {
return x < b;
} else {
return b < x;
}
}
where (in case of checking angles) modN() would be implemented as
// modN(x) is assumed to calculate Euclidean (=non-negative) x % N.
static int modN(int x) {
const int N = 360;
int m = x % N;
if (m < 0) {
m += N;
}
return m;
}
void normalize( float& angle )
{
while ( angle < -180 ) angle += 360;
while ( angle > 180 ) angle -= 360;
}
bool isWithinRange( float testAngle, float a, float b )
{
a -= testAngle;
b -= testAngle;
normalize( a );
normalize( b );
if ( a * b >= 0 )
return false;
return fabs( a - b ) < 180;
}
If angle2 were always 0, and angle1 were always between 0 and 180, this would be easy:
return angle1 < 180 && 0 < target && target < angle1;
if I'm reading the requirements correctly.
But it's not that hard to get there.
int reduced1 = (angle1 - angle2 + 360) % 360; // and imagine reduced2 = 0
if (180 < reduced1) { angle2 = angle1; reduced1 = 360 - reduced1; } // swap if backwards
int reducedTarget = (target - angle2 + 360) % 360;
return reduced1 < 180 && 0 < reducedTarget && reducedTarget < reduced1;
I've done this before by comparing angles.
In the sketch above vector AD will be between AB and AC if and only if
angle BAD + angle CAD == angle BAC
Because of floating point inaccuracies I compared the values after rounding them first to say 5 decimal places.
So it comes down to having an angle algorithm between two vectors p and q which is simply put like:
double a = p.DotProduct(q);
double b = p.Length() * q.Length();
return acos(a / b); // radians
I'll leave the vector DotProduct and Length calculations as a google search exercise. And you get vectors simply by subtracting the coordinates of one terminal from the other.
You should of course first check whether AB and AC are parallel or anti-parallel.
All the top answers here are wrong. As such I feel it is necessary for me to post an answer.
I'm just reposting a portion of an answer which I posted here: https://stackoverflow.com/a/42424631/2642059 That answer also deals with the case where you already know which angle is the lefthand side and righthand side of the reflexive angle. But you also need to determine which side of the angle is which.
1st to find the leftmost angle if either of these statements are true angle1 is your leftmost angle:
angle1 <= angle2 && angle2 - angle1 <= PI
angle1 > angle2 && angle1 - angle2 >= PI
For simplicity let's say that your leftmost angle is l and your rightmost angle is r and you're trying to find if g is between them.
The problem here is the seem. There are essentially 3 positive cases that we're looking for:
l ≤ g ≤ r
l ≤ g ∧ r < l
g ≤ r ∧ r < l
Since you're calculating the lefthand and righthand sides of the angle, you'll notice there is an optimization opportunity here in doing both processes at once. Your function will look like:
if(angle1 <= angle2) {
if(angle2 - angle1 <= PI) {
return angle1 <= target && target <= angle2;
} else {
return angle2 <= target || target <= angle1;
}
} else {
if(angle1 - angle2 <= PI) {
return angle2 <= target && target <= angle1;
} else {
return angle1 <= target || target <= angle2;
}
}
Or if you need it you could expand into this nightmare condition:
angle1 <= angle2 ?
(angle2 - angle1 <= PI && angle1 <= target && target <= angle2) || (angle2 - angle1 > PI && (angle2 <= target || target <= angle1)) :
(angle1 - angle2 <= PI && angle2 <= target && target <= angle1) || (angle1 - angle2 > PI && (angle1 <= target || target <= angle2))
Note that all this math presumes that your input is in radians and in the range [0 : 2π].
Live Example
Is angle T between angles A and B, there are always two answers: true and false.
We need specify what we mean, and in this case we're looking for the normalized small sweep angles and whether our angle is between those values. Given any two angles, there is a reflex angle between them, is the normalized value of T within that reflex angle?
If we rotate A and B and T such that T = 0 and normalize A and B to within +-hemicircumference (180° or 2PI). Then our answer is whether A and B have different signs, and are within a hemicircumference of each other.
If we subtract the angle from test, then add 180° (so A is relative to T+180). Then we mod by 360 giving us a range between [-360°,360°] we add 360° and mod again (note, you could also just check if it's negative and add 360 if it is), giving us a value that is certain to be [0°,360°]. We subtract 180° giving us a value between [-180°,180°] relative to T+180°-180° aka, T. So T is now angle zero and all angles fall within the normalized range. Now we check to make sure the angles have a sign change and that they are not more than 180° apart, we have our answer.
Because the question asks in C++:
bool isAngleBetweenNormalizedSmallSweepRange(int test, int a, int b) {
int a_adjust = ((((a - test + 180)) % 360) + 360) % 360 - 180;
int b_adjust = ((((b - test + 180)) % 360) + 360) % 360 - 180;
return ((a_adjust ^ b_adjust) < 0) && ((a_adjust - b_adjust) < 180) && ((a_adjust - b_adjust) > -180);
}
We can also do some tricks to simplify out the code and avoid any unneeded modulo ops (see comments below). Normalize will move angle a into the range [-180°,180°] relative to angle t.
int normalized(int a, int test) {
int n = a - test + 180;
if ((n > 360) || (n < -360)) n %= 360;
return (n > 0)? n - 180: n + 180;
}
bool isAngleBetweenNormalizedSmallSweepRange(int test, int a, int b) {
int a_adjust = normalized(a,test);
int b_adjust = normalized(b,test);
return ((a_adjust ^ b_adjust) < 0) &&
((a_adjust > b_adjust)? a_adjust-b_adjust: b_adjust-a_adjust) < 180;
}
Also if we can be sure the range is [0,360], we can make do with a simpler if statement
bool isAngleBetweenNormalizedSmallSweepRange(int test, int a, int b) {
int dA = a - test + 180;
if (dA > 360) {
dA -= 360;
}
int a_adjust = (dA > 0) ? dA - 180 : dA + 180;
int dB = b - test + 180;
if (dB > 360) {
dB -= 360;
}
int b_adjust = (dB > 0) ? dB - 180 : dB + 180;
return ((a_adjust ^ b_adjust) < 0)
&& ((a_adjust > b_adjust) ? a_adjust - b_adjust : b_adjust - a_adjust) < 180;
}
JS Fiddle test of the code
I've found this quote from this thread:
if a point P is inside triangle ABC, then
Area PAB+Area PBC +Area PAC=Area ABC
notice that if P is on the edge of AB, BC, or CA, the above hold. But
effectively, one of the area PAB, PBC, PAC is 0 (so just make sure you
check that).
if P is outside, the above equality does NOT hold...
How to determine area? you have two options: 1) Heron's theorem,
involves sqrt, slower 2) the more perferred way is the cross products
(or effectively, the half of absolute value of (sum of the down
products minus the sum of up products))
for example, if A=(x1,y1) B=(x2,y2), C=(x3,y3) Area=
abs(x1*y2+x2*y3+x3*y1-x1*y3-x3*y2-x2*y1)/2
also you might want to be careful about floating point errors...
instead of checking for strict inequality, check for abs(b-a)
Hopefully that will help
Using a similar style of function as in your question, I have had good luck with the following methods:
public static bool IsInsideRange(double testAngle, double startAngle, double endAngle)
{
var a1 = System.Math.Abs(AngleBetween(startAngle, testAngle));
var a2 = System.Math.Abs(AngleBetween(testAngle, endAngle));
var a3 = System.Math.Abs(AngleBetween(startAngle, endAngle));
return a1 + a2 == a3;
}
public static double AngleBetween(double start, double end)
{
return (end - start) % 360;
}
I know this post is old, but there doesn't seem to be an accepted answer and I have found the following approach to be quite reliable. Although it might be more than what you need. It supports angle ranges larger than 180 degrees (as well as larger than 360 degrees and negative angles). It also supports decimal accuracy.
The method uses this normalize() helper function to convert angles into the right space:
float normalize( float degrees )
{
//-- Converts the specified angle to an angle between 0 and 360 degrees
float circleCount = (degrees / 360.0f);
degrees -= (int)circleCount * 360;
if( 0.0f > degrees )
{
degrees += 360.0f;
}
return degrees;
}
Here's the solution:
bool isWithinRange( float start, float end, float angle )
{
if( fabsf( end - start ) >= 360.0f )
{
//-- Ranges greater or equal to 360 degrees cover everything
return true;
}
//-- Put our angle between 0 and 360 degrees
float degrees = normalize( angle );
//-- Resolve degree value for the start angle; make sure it's
// smaller than our angle.
float startDegrees = normalize( start );
if( startDegrees > degrees )
{
startDegrees -= 360.0f;
}
//-- Resolve degree value for the end angle to be within the
// same 360 degree range as the start angle and make sure it
// comes after the start angle.
float endDegrees = normalize( end );
if( endDegrees < startDegrees )
{
endDegrees += 360.0f;
}
else if( (endDegrees - startDegrees) >= 360.0f )
{
endDegrees -= 360.0f;
}
//-- All that remains is to validate that our angle is between
// the start and the end.
if( (degrees < startDegrees) || (degrees > endDegrees) )
{
return false;
}
return true;
}
Hope this helps someone.
If you have angles $$a$ and $b$, and wan't to see if angle x is between these angles.
You can calculate the angle between a->x and a->b.
If ∠a->x is less than ∠a->b, x must be between a and b.
The distance between to angles, a and b
function distanceBetweenAngles(a, b) {
distance = b - a;
if (a > b) {
distance += 2*pi;
}
return distance;
}
Then you can do
// Checks if angle 'x' is between angle 'a' and 'b'
function isAngleBetween(x, a, b) {
return distanceBetweenAngles(a, b) >= distanceBetweenAngles(a, x);
}
This assumes you are using Radians, and not Degrees, as one should. It removes a lot of unnecessary code.

Determine if two rectangles overlap each other?

I am trying to write a C++ program that takes the following inputs from the user to construct rectangles (between 2 and 5): height, width, x-pos, y-pos. All of these rectangles will exist parallel to the x and the y axis, that is all of their edges will have slopes of 0 or infinity.
I've tried to implement what is mentioned in this question but I am not having very much luck.
My current implementation does the following:
// Gets all the vertices for Rectangle 1 and stores them in an array -> arrRect1
// point 1 x: arrRect1[0], point 1 y: arrRect1[1] and so on...
// Gets all the vertices for Rectangle 2 and stores them in an array -> arrRect2
// rotated edge of point a, rect 1
int rot_x, rot_y;
rot_x = -arrRect1[3];
rot_y = arrRect1[2];
// point on rotated edge
int pnt_x, pnt_y;
pnt_x = arrRect1[2];
pnt_y = arrRect1[3];
// test point, a from rect 2
int tst_x, tst_y;
tst_x = arrRect2[0];
tst_y = arrRect2[1];
int value;
value = (rot_x * (tst_x - pnt_x)) + (rot_y * (tst_y - pnt_y));
cout << "Value: " << value;
However I'm not quite sure if (a) I've implemented the algorithm I linked to correctly, or if I did exactly how to interpret this?
Any suggestions?
if (RectA.Left < RectB.Right && RectA.Right > RectB.Left &&
RectA.Top > RectB.Bottom && RectA.Bottom < RectB.Top )
or, using Cartesian coordinates
(With X1 being left coord, X2 being right coord, increasing from left to right and Y1 being Top coord, and Y2 being Bottom coord, increasing from bottom to top -- if this is not how your coordinate system [e.g. most computers have the Y direction reversed], swap the comparisons below) ...
if (RectA.X1 < RectB.X2 && RectA.X2 > RectB.X1 &&
RectA.Y1 > RectB.Y2 && RectA.Y2 < RectB.Y1)
Say you have Rect A, and Rect B.
Proof is by contradiction. Any one of four conditions guarantees that no overlap can exist:
Cond1. If A's left edge is to the right of the B's right edge,
- then A is Totally to right Of B
Cond2. If A's right edge is to the left of the B's left edge,
- then A is Totally to left Of B
Cond3. If A's top edge is below B's bottom edge,
- then A is Totally below B
Cond4. If A's bottom edge is above B's top edge,
- then A is Totally above B
So condition for Non-Overlap is
NON-Overlap => Cond1 Or Cond2 Or Cond3 Or Cond4
Therefore, a sufficient condition for Overlap is the opposite.
Overlap => NOT (Cond1 Or Cond2 Or Cond3 Or Cond4)
De Morgan's law says
Not (A or B or C or D) is the same as Not A And Not B And Not C And Not D
so using De Morgan, we have
Not Cond1 And Not Cond2 And Not Cond3 And Not Cond4
This is equivalent to:
A's Left Edge to left of B's right edge, [RectA.Left < RectB.Right], and
A's right edge to right of B's left edge, [RectA.Right > RectB.Left], and
A's top above B's bottom, [RectA.Top > RectB.Bottom], and
A's bottom below B's Top [RectA.Bottom < RectB.Top]
Note 1: It is fairly obvious this same principle can be extended to any number of dimensions.
Note 2: It should also be fairly obvious to count overlaps of just one pixel, change the < and/or the > on that boundary to a <= or a >=.
Note 3: This answer, when utilizing Cartesian coordinates (X, Y) is based on standard algebraic Cartesian coordinates (x increases left to right, and Y increases bottom to top). Obviously, where a computer system might mechanize screen coordinates differently, (e.g., increasing Y from top to bottom, or X From right to left), the syntax will need to be adjusted accordingly/
struct rect
{
int x;
int y;
int width;
int height;
};
bool valueInRange(int value, int min, int max)
{ return (value >= min) && (value <= max); }
bool rectOverlap(rect A, rect B)
{
bool xOverlap = valueInRange(A.x, B.x, B.x + B.width) ||
valueInRange(B.x, A.x, A.x + A.width);
bool yOverlap = valueInRange(A.y, B.y, B.y + B.height) ||
valueInRange(B.y, A.y, A.y + A.height);
return xOverlap && yOverlap;
}
struct Rect
{
Rect(int x1, int x2, int y1, int y2)
: x1(x1), x2(x2), y1(y1), y2(y2)
{
assert(x1 < x2);
assert(y1 < y2);
}
int x1, x2, y1, y2;
};
bool
overlap(const Rect &r1, const Rect &r2)
{
// The rectangles don't overlap if
// one rectangle's minimum in some dimension
// is greater than the other's maximum in
// that dimension.
bool noOverlap = r1.x1 > r2.x2 ||
r2.x1 > r1.x2 ||
r1.y1 > r2.y2 ||
r2.y1 > r1.y2;
return !noOverlap;
}
It is easier to check if a rectangle is completly outside the other, so if it is either
on the left...
(r1.x + r1.width < r2.x)
or on the right...
(r1.x > r2.x + r2.width)
or on top...
(r1.y + r1.height < r2.y)
or on the bottom...
(r1.y > r2.y + r2.height)
of the second rectangle, it cannot possibly collide with it. So to have a function that returns a Boolean saying weather the rectangles collide, we simply combine the conditions by logical ORs and negate the result:
function checkOverlap(r1, r2) : Boolean
{
return !(r1.x + r1.width < r2.x || r1.y + r1.height < r2.y || r1.x > r2.x + r2.width || r1.y > r2.y + r2.height);
}
To already receive a positive result when touching only, we can change the "<" and ">" by "<=" and ">=".
This is a very fast way to check with C++ if two rectangles overlap:
return std::max(rectA.left, rectB.left) < std::min(rectA.right, rectB.right)
&& std::max(rectA.top, rectB.top) < std::min(rectA.bottom, rectB.bottom);
It works by calculating the left and right borders of the intersecting rectangle, and then comparing them: if the right border is equal to or less than the left border, it means that the intersection is empty and therefore the rectangles do not overlap; otherwise, it tries again with the top and bottom borders.
What is the advantage of this method over the conventional alternative of 4 comparisons? It's about how modern processors are designed. They have something called branch prediction, which works well when the result of a comparison is always the same, but have a huge performance penalty otherwise. However, in the absence of branch instructions, the CPU performs quite well. By calculating the borders of the intersection instead of having two separate checks for each axis, we're saving two branches, one per pair.
It is possible that the four comparisons method outperforms this one, if the first comparison has a high chance of being false. That is very rare, though, because it means that the second rectangle is most often on the left side of the first rectangle, and not on the right side or overlapping it; and most often, you need to check rectangles on both sides of the first one, which normally voids the advantages of branch prediction.
This method can be improved even more, depending on the expected distribution of rectangles:
If you expect the checked rectangles to be predominantly to the left or right of each other, then the method above works best. This is probably the case, for example, when you're using the rectangle intersection to check collisions for a game, where the game objects are predominantly distributed horizontally (e.g. a SuperMarioBros-like game).
If you expect the checked rectangles to be predominantly to the top or bottom of each other, e.g. in an Icy Tower type of game, then checking top/bottom first and left/right last will probably be faster:
return std::max(rectA.top, rectB.top) < std::min(rectA.bottom, rectB.bottom)
&& std::max(rectA.left, rectB.left) < std::min(rectA.right, rectB.right);
If the probability of intersecting is close to the probability of not intersecting, however, it's better to have a completely branchless alternative:
return std::max(rectA.left, rectB.left) < std::min(rectA.right, rectB.right)
& std::max(rectA.top, rectB.top) < std::min(rectA.bottom, rectB.bottom);
(Note the change of && to a single &)
Suppose that you have defined the positions and sizes of the rectangles like this:
My C++ implementation is like this:
class Vector2D
{
public:
Vector2D(int x, int y) : x(x), y(y) {}
~Vector2D(){}
int x, y;
};
bool DoRectanglesOverlap( const Vector2D & Pos1,
const Vector2D & Size1,
const Vector2D & Pos2,
const Vector2D & Size2)
{
if ((Pos1.x < Pos2.x + Size2.x) &&
(Pos1.y < Pos2.y + Size2.y) &&
(Pos2.x < Pos1.x + Size1.x) &&
(Pos2.y < Pos1.y + Size1.y))
{
return true;
}
return false;
}
An example function call according to the given figure above:
DoRectanglesOverlap(Vector2D(3, 7),
Vector2D(8, 5),
Vector2D(6, 4),
Vector2D(9, 4));
The comparisons inside the if block will look like below:
if ((Pos1.x < Pos2.x + Size2.x) &&
(Pos1.y < Pos2.y + Size2.y) &&
(Pos2.x < Pos1.x + Size1.x) &&
(Pos2.y < Pos1.y + Size1.y))
↓
if (( 3 < 6 + 9 ) &&
( 7 < 4 + 4 ) &&
( 6 < 3 + 8 ) &&
( 4 < 7 + 5 ))
Ask yourself the opposite question: How can I determine if two rectangles do not intersect at all? Obviously, a rectangle A completely to the left of rectangle B does not intersect. Also if A is completely to the right. And similarly if A is completely above B or completely below B. In any other case A and B intersect.
What follows may have bugs, but I am pretty confident about the algorithm:
struct Rectangle { int x; int y; int width; int height; };
bool is_left_of(Rectangle const & a, Rectangle const & b) {
if (a.x + a.width <= b.x) return true;
return false;
}
bool is_right_of(Rectangle const & a, Rectangle const & b) {
return is_left_of(b, a);
}
bool not_intersect( Rectangle const & a, Rectangle const & b) {
if (is_left_of(a, b)) return true;
if (is_right_of(a, b)) return true;
// Do the same for top/bottom...
}
bool intersect(Rectangle const & a, Rectangle const & b) {
return !not_intersect(a, b);
}
In the question, you link to the maths for when rectangles are at arbitrary angles of rotation. If I understand the bit about angles in the question however, I interpret that all rectangles are perpendicular to one another.
A general knowing the area of overlap formula is:
Using the example:
1 2 3 4 5 6
1 +---+---+
| |
2 + A +---+---+
| | B |
3 + + +---+---+
| | | | |
4 +---+---+---+---+ +
| |
5 + C +
| |
6 +---+---+
1) collect all the x coordinates (both left and right) into a list, then sort it and remove duplicates
1 3 4 5 6
2) collect all the y coordinates (both top and bottom) into a list, then sort it and remove duplicates
1 2 3 4 6
3) create a 2D array by number of gaps between the unique x coordinates * number of gaps between the unique y coordinates.
4 * 4
4) paint all the rectangles into this grid, incrementing the count of each cell it occurs over:
1 3 4 5 6
1 +---+
| 1 | 0 0 0
2 +---+---+---+
| 1 | 1 | 1 | 0
3 +---+---+---+---+
| 1 | 1 | 2 | 1 |
4 +---+---+---+---+
0 0 | 1 | 1 |
6 +---+---+
5) As you paint the rectangles, its easy to intercept the overlaps.
Here's how it's done in the Java API:
public boolean intersects(Rectangle r) {
int tw = this.width;
int th = this.height;
int rw = r.width;
int rh = r.height;
if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
return false;
}
int tx = this.x;
int ty = this.y;
int rx = r.x;
int ry = r.y;
rw += rx;
rh += ry;
tw += tx;
th += ty;
// overflow || intersect
return ((rw < rx || rw > tx) &&
(rh < ry || rh > ty) &&
(tw < tx || tw > rx) &&
(th < ty || th > ry));
}
struct Rect
{
Rect(int x1, int x2, int y1, int y2)
: x1(x1), x2(x2), y1(y1), y2(y2)
{
assert(x1 < x2);
assert(y1 < y2);
}
int x1, x2, y1, y2;
};
//some area of the r1 overlaps r2
bool overlap(const Rect &r1, const Rect &r2)
{
return r1.x1 < r2.x2 && r2.x1 < r1.x2 &&
r1.y1 < r2.y2 && r2.x1 < r1.y2;
}
//either the rectangles overlap or the edges touch
bool touch(const Rect &r1, const Rect &r2)
{
return r1.x1 <= r2.x2 && r2.x1 <= r1.x2 &&
r1.y1 <= r2.y2 && r2.x1 <= r1.y2;
}
Don't think of coordinates as indicating where pixels are. Think of them as being between the pixels. That way, the area of a 2x2 rectangle should be 4, not 9.
bool bOverlap = !((A.Left >= B.Right || B.Left >= A.Right)
&& (A.Bottom >= B.Top || B.Bottom >= A.Top));
Easiest way is
/**
* Check if two rectangles collide
* x_1, y_1, width_1, and height_1 define the boundaries of the first rectangle
* x_2, y_2, width_2, and height_2 define the boundaries of the second rectangle
*/
boolean rectangle_collision(float x_1, float y_1, float width_1, float height_1, float x_2, float y_2, float width_2, float height_2)
{
return !(x_1 > x_2+width_2 || x_1+width_1 < x_2 || y_1 > y_2+height_2 || y_1+height_1 < y_2);
}
first of all put it in to your mind that in computers the coordinates system is upside down. x-axis is same as in mathematics but y-axis increases downwards and decrease on going upward..
if rectangle are drawn from center.
if x1 coordinates is greater than x2 plus its its half of widht. then it means going half they will touch each other. and in the same manner going downward + half of its height. it will collide..
For those of you who are using center points and half sizes for their rectangle data, instead of the typical x,y,w,h, or x0,y0,x1,x1, here's how you can do it:
#include <cmath> // for fabsf(float)
struct Rectangle
{
float centerX, centerY, halfWidth, halfHeight;
};
bool isRectangleOverlapping(const Rectangle &a, const Rectangle &b)
{
return (fabsf(a.centerX - b.centerX) <= (a.halfWidth + b.halfWidth)) &&
(fabsf(a.centerY - b.centerY) <= (a.halfHeight + b.halfHeight));
}
Lets say the two rectangles are rectangle A and rectangle B. Let their centers be A1 and B1 (coordinates of A1 and B1 can be easily found out), let the heights be Ha and Hb, width be Wa and Wb, let dx be the width(x) distance between A1 and B1 and dy be the height(y) distance between A1 and B1.
Now we can say we can say A and B overlap: when
if(!(dx > Wa+Wb)||!(dy > Ha+Hb)) returns true
If the rectangles overlap then the overlap area will be greater than zero. Now let us find the overlap area:
If they overlap then the left edge of overlap-rect will be the max(r1.x1, r2.x1) and right edge will be min(r1.x2, r2.x2). So the length of the overlap will be min(r1.x2, r2.x2) - max(r1.x1, r2.x1)
So the area will be:
area = (max(r1.x1, r2.x1) - min(r1.x2, r2.x2)) * (max(r1.y1, r2.y1) - min(r1.y2, r2.y2))
If area = 0 then they don't overlap.
Simple isn't it?
I have implemented a C# version, it is easily converted to C++.
public bool Intersects ( Rectangle rect )
{
float ulx = Math.Max ( x, rect.x );
float uly = Math.Max ( y, rect.y );
float lrx = Math.Min ( x + width, rect.x + rect.width );
float lry = Math.Min ( y + height, rect.y + rect.height );
return ulx <= lrx && uly <= lry;
}
I have a very easy solution
let x1,y1 x2,y2 ,l1,b1,l2,be cordinates and lengths and breadths of them respectively
consider the condition ((x2
now the only way these rectangle will overlap is if the point diagonal to x1,y1 will lie inside the other rectangle or similarly the point diagonal to x2,y2 will lie inside the other rectangle. which is exactly the above condition implies.
A and B be two rectangle. C be their covering rectangle.
four points of A be (xAleft,yAtop),(xAleft,yAbottom),(xAright,yAtop),(xAright,yAbottom)
four points of A be (xBleft,yBtop),(xBleft,yBbottom),(xBright,yBtop),(xBright,yBbottom)
A.width = abs(xAleft-xAright);
A.height = abs(yAleft-yAright);
B.width = abs(xBleft-xBright);
B.height = abs(yBleft-yBright);
C.width = max(xAleft,xAright,xBleft,xBright)-min(xAleft,xAright,xBleft,xBright);
C.height = max(yAtop,yAbottom,yBtop,yBbottom)-min(yAtop,yAbottom,yBtop,yBbottom);
A and B does not overlap if
(C.width >= A.width + B.width )
OR
(C.height >= A.height + B.height)
It takes care all possible cases.
This is from exercise 3.28 from the book Introduction to Java Programming- Comprehensive Edition. The code tests whether the two rectangles are indenticle, whether one is inside the other and whether one is outside the other. If none of these condition are met then the two overlap.
**3.28 (Geometry: two rectangles) Write a program that prompts the user to enter the
center x-, y-coordinates, width, and height of two rectangles and determines
whether the second rectangle is inside the first or overlaps with the first, as shown
in Figure 3.9. Test your program to cover all cases.
Here are the sample runs:
Enter r1's center x-, y-coordinates, width, and height: 2.5 4 2.5 43
Enter r2's center x-, y-coordinates, width, and height: 1.5 5 0.5 3
r2 is inside r1
Enter r1's center x-, y-coordinates, width, and height: 1 2 3 5.5
Enter r2's center x-, y-coordinates, width, and height: 3 4 4.5 5
r2 overlaps r1
Enter r1's center x-, y-coordinates, width, and height: 1 2 3 3
Enter r2's center x-, y-coordinates, width, and height: 40 45 3 2
r2 does not overlap r1
import java.util.Scanner;
public class ProgrammingEx3_28 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out
.print("Enter r1's center x-, y-coordinates, width, and height:");
double x1 = input.nextDouble();
double y1 = input.nextDouble();
double w1 = input.nextDouble();
double h1 = input.nextDouble();
w1 = w1 / 2;
h1 = h1 / 2;
System.out
.print("Enter r2's center x-, y-coordinates, width, and height:");
double x2 = input.nextDouble();
double y2 = input.nextDouble();
double w2 = input.nextDouble();
double h2 = input.nextDouble();
w2 = w2 / 2;
h2 = h2 / 2;
// Calculating range of r1 and r2
double x1max = x1 + w1;
double y1max = y1 + h1;
double x1min = x1 - w1;
double y1min = y1 - h1;
double x2max = x2 + w2;
double y2max = y2 + h2;
double x2min = x2 - w2;
double y2min = y2 - h2;
if (x1max == x2max && x1min == x2min && y1max == y2max
&& y1min == y2min) {
// Check if the two are identicle
System.out.print("r1 and r2 are indentical");
} else if (x1max <= x2max && x1min >= x2min && y1max <= y2max
&& y1min >= y2min) {
// Check if r1 is in r2
System.out.print("r1 is inside r2");
} else if (x2max <= x1max && x2min >= x1min && y2max <= y1max
&& y2min >= y1min) {
// Check if r2 is in r1
System.out.print("r2 is inside r1");
} else if (x1max < x2min || x1min > x2max || y1max < y2min
|| y2min > y1max) {
// Check if the two overlap
System.out.print("r2 does not overlaps r1");
} else {
System.out.print("r2 overlaps r1");
}
}
}
bool Square::IsOverlappig(Square &other)
{
bool result1 = other.x >= x && other.y >= y && other.x <= (x + width) && other.y <= (y + height); // other's top left falls within this area
bool result2 = other.x >= x && other.y <= y && other.x <= (x + width) && (other.y + other.height) <= (y + height); // other's bottom left falls within this area
bool result3 = other.x <= x && other.y >= y && (other.x + other.width) <= (x + width) && other.y <= (y + height); // other's top right falls within this area
bool result4 = other.x <= x && other.y <= y && (other.x + other.width) >= x && (other.y + other.height) >= y; // other's bottom right falls within this area
return result1 | result2 | result3 | result4;
}
struct point { int x, y; };
struct rect { point tl, br; }; // top left and bottom right points
// return true if rectangles overlap
bool overlap(const rect &a, const rect &b)
{
return a.tl.x <= b.br.x && a.br.x >= b.tl.x &&
a.tl.y >= b.br.y && a.br.y <= b.tl.y;
}