rectangle collision - c++

This is more of a programming problem than a technical question but since it relates to programming and math, I'm hoping to get some helpful feedback.
I have two rectangles: rectangle1 and rectangle2.
Both are defined by four float values:
float left;
float right;
float top;
float bottom;
For the sake of this example, say that each rectangle is 100 x 100 and that rectangle1 is:
float left = 100.0;
float right = 200.0;
float top = 500.0;
float bottom = 600.0;
And rectangle2 is:
float left = 150.0;
float right = 250.0;
float top = 550.0;
float bottom = 650.0;
When a collision occurs, I am trying to determine which side of rectangle1 hit which side of rectangle2 using the eight float values.
If my question was answered, I might be able to determine something like the following when a collision occurs:
rectangle1's right side hit rectangle2's left side
So far, I have tried using simple math to determine the distance between each possibility:
float distance1 = rectangle2.left - rectangle1.right;
float distance2 = rectangle2.top - rectangle1.bottom;
float distance3 = rectangle2.right - rectangle1.left;
float distance4 = rectangle2.bottom - rectangle1.top;
And then taking the minimum of those values to determine which side of each rectangle was involved in the collision. It doesn't seem so simple, though. There were two basic problems with this attempt:
1) The rectangles will already be overlapping by the time the collision code is reached.
2) If multiple rectangles are stacked on top of each other, the calculation will produce strange results (ie, even if rectangle1 is moving in the upper right direction and should hit both rectangles on their left side, it may actually hit one rectangle on the bottom and the other on the left.)
(This is because the rectangles are overlapping when the collision code is reached AND because distance1 and distance4 will be close or equal in this case.)
Is there a better way to answer this question using simple math? Any help would be appreciated.
And, before it's mentioned, this is not homework but a real problem I'm trying to solve for my game.

If you can correctly identify the collision, then to determine the faces draw a line joining the center of the 2 rectangles and check for intersection with the faces of each rectangle. At any given time the line will intersect 2 faces as long as the 2 rectangles are not overlapping or to be precise, as long as the center of 1 is not inside the other.
When they are overlapping, you can get 1 or 0 intersection.
case 0: 1 rectangle is totally inside the other so you can decide how you want to decide which sides are hitting, may be choose the one closest to each center.
case 1: rectangle is totally or partially inside the other. In either case, continue to extend your line joining the centers until you cross the outer (containing) rectangle. If u cross the contained rectangle before again, just change the hit face to the newly crossed face.
Hope its not too confusing :)

Related

Ellipse rotated not centered

