C++ recognize shape from points - c++

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.

Related

C++ Monster Roaming Functionality

I have a working monster system that follows players around by moving a certain distance towards the players 2D (X, Y) location.
However, I now want to make it so these monsters roam around at random time intervals for a short distance. Say we have a monster that can travel anywhere from 200-300 cm/sec.
I need to know how to accurately determine the monsters destination location (X, Y). Currently I simply pick a random number between 200-300 and then add those values to the monsters current X & Y value. Although doing this will sometimes exceed the desired distance traveled.
My question is, how can I pick a location on an X, Y grid that is a certain distance away from our current location.
This is the moving code I have right now...
// Determines if position is changed via addition or subtraction.
const int positive_or_negative = RandomValueInRange_New(0, 1);
// Determines how much to move in each direction
const int x = RandomValueInRange(200, 300);
const int y = RandomValueInRange(200, 300);
if (positive_or_negative == 1)
{
location.Move(x, y);
}
else
{
location.Move(-x, -y);
}
This sounds like a job for polar co-ordinates. You want to pick a random point on a circle of a given (random, within a range) radius, then add that point to your monster's current location:
// pick a random angle, in radians, between 0 and 2*pi
const double angle = ((double) RandomValueInRange(0, 628318)) / 100000.0;
// pick a random distance between min and max distance
const double radius = RandomValueInRange(200, 300);
// Convert polar co-ordinates to rectilinear co-ordinate deltas
const double dX = cos(angle)*radius;
const double dY = sin(angle)*radius;
// Add the rectilinear co-ordinates to your monster's position
location.Move(dX, dY);
There are at least two approaches you can use. The approach you use will affect the distribution of destination coordinates.
The first, as stated by Jeremy, is the use polar coordinates. r = random(200, 300); ang = random(0, 360). This with result in a higher density of coordinates at r=200 than at r=300 due to the fact that a “ring” at the largest radius will have 50% more area than the ring at the smallest radius, due to its larger circumstance.
A second approach would be to generate two random values x = random(-300, 300); y = random(-300, 300) repeatedly until a random pair passes the constraint of a distance between 200 & 300.
int dX, dY, d2;
do {
dX = RandomValueInRange(-300, 300);
dY = RandomValueInRange(-300, 300);
d2 = dX*dX + dY*dY;
} while ( d2 < 200*200 || d2 > 300*300);
location.Move(dX, dY);
This produces an even distribution in space, but at the cost of repeated random number generation. Only 43.6% of random pairs will fall in the desired area, so the loop will typically execute 2 to 3 times before generating an acceptable pair.
While this distribution is even in x-y space, it is not even in terms of distance. A monster will on average move more than 250cm, since there is more area in the ring between 250cm to 300cm than in the ring from 200cm to 250cm.
A more realistic move distribution would bias the next move based on the previous move. For instance, doing an about-face is probably a low probability event. Unless the monster was actively guarding a given location, in which case it might be the highest likelihood action!
Without more detail on exactly how the monster should behave, and if you aren’t overly concerned with the distribution, the simplest generation is going to be the polar coordinate route, which gives a legal position from exactly 2 random number generations and no looping.

In c++, how do I create point locations arbitrarily?

I'm trying to program a simulation. Originally I'd randomly create points like so...
for (int c = 0; c < number; c++){
for(int d = 0; d < 3; d++){
coordinate[c][d] = randomrange(low, high);
}
}
Where randomrange() is an arbitrary range randomizer, number is the amount of created points, and d represents the x,y,z coordinate. It works, however I want to take things further. How would I define a known shape? Say I want 80 points on a circle's circumference, or 500 that form the edges of a cube. I can explain well on paper, but have a problem describing the process as coding. This doesn't pertain to the question, but I end up taking the points to txt file and then use matlab, scatter3 to plot the points. Creating the "shape" points is my issue.
Both a circle and a cube edges set are 1-dimensional sets, so you can represent them as real intervals. For a circle it's straightforward: use an interval (0, 2pi) and transform a random value phi from the interval into a point:
xcentre + R cos(phi), ycentre + R sin(phi)
For a cube you have 12 segments, so use interval (0, 12) and split a random number from the interval into an integer part and a fraction. Then use the integer as an edge number and the fraction as a position inside the edge.
Easy variant:
First think of the min/max x/y values (separately; to reduce the faulty values for the step below), generate some coordinates matching this range, and then check if it fulfills eg. a^2+b^2=r^2 (circle)
If not, try again.
Better, but only possible for certain shapes:
Generate a radius between (0-max) and an angle (0-360)
(or just an angle if it should be on the circle border)
and use some math (sin/cos...) to transform it into x and y.
http://en.wikipedia.org/wiki/Polar_coordinate_system

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).)

C++ Detect collision between two points and bouncing off the normal if there is a collision

I have a ground set up of various points, some of which are flat and others are at an angle, I'm trying to check if there is a collision between the angled points (non-axis aligned).
I have a vector array consisting of two floats at each point - This is each of the points of the ground.
Here's an image representation of what the ground looks like.
http://i.imgur.com/cgEMqUv.png?1?4597
At the moment I want to check collisions between points 1 and 2 and then go onto the others.
I shall use points 1 and 2 as an example.
g1x = 150; g2x = 980;
g2x = 500; g2y = 780;
The dxdy of this is dx = 350 and dy = -200
The normal x of this is dy and the normal y is -dx
nx = -200;
ny = -350;
normalized it is the length between points 1 and 2 which is 403.11
nx/normalized = -0.496
ny/normalized = -0.868
//get position of object - Don't know if its supposed to be velocity or not
float vix = object->getPosition().x;
float viy = object->getPosition().y;
//calculate dot product - unsure if vix/viy are supposed to be minused
float dot = ((-vix * nrmx) + (-viy * nrmy)) * nrmx; //= -131.692
Is this information correct to calculate the normal and dot product between the two points.
How can I check if there is a collision with this line and then reflect according to the normal.
Thanks :) any and all changes are welcome.
Say you have a particle at position x travelling at velocity v and a boundary defined by the line between a and b.
We can find how far along the boundary (as a fraction) the particle collides by projecting c-a onto b-a and dividing by the length ||b-a||. That is,
u = ((c-a).((b-a)/||b-a||))/||b-a|| == (c-a).(b-a) / ||b-a||2.
If u > 1 then the particle travels past the boundary on the b side, if u < 0 then the particle travels past the boundary on the a side. The point of collision would be
c = a + u b.
The time to collision could be found by solving
x + t v = a + s (b-a)
for t. The reflection matrix can be found here. But it will need to be rotated by 90 deg (or pi/2) so that you're reflecting orthogonal to the line, not across it.
In terms of multiple boundaries, calculate the time to collision for each of them, sort by that time (discarding negative times) and check for collisions through the list. Once you've found the one that you will collide with then you can move your particle to the point of collision, reflect it's velocity, change the delta t and redo the whole thing again (ignoring the one you just collided with) as you may collide with more than one boundary in a corner case (get it? It's a maths pun).
Linear algebra can be fun, and you can do so much more with it, getting to grips with linear algebra allows you to do some powerful things. Good luck!

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.