How to calculate position of a moving object on a line - c++

So basically I'm making a pool game (sort of) on c++. I'm still thinking about the theory and how exactly to make it before I start coding and I'm a bit stuck. So the ball starting coordinates are given and also an input is given on how much power is going into the shot and the direction of the shot with coordinates.
Example:
> Ball: (280,70)
Input:
> 2(power) 230(x) 110(y)
Output:
> 180(x) 150(y)
The power means that basically it's going to go X * the distance of the given coordinates. So if it's 1 it would just go to 230 110 but if it's more it will go double, triple, quadruple, etc. times that distance. (external factors should be ignored - friction, etc.)
By now I've managed to create an algorithm to find the line that the ball is going to travel on. But I can't figure out on what point of this line the ball will stop at. Any help will be greatly appreciated!
Also one more thing, I also need to calculate where it would go if it hits the wall of the pool table(pool table is a 2:1 rectangle with given coordinates of edges) and I've also managed to find the line where it would travel on but not the exact point where it will stop.
TL;DR I need to find the point of the line of travel that a billiards ball will stop at.

You probably want to work in terms of orthogonal components, basically thinking of the displacement of the ball in terms of deltaX and deltaY instead of finding a line it will travel. Conveniently, you are already in rectangular coordinates and can compute your changes in x and y followed by scaling them by your power factor. For example, here, deltaX = 2*(280-230) or -100, so the destination will be 280 + -100, which equals 180.
To account for the edges, you bound the movement in any direction to be within the 4 edges. You'll have some extra displacement if it strikes the edge. You might think of a bounce as reversing some of the remainder and then recursively call your moveBall function with power 1 when given the location on the edge the ball strikes plus the excess deltaX and deltaY changed in sign appropriately. If moveBall took std::pair<int, int> startingPosition, std::pair<int, int> displacement, int power, if it hits the wall, you'll return moveBall(locationOnEdge, predictedLocationBasedOnExcess, 1). This setup will recursively call itself as many times as is needed until the ball finally finds its ending position (a ball can bounce off edges multiple times).
For example, if you had an edge at x = 200 and y = 100 (meaning your asserted desired output was different), you'd have a remaining deltaX of -20 and deltaY of 50. Since the ball was traveling up and to the left, it will bounce down and to the left. You'd call moveBall with starting location (200, 100), displacement (-20, -50), and power 1.
I'm doing some guesswork here since you didn't define the expected behavior when the ball bounces off an edge.

Related

How a feature descriptior for traffic sign detection works in opencv