I am trying to draw a rotated ellipse not centered at the origin (in c++).
so far my code "works":
for (double i = 0; i <= 360; i = i + 1) {
theta = i*pi / 180;
x = (polygonList[compt]->a_coeff / 2) * sin(theta) + polygonList[compt]->centroid->datapointx;
y = (polygonList[compt]->b_coeff / 2) * cos(theta) + polygonList[compt]->centroid->datapointy;
xTmp = (x - polygonList[compt]->centroid->datapointx)* cos(angle1) - (y - polygonList[compt]->centroid->datapointy)*sin(angle1) + polygonList[compt]->centroid->datapointx;
yTmp = (x - polygonList[compt]->centroid->datapointx)* sin(angle1) + (y - polygonList[compt]->centroid->datapointy)*cos(angle1) + polygonList[compt]->centroid->datapointy;
}
PolygonList is a list of "bloc" which will be replaced by an ellipse of same area.
My issue is that the angles are not quite exact, as if I had to put a protractor that'd fit the shape of my ellipse, the protractor would obviously get squeezed, and so would be the angles (is that clear ?)
Here is an example: I am trying to set a point on the top ellipse (E1) which would be lying on a line drawn between the centroid of E1, and any point on the second ellipse (E2).On this example, the point on E2 lies at an angle of ~220-230 degree. I am able to catch this angle, the angle seems ok.
The problem is that if I try to project this point on E1 by using this angle of ~225 degree, I end up on the second red circle on top. it looks like my angle is now ~265 degree, but in fact, if I shape the protractor to fit in my ellipse, I get the right angle (~225) ,cf img 2)
it is a bit hard to see the angle on that re-shaped protractor, but it does show ~225 degree.
My conclusion is that the ellipse is drawn like if I had to drew a circle and then I'd compress it, which changes the distance between the angles.
Could someone tell me how I could fix that ?
PS: to draw those ellipses I just use a for loop which plots a dot at every angle (from 0 to 360). we clearly see on the first picture that the distance between the dots are different whether we are at 0 or at 90 degree.
your parametrisation is exactly that, a circle is a case of ellipse with both axes are equal. It sounds like you need use rational representation of ellipse instead of standard: https://en.m.wikipedia.org/wiki/Ellipse
So, I've asked the question above so that I could find a possible overlap between 2 ellipses by checking the distance between any point on E2 and its projection on E1: if the distance between the centroid of E1 and the projected dot on E1 is larger than the distance between the centroid of E1 to a dot on E2 I'll assume an overlap. I reckon this solution has never been tried (or I haven't search enough) and should work fine. But before working I needed to get those angles right.
I have found a way to avoid using angles and projected dots, by checking the foci:
the sum of the distance between the focus A and B to any point around an axis is constant (let's call it DE1 for E1).
I then check the distance between my foci and any point on E2. If that distance becomes less than DE1, I'll assume a connection.
So far it seems to work fine :)
I'll put that here for anyone in need.
Flo

Using Standard Cartesian Circle formula to draw circle in graphics mode (C++)

I wanted to draw a circle using graphics.h in C++, but not directly using the circle() function. The circle I want to draw uses smaller circles as it's points i.e. The smaller circles would constitute the circumference of the larger circle. So I thought, if I did something like this, it would work:
{
int radius = 4;
// Points at which smaller circles would be drawn
int x, y;
int maxx = getmaxx();
int maxy = getmaxy();
// Co-ordinates of center of the larger circle (centre of the screen)
int h = maxx/2;
int k = maxy/2;
//Cartesian cirle formula >> (X-h)^2 + (Y-k)^2 = radius^2
//Effectively, this nested loop goes through every single coordinate on the screen
int gmode = DETECT;
int gdriver;
initgraph(&gmode, &gdriver, "");
for(x = 0; x<maxx; x++)
{
for(y = 0; y<maxy; y++)
{
if((((x-h)*(x-h)) + ((y-k)*(y-k))) == (radius*radius))
{
circle(x, y, 5) //Draw smaller circle with radius 5
} //at points which satisfy circle equation only!
}
}
getch();
}
This is when I'm using graphics.h on Turbo C++ as this is the compiler we're learning with at school.
I know it's ancient.
So, theoretically, since the nested for loops check all the points on the screen, and draw a small circle at every point that satisfies the circle equation only, I thought I would get a large circle of radius as entered, whose circumference constitutes of the smaller circles I make in the for loop.
However, when I try the program, I get four hyperbolas (all pointing towards the center of the screen) and when I increase the radius, the pointiness (for lack of a better word) of the hyperbolas increase, until finally, when the radius is 256 or more, the two hyperbolas on the top and bottom intersect to make a large cross on my screen like : "That's it, user, I give up!"
I came to the value 256 as I noticed that of the radius was a multiple of 4 the figures looked ... better?
I looked around for a solution for quite some time, but couldn't get any answers, so here I am.
Any suggestions???
EDIT >> Here's a rough diagram of the output I got...
There are two issues in your code:
First: You should really call initgraph before you call getmaxx and getmaxy, otherwise they will not necessarily return the correct dimensions of the graphics mode. This may or may not be a contributing factor depending on your setup.
Second, and most importantly: In Turbo C++, int is 16-bit. For example, here is circle with radius 100 (after the previous initgraph order issue was fixed):
Note the stray circles in the four corners. If we do a little debugging and add some print-outs (a useful strategy that you should file away for future reference):
if((((x-h)*(x-h)) + ((y-k)*(y-k))) == (radius*radius))
{
printf(": (%d-%d)^2 + (%d-%d)^2 = %d^2\n", x, h, y, k, radius);
circle(x, y, 5); //Draw smaller circle with radius
} //at points which satisfy circle equation only!
You can see what's happening (first line is maxx and maxy, not shown in above snippet):
In particular that circle at (63, 139) is one of the corners. If you do the math, you see that:
(63 - 319)2 + (139 - 239)2 = 75536
And since your ints are 16-bit, 75536 modulo 65536 = 10000 = the value that ends up being calculated = 1002 = a circle where it shouldn't be.
An easy solution to this is to just change the relevant variables to long:
maxx, maxy
x, y
h, k
So:
long x, y;
...
initgraph(...);
...
long maxx = getmaxx();
long maxy = getmaxy();
...
long h = maxx / 2;
long k = maxy / 2;
And then you'll end up with correct output:
Note of course that like other answers point out, since you are using ints, you'll miss a lot of points. This may or may not be OK, but some values will produce noticeably poorer results (e.g. radius 256 only seems to have 4 integer solutions). You could introduce a tolerance if you want. You could also use a more direct approach but that might defeat the purpose of your exercise with the Cartesian circle formula. If you're into this sort of thing, here is a 24-page document containing a bunch of discussion, proofs, and properties about integers that are the sum of two squares.
I don't know enough about Turbo C++ to know if you can make it use 32-bit ints, I'll leave that as an exercise to you.
First of all, maxx and maxy are integers, which you initialize using some functions representing the borders of the screen and then later you use them as functions. Just remove the paranthesis:
// Co-ordinates of center of the larger circle (centre of the screen)
int h = maxx/2;
int k = maxy/2;
Then, you are checking for exact equality to check whether a point is on a circle. Since the screen is a grid of pixels, many of your points will be missed. You need to add a tolerance, a maximum distance between the point you check and the actual circle. So change this line:
if(((x-h)*(x-h)) + ((y-k)*(y-k)) == radius*radius)
to this:
if(abs(((x-h)*(x-h)) + ((y-k)*(y-k)) - radius*radius) < 2)
Introduction of some level of tolerance will solve the problem.
But it is not wise to check all the points in graphical window. Would you change an approach? You can draw needed small circles without checks at all:
To fill all big circle circumference (with RBig radius), you need NCircles small circles with RSmall radius
NCircles = round to integer (Pi / ArcSin(RSmall / RBig));
Center of i-th small circle is at position
cx = mx + Round(RBig * Cos(i * 2 * Pi / N));
cy = my + Round(RBig * Sin(i * 2 * Pi / N));
where mx, my - center of the big circle

C++ recognize shape from points

I'am trying to find out an algorithm to recognize circle in array of points.
Lets say that I've got points array where circle could or could not be stored (that also means array doesn't have to store only circle's points, there could be some "extra" points before or after circle's data).
I've already tried some algorithms but none of them work properly with those "extra" points. Have you got any ideas how to deal with this problem?
EDIT// I didn't mention that before. I want this algorithm to be used on circle gesture recognition. I've thought I would have data in array (for last few seconds) and by analysing this data in every tracking frame I would be able to say if there was or was not a circle gesture.
First I calculate the geometric mean (not the aritmetic mean) for each X and Y component.
I choose geometric mean because one feature is that small values ​​(with respect to the arithmetic mean ) of the values ​​are much more influential than the large values.
This lead me to the theoretical center of all points: circ_center
Then I calculate the standard deviation of distance of each point to center: stddev. This gives me the "indicator" to quantify the amount of variation. One property of circle is that all circumference point is at the same distance of it's center. With standard dev I try to test if your points are (with max variance threshold: max_dispersion) equally distance.
Last I calculates the average distance of points inside max_dispersion threshold from center, this give me the radius of the circle: avg_dist.
Parameters:
max_dispersion represents the "cicle precision". Smaller means more precise.
min_points_needed is the minimun number of points valid to be considered as circumference.
This is just an attempt, I have not tried. Let me know.
I will try this (in pseudo language)
points_size = 100; //number_of_user_points
all_poins[points_size]; //coordinates of points
//thresholds to be defined by user
max_dispersion = 20; //value of max stddev accepted, expressed in geometric units
min_points_needed = 5; //minimum number of points near the circumference
stddev = 0; //standard deviation of points from center
circ_center; //estimated circumference center, using Geometric mean
num_ok_points = 0; //points with distance under standard eviation
avg_dist = 0; //distance from center of "ok points"
all_x = 1; all_y = 1;
for(i = 0 ; i < points_size ; i++)
{
all_x = all_x * all_poins[i].x;
all_y = all_y * all_poins[i].y;
}
//pow(x, 1/y) = nth root
all_x = pow(all_x, 1 / points_size); //Geometric mean
all_y = pow(all_y, 1 / points_size); //Geometric mean
circ_center = make_point(all_x, all_y);
for(i = 0 ; i < points_size ; i++)
{
dist = distance(all_poins[i], circ_center);
stddev = stddev + (dist * dist);
}
stddev = square_root(stddev / points_size);
for(i = 0 ; i < points_size ; i++)
{
if( distance(all_poins[i], circ_center) < max_dispersion )
{
num_ok_points++;
avg_dist = avg_dist + distance(all_poins[i], circ_center);
}
}
avg_dist = avg_dist / num_ok_points;
if(stddev <= max_dispersion && num_ok_points >= min_points_needed)
{
circle recognized; it's center is circ_center; it's radius is avg_dist;
}
Can we assume the array of points are mostly on or near to the circumference of the circle?
A circle has a center and radius. If you can determine the circle's center coordinates, via the intersection of perpendiculars of two chords, then all the true circle points should be equidistant(r), from the center point.
The false points can be eliminated by not being equidistant (+-)tolerance from the center point.
The weakness of this approach is how well can you determine the center and radius? You may want to try a least squares approach to computing the center coordinates.
To answer the initially stated question, my approach would be to iterate through the points and derive the center of a circle from each consecutive set of three points. Then, take the longest contiguous subset of points that create circles with centers that fall within some absolute range. Then determine if the points wind consistently around the average of the circles. You can always perform some basic heuristics on any discarded data to determine if a circle is actually what the user wanted to make though.
Now, since you say that you want to perform gesture recognition, I would suggest you think of a completely different method. Personally, I would first create a basic sort of language that can be used to describe gestures. It should be very simple; the only words I would consider having are:
Start - Denotes the start of a stroke
Angle - The starting angle of the stroke. This should be one of the eight major cardinal directions (N, NW, W, SW, S, SE, E, NE) or Any for unaligned gestures. You could also add combining mechanisms, or perhaps "Axis Aligned" or other such things.
End - Denotes the end of a stroke
Travel - Denotes a straight path in the stroke
Distance - The percentage of the total length of the path that this particular operation will consume.
Turn - Denotes a turn in the stroke
Direction - The direction to turn in. Choices would be Left, Right, Any, Previous, or Opposite.
Angle - The angle of the turn. I would suggest you use just three directions (90 deg, 180 deg, 270 deg)
Tolerance - The maximum tolerance for deviation from the specified angle. This should have a default of somewhere around 45 degrees in either direction for a high chance of matching the angle in a signature.
Type - Hard or Radial. Radial angles would be a stroke along a radius. Hard angles would be a turn about a point.
Radius - If the turn is radial, this is the radius of the turn (units are in percentage of total path length, with appropriate conversions of course)
Obviously you can make the angles much more fine, but the coarser the ranges are, the more tolerant of input error it can be. Being too tolerant can lead to misinterpretation though.
If you apply some fuzzy logic, it wouldn't be hard to break just about any gesture down into a language like this. You could then create a bunch of gesture "signatures" that describe various gestures that can be performed. For instance:
//Circle
Start Angle=Any
Turn Type=Radial Direction=Any Angle=180deg Radius=50%
Turn Type=Radial Direction=Previous Angle=180deg Radius=50%
End
//Box
Start Angle=AxisAligned
Travel Distance=25%
Turn Type=Hard Direction=Any Angle=90deg Tolerance=10deg
Travel Distance=25%
Turn Type=Hard Direction=Previous Angle=90deg Tolerance=10deg
Travel Distance=25%
Turn Type=Hard Direction=Previous Angle=90deg Tolerance=10deg
Travel Distance=25%
End
If you want, I could work on an algorithm that could take a point cloud and degenerate it into a series of commands like this so you can compare them with pre-generated signatures.