I am trying to understand how Centroid to Contour (CtC) detector works. Here is a sample code that I have found on Github, and I am trying to understand what is the idea behind this. In this sample, the author trying to detect speed sign using CtC. There are just two important functions:
pre_process()
CtC_features
I have understood a part of the code and how it works but I have some problems in understanding how CtC_features function works.
If you can help me I would like to understand the following parts (just 3 points):
Why if centroid.x > curr.x we need to add PI value to the angle result ( if (centroid.x > curr.x) ang += 3.14159; //PI )
When we start selecting the features on line 97 we set the start angle ( double ang = - 1.57079; ). Why is this half the pi value and negative? How was this value chosen?
And a more general question, how can you know that what feature you select are related to speed limit sign? You find the centroid of the image and adjust the angle in the first step, but in the second step how can you know if ( while (feature_v[i].first > ang) ) the current angle is bigger than your hardcode angle ( in first case ang = - 1.57079) then we add that distance as a feature.
I would like to understand the idea behind this code and if someone with more experience and with some knowledge about trigonometry would help me it will be just great.
Thank you.
The code you provided is not the best, but let's see what happens.
I took this starting image of a sign:
Then, pre_process is called, which basically runs a Canny edge detector, along with some tricks which should lead to a better edge detection. I won't look into them, but this is what it returns:
Not the greatest. Maybe some parameter tuning would help.
But now, CtC_features is called, which is the scope of the question. The role of CtC_features is to obtain some features for a machine learning algorithms. This amounts to finding a numerical description of the image which would help the ML algorithm detect the sign. Such a description can be anything. Think about how someone who never saw a STOP sign and does not know how to read would describe it. They would say something like "A red, flat plate, with 8 sides and some white stuff in the middle". Based on this description, someone might be able to tell it's a STOP sign. We want to do the same, but since computers are computers, we look for numerical features. And, with them, some algorithm could be trained to "learn" what features each sign has.
So, let's see what features does CtC_features obtains from the contours.
The first thing it does is to call findContours. This function takes a binary image and returns arrays of points representing the contours of the image. Basically, it takes the edges and puts them into arrays of points. With connectivity, so we basically know which points are connected. If we use the code from here for visualization, we can see what happens:
So, the array contours is a std::vector<std::vector<cv::Point>> and you have in each sub-array a continuous contour, here drawn with a different color.
Next, we compute the number of points (edge pixels), and do an average over their coordinates to find the centroid of the edge image. The centroid is the filled circle:
Then, we iterate over all points, and create a vector of std::pair<double, double>, recording for each point the distance from the centroid and the angle. The angle function is defined at the bottom of the file as
double angle(Point2f a, Point2f b) {
return atan((a.y - b.y) / (a.x - b.x));
}
It basically computes the angle of the line from a to b with respect to the x axis, using the arctangent function. I'll let you watch a video on arctangent, but tl;dr is that it gives you the angle from a ratio. In radians (a circle is 2 PI radians, half a circle is PI radians). The problem is that the function is periodic, with a period of PI. This means that there are 2 angles on the circle (the circle of all points at the same distance around the centroid) which give you the same value. So, we compute the ratio (the ratio is btw known as the tangent of the angle), apply the inverse function (arctangent) and we get an angle (corresponding to a point). But what if it's the other point? Well, we know that the other point is exactly with PI degrees offset (it is diametrically opposite), so we add PI if we detect that it's the other point.
The picture below also helps understand why there are 2 points:
The tangent of the angle is highlighted vertical distance,. But the angle on the other side of the diagonal line, which intersects the circle in the bottom left, also has the same tangent. The atan function gives the tangents only for angles on the left side of the center. Note that there are no 2 directions with the same tangent.
What the check does is to ask whether the point is on the right of the centroid. This is done in order to be able to add a half a circle (PI radians or 180 degrees) to correct for the result of atan.
Now, we know the distance (a simple formula) and we have found (and corrected) for the angle. We insert this pair into the vector feature_v, and we sort it. The sort function, called like that, sorts after the first element of the pair, so we sort after the angle, then after distance.
The interval variable:
int degree = 10;
double interval = double((double(degree) / double(360)) * 2 * 3.14159); //5 degrees interval
simply is value of degree, converted from degrees into radians. We need radians since the angles have been computed so far in radians, and degrees are more user friendly. Yep, the comment is wrong, the interval is 10 degrees, not 5.
The ang variable defined below it is -PI / 2 (a quarter of a circle):
double ang = - 1.57079;
Now, what it does is to divide the points around the centroid into bins, based on the angle. Each bin is 10 degrees wide. This is done by iterating over the points sorted after angle, all are accumulated until we get to the next bin. We are only interested in the largest distance of a point in each bin. The starting point should be small enough that all the direction (points) are captured.
In order to understand why it starts from -PI/2, we have to get back at the trigonometric function diagram above. What happens if the angle goes like this:
See how the highlighted vertical segment goes "downwards" on the y axis. This means that its length (and implicitly the tangent) is negative here. Also, the angle is considered to be negative (otherwise there would be 2 angles on the same side of the center with the same tangent). Now, we are interested in the range of angles we have. It's all the angles on the right side of the centroid, starting from the bottom at -PI/2 to the top at PI/2. A range of PI radians, or 180 degrees. This is also written in the documentation of atan:
If no errors occur, the arc tangent of arg (arctan(arg)) in the range [-PI/2, +PI/2] radians, is returned.
So, we simply split all the possible directions (360 degrees) into buckets of 10 degrees, and take the distance of the farthest point in each bin. Since the circle has 360 degrees, we'll get 360 / 10 = 36 bins. Then, these are normalized such that the greatest value is 1. This helps a bit with the machine learning algorithm.
How can we know if the point we selected belongs to the sign? We don't. Most computer vision make some assumptions regarding the image in order to simplify the problem. The idea of the algorithm is to determine the shape of the sign by recording the distance from the center to the edges. This makes the assumption that the centroid is roughly in the middle of the sign. Depending on the ML algorithm used, and on the training data, different levels of robustness can be obtained.
Also, it assumes that (some of) the edges can be reliably identified. See how in my image, the algorithm was not able to detect the upper left edge?
The good news is that this doesn't have to be perfect. ML algorithms know how to handle this variation (up to some extent) provided that they are appropriately trained. It doesn't have to be perfect, but it has to be good enough. In order to answer what good enough means, what are the actual limitations of the algorithm, some more testing needs to be done, as well as some understanding of the ML algorithm used. But this is also why ML is so popular in vision: it can handle a lot of variation quite well.
At the end, we basically get an array of 36 numbers, one for each of the 36 bins of 10 degrees, representing the maximum distance of a point in the bin. I assume this is because the developer of the algorithm wanted a way to capture the shape of the sign, by looking at distances from center in various directions. This assumes that no edges are detected in the background, and the sign looks something like:
The max distance is used to pick the border, and not the or other symbols on the sign.
It is not directly used here, but a possibly related reading is the Hough transform, which uses a similar particularization to detect straight lines in an image.

C++ check if 2d vector hit an obstacle

I'm building a server-side(!) for online game and I need to check if bullet hit a target.
Client sends me position and angle of bullet fired, I know all the enemies coordinates and sizes. How can I calculate if bullet hit an enemy after a bullet fired? Enemies have different sizes, bullet is 1px size.
For example, I have player shooting angle of 45 degrees from 0, 0 coordinates, and an enemy on 200, 200 coordinates with 10 width, 15 height. How do I calculate that bullet hit the enemy?
UPDATE: The game is 2d dhooter from the top, like Crimsonland. Projectiles have start speed which decreases slowly.
You should get a glance at the power of a point.
It will allow you to know the minimal distance between a line and a point.
So if the distance is lower than the width of the target, it's a hit !
The easiest way is to just check if the bullet is inside the rectangle of the enemy. If it is, dispose the bullet and the enemy.
basically:
while(game.is_on()){
for(enemy = enemyCollection.begin(); enemy != enemyCollection.end(); ++enemy){
if(enemy.contains(bullet)){
enemy.dead();
bullet.hit();
}
}
If you need to check whether line intersects rectangle, then apply orientation test based on cross product - if sign of cross product is the same for all rectangle vertices - line does not intersect it.
Line L0-L1, point P
Orientation = Cross(P - L0, L1 - L0)
(instead of L1-L0 components you can use Cos(Fi) and Sin(Fi) of shooting angle)
If you need to get intersection points, use some algorithm for line clipping - for example, Liang-Barsky one.
It's not quite as easy as it looks. To get a full solution, you need to extrude your objects along their paths of travel. Then you do object to object intersection tests.
That's difficult, as extrusion of an arbitrary shape by an arbitrary path is hard. So it's easier to cheat a little bit. Bullets can have no area, so they are just line segments. Make sure the step size is low enough for the line segment to be relatively short. Then make the ships rectangles, again with relatively short lines. Now it's lots of short line to line intersection tests. You can do these quickly with the planesweep algorithm. The nice thing about planesweep is that you can also extend it to curves or shapes, by returning possible intersections rather than actual intersections.
Once you have an intersection between a bullet and a ship's collision rectangle, you might need to run a timestep to check that a hit actually takes place rather than a narrow miss. You can also determine whether the hit was on front, left, right or back at this point.

Function to approach a number asymptotically

I have a map that I can zoom in and out of. Gridlines display the latitude and longitude.
Right now I zoom in by shrinking the borders by a specific amount.
Say top edge is lat 30n, bot edge is lat 28n, left edge is lon -40w, right edge is lon -38w.
So for one zoom in, the new edges are 29.5n, 28.5n, -39.5w,-38.5 respectively.
Zooming in enough times would eventually make the opposite edges equal each other and then flip.
So next zoom in for top and bot edge would be 29n, 29n and then next 28.5n,29.5n which flips the orientation.
I'm looking for a function or a way that I can continuously zoom in, but never have the edges equal each other or flip. In others words something where I can get the edges to continuously get closer and closer to each other, but never touch.
So I have an idea that I'll need some function like
lim x-> infinity of x/(x+1) - 1 + midpoint of the two edges
which basically means, as I zoom in I will approach the midpoint.
If this is valid, I don't know how to implement limits in C++.
This is only one equation too. I have two edges on each axis and so I'd need two equations to approach the midpoint from both sides at an equal rate.

Ballistic curve problem

Ok i know this is quite off-topic for programmers but still I need this for app, so here it is:
Ballistic curve (without wind or any other conditions) is specified by these 2 lines:
So, there is a problem that you got 3 unknown values: x,y and time t, but only 2 equations.
You can't really compute all 3 with just these values, I got:
velocity v
angle Alpha
origin coordinates
Thus, you have to decide which one to specify.
Now you have 2D tanks game, or anything like that, you know you have tank and using ballistic you have to shoot opponent down with setting angle and power.
I need to know when the bullet hit the ground, it can be on-air as it fly, or precomputed.
There comes up my problem. Which way to use? Pre-compute or check for hitting the ground in each step.
If I would like to pre-compute, I would need to know height of terrain, which, logically would have to be constant as I don't know in which x coord. If I would know the X, it would mean that just in front of my turret is wall. So only way to get to result, when I hit the ground, would be with checking in intervals of time for hitting the ground. This is also good because the terrain doesn't have top be static yay! But isn't that too great overhead which could be made much simpler? Have you encountered with such problem/solution?
Thanks in advance, btw the terrain can be flat, using lines or NURBS so I please for general solution, not specific as in which height you shoot in that will be impact.
You can compute the path of the projectile y(x) by solving one equation for t and substituting into the other. You get
Then finding the landing point is a matter of computing the intersections between that function and the function that defines the height of the terrain. One intersection will be the launch point and the other will be the landing point. (If your terrain is very steep and hilly, there could be more than 2 intersections, in which case you take the first one with x greater than the launch point.) You can use any of various root-finding algorithms to actually compute the intersection; check the documentation of whatever mathematical or game-physical libraries you have to see if they provide a method to do this.
David Zaslavsky did a good job of answering your question about solving for the equation, but if your ultimate goal is simple ballistics simluation, I suggest you instead use vector decomposition.
By utilizing vector decomposition, you can derive the x- and y-compenent vectors of your projectile. You can then apply acceleration to each component to account for gravity, wind, etc. Then you can update the projectile's (x,y) position each interval as a function of time.
For example:
double Speed = 100.0; // Speed rather than velocity, as it is only the magnitude
double Angle = 30.0; // Initial angle of 30ยบ
doulbe Position[2] = {0.0,0.0}; // Set the origin to (0,0)
double xvelocity = Speed * Cos(Angle);
double yvelocity = Speed * Sin(Angle);
Then if you can impliment a simple Update function as follows:
void Update(double Time)
{
yvelocity = -9.8 * Time; // Apply gravity
Position[0] *= (xvelocity * Time); // update x position
Position[1] *= (yvelocity * time); // update y position
CheckCollisions(); // check for collisions
}
Of course this is a very basic example, but you can build on it from here.
Fortunately, this is pretty simple kinematics.
Those equations are parametric: For any given time t, they give you the x and y coordinates for that time. All you need to do is plug in the starting velocity v and angle a.
If you're working on level ground, the time for your projectile to come back down is simply 2sin(a)v/g, i.e. the vertical component of your velocity divided by the downward acceleration due to gravity. The 2 is because it takes that amount of time for the speed to drop to 0, then the same time again for it to accelerate back down. Once you know the time you can solve for x.
If your terrain is not flat, you have some additional fun. Something you could try is work out the time for hitting the ground at the same height, and then correct for the extra vertical distance. This will also change your horizontal distance which might again affect your height... but two or three adjustments and the error will be too small for humans to notice :)
I'm not sure you're going about this is right way. The main equation you want is s = si + vi*dt + .5*adtdt. This is a simple equation of one dimension, but it generalizes to vectors cleanly.
Effectively, si is your initial position and vi is your initial velocity and a is acceleration due to gravity.
To make this work, build a vector for perfect horizontal muzzle velocity and project it on the launch angle. That's your vi. Si will be the tip of the barrel. From there it's vector summing and scaling.
Continuous functions do not work well for computers, because computers are implicitly discrete: the floating/double numbers are discrete, the timer is discrete, the game grid is discrete (even if it uses 'doubles').
So just discretize the equation the way Justin Holdsclaw suggested. Have velocity and accelerations vectors in each direction (in your case X and Y; you could also add Z). Update all vectors, and the object's position in space, at every tick.
Note that the result won't be 'exact'. The smaller your 'delta' values (grid coarseness), the closer you'll be to the 'exact' curve. To know precisely how close - if you're interested, find a book on numerical analysis and read the first few chapters. For practical purposes you can just experiment a bit.

How do I bounce a point off of a line?

I'm working on writing a Pong game and I've run across a problem.
I'm trying to figure out how to bounce a point off of a line.
The best method I can figure out to do this with is
Calculate the current and future position of the Ball.
Line Segment: {Ball.location, Ball.location + Ball.direction} (Ball.location and Ball.direction use a custom vector/coordinate class)
Calculate if the generated line segment intersects with any of the walls or paddles.
??? Don't know how to do this yet (Will ask in a separate question)
At the first intersection found
Bounce the ball off of the line
Create a triangle formed with
a = Ball's current position
b = Intersection point of the line.
c = Closest point to the Ball's current position on the line.
Find the angle that the ball hits the line
angle = cos(distance(b, c) / distance(a, b))
Find the angle to rotate the ball's direction
(90 - angle)*2
Rotate Ball's direction and move it to it's new position
ignoring distance traveled to hit the line for now, doesn't need to be exactly on the line
Else if there is no intersection
Move the ball to it's new position.
Is this an acceptable method or am I missing something?
You just need to check if the center of the ball is within its radius of the paddle to tell whether or not its time to bounce. There was an older question asked that has several answers on calculating bounce angle.
If you want the authentic Pong feel, then computing the new vector is much easier than doing real reflections. Pong just reverses the sign of either dx or dy. If the ball hits a horizontal barrier, then negate dy. Vertical, then negate dx.
In your game loop, calculate the new ball position as if there were no obsticals.
Then check to see if the new position intersects with or is PAST the obstical edge.
If either condition is met, then calculate a new ball position by bouncing it off the obstical.
A method that calculates a point given a starting point, angle, and distance would come in handy:
Public Function TranslatePoint(ByVal tStartPoint As Point, _
ByVal tAngle as Decimal, ByVal tDistance As Decimal) As Point
Here is what I would do:
1) assume your pong sides are at the lines x=a and x=b
2) let your balls position be (x0, y0) and traveling on the line Ax+By=C
3) from this you can calculate easily (x1, y1) the point where that line intersects
the wall
4) you can get the equation of the line after the bounce by knowing that
(x0, y1+y0) is the reflection after the bounce. (The ball is y1-y0 below the
intersection point and hence will be y1+y0 above the intersection point.)
5) given the 2 equations you can plot your points (assuming you know the velocity).
You may be interested in the N Tutorials, which discuss collision detection and response (including bounce and friction) used in the game "N".
The tutorials may go deeper than you particularly need, but they're well-written and have interactive examples -- and simple bounce is one of the first topics.
Bouncing is a problem from the physics domain, not the graphics domain. Therefore OpenGL offers no real support for it. If you look at the hardware, you'll notice that there have been seperate physics cards similar to videocards, although the most recent trends are to integrate them.