Precision problems in raycasting algorithm

I am programming a raycasting engine.
The starting position of a ray is given by the position of the player who is standing inside a 2D-grid.
When casting a ray into a direction, I have to determine the grids that the ray is intersecting.
(The in-depth description of the concept is here: http://www.permadi.com/tutorial/raycast/rayc7.html)
There is a small inaccuracy which causes some trouble. I believe that the problem is caused by an incorrect calculation of the grid steps.
However I lack the mathematical understanding to fix that problem.
Problem description:
When the ray is heading to the left, the grid intersection step size is slightly different than the step size when it's heading to the right.
(Why do I even care about this?: It's causing the problem that some horizontal grid intersections are further away from the player than vertical grid intersections when vertical and horizontal intersections are close to each other, specifically in corners. Since I am using different textures for vertical intersections, the look of horizontal walls are ruined, because a vertical texture is used on small parts of the wall, even though it's an horizontal wall.)
Is this problem caused by a flaw in my algorithm? This is how I calculate the first horizontal grid intersection and the grid stepsize:
Find first grid intersection:
if (current_angle > 180) {
first_grid_horizontal_y = ((int)p.pos_y / Field::width) * Field::width + Field::width;
} else {
first_grid_horizontal_y = ((int)p.pos_y / Field::width) * Field::width - 1;
}
first_grid_horizontal_x = p.pos_x + (p.pos_y - first_grid_horizontal_y) / tan( 180 - current_angle);
Calculate the step size:
if (current_angle > 180) {
grid_stepsize_horizontal_y = Field::width;
grid_stepsize_horizontal_x = Field::width / tan(current_angle - 180);
} else {
grid_stepsize_horizontal_y = -Field::width;
grid_stepsize_horizontal_x = Field::width / tan(180 - current_angle);
}
As you can see I am always using "180 - current angle" to determine the direction of the x-value. Does this cause the inaccurancy? Do I have to differentiate more between angles?
Trigonometric functions work with radians, not degrees. So
tan(180 - current_angle)
should look like
tan(Math.Pi - current_angle)
Note that it is equal to
- tan(current_angle)
If your current_angle is in degrees that:
current_angle_radians = current_angle_degrees * Math.Pi / 180
I think your inaccuracy comes from subracting 1 when going upwards.
The idea behind this is probably that you want to get the index of the last pixel of a block, but that is inneccessary: You are doing floating-point math here and the y value of the next horizontal intersection should represent the line between the grid cells. If you go downward, it represents to uppermost coordinate of a cell; if you go upwards it represents the lowermost coordinate.
(Aside: (int) y / w will round towards zero and will thus only work for non-negative numbers. You might consider using floor(x / w).)

Points on a circle, with limits. How To calculate without angle, but radius and centre point?

This is quite complicated to explain, so I will do my best, sorry if there is anything I missed out, let me know and I will rectify it.
My question is, I have been tasked to draw this shape,
(source: learnersdictionary.com)
This is to be done using C++ to write code that will calculate the points on this shape.
Important details.
User Input - Centre Point (X, Y), number of points to be shown, Font Size (influences radius)
Output - List of co-ordinates on the shape.
The overall aim once I have the points is to put them into a graph on Excel and it will hopefully draw it for me, at the user inputted size!
I know that the maximum Radius is 165mm and the minimum is 35mm. I have decided that my base Font Size shall be 20. I then did some thinking and came up with the equation.
Radius = (Chosen Font Size/20)*130. This is just an estimation, I realise it probably not right, but I thought it could work at least as a template.
I then decided that I should create two different circles, with two different centre points, then link them together to create the shape. I thought that the INSIDE line will have to have a larger Radius and a centre point further along the X-Axis (Y staying constant), as then it could cut into the outside line.
So I defined 2nd Centre point as (X+4, Y). (Again, just estimation, thought it doesn't really matter how far apart they are).
I then decided Radius 2 = (Chosen Font Size/20)*165 (max radius)
So, I have my 2 Radii, and two centre points.
Now to calculate the points on the circles, I am really struggling. I decided the best way to do it would be to create an increment (here is template)
for(int i=0; i<=n; i++) //where 'n' is users chosen number of points
{
//Equation for X point
//Equation for Y Point
cout<<"("<<X<<","<<Y<<")"<<endl;
}
Now, for the life of me, I cannot figure out an equation to calculate the points. I have found equations that involve angles, but as I do not have any, I'm struggling.
I am, in essence, trying to calculate Point 'P' here, except all the way round the circle.
(source: tutorvista.com)
Another point I am thinking may be a problem is imposing limits on the values calculated to only display the values that are on the shape.? Not sure how to chose limits exactly other than to make the outside line a full Half Circle so I have a maximum radius?
So. Does anyone have any hints/tips/links they can share with me on how to proceed exactly?
Thanks again, any problems with the question, sorry will do my best to rectify if you let me know.
Cheers
UPDATE;
R1 = (Font/20)*130;
R2 = (Font/20)*165;
for(X1=0; X1<=n; X1++)
{
Y1 = ((2*Y)+(pow(((4*((pow((X1-X), 2)))+(pow(R1, 2)))), 0.5)))/2;
Y2 = ((2*Y)-(pow(((4*((pow((X1-X), 2)))+(pow(R1, 2)))), 0.5)))/2;
cout<<"("<<X1<<","<<Y1<<")";
cout<<"("<<X1<<","<<Y2<<")";
}
Opinion?
As per Code-Guru's comments on the question, the inner circle looks more like a half circle than the outer. Use the equation in Code-Guru's answer to calculate the points for the inner circle. Then, have a look at this question for how to calculate the radius of a circle which intersects your circle, given the distance (which you can set arbitrarily) and the points of intersection (which you know, because it's a half circle). From this you can draw the outer arc for any given distance, and all you need to do is vary the distance until you produce a shape that you're happy with.
This question may help you to apply Code-Guru's equation.
The equation of a circle is
(x - h)^2 + (y - k)^2 = r^2
With a little bit of algebra, you can iterate x over the range from h to h+r incrementing by some appropriate delta and calculate the two corresponding values of y. This will draw a complete circle.
The next step is to find the x-coordinate for the intersection of the two circles (assuming that the moon shape is defined by two appropriate circles). Again, some algebra and a pencil and paper will help.
More details:
To draw a circle without using polar coordinates and trig, you can do something like this:
for x in h-r to h+r increment by delta
calculate both y coordinates
To calculate the y-coordinates, you need to solve the equation of a circle for y. The easiest way to do this is to transform it into a quadratic equation of the form A*y^2+B*y+C=0 and use the quadratic equation:
(x - h)^2 + (y - k)^2 = r^2
(x - h)^2 + (y - k)^2 - r^2 = 0
(y^2 - 2*k*y + k^2) + (x - h)^2 - r^2 = 0
y^2 - 2*k*y + (k^2 + (x - h)^2 - r^2) = 0
So we have
A = 1
B = -2*k
C = k^2 + (x - h)^2 - r^2
Now plug these into the quadratic equation and chug out the two y-values for each x value in the for loop. (Most likely, you will want to do the calculations in a separate function -- or functions.)
As you can see this is pretty messy. Doing this with trigonometry and angles will be much cleaner.
More thoughts:
Even though there are no angles in the user input described in the question, there is no intrinsic reason why you cannot use them during calculations (unless you have a specific requirement otherwise, say because your teacher told you not to). With that said, using polar coordinates makes this much easier. For a complete circle you can do something like this:
for theta = 0 to 2*PI increment by delta
x = r * cos(theta)
y = r * sin(theta)
To draw an arc, rather than a full circle, you simply change the limits for theta in the for loop. For example, the left-half of the circle goes from PI/2 to 3*PI/2.