recalculate ray tracing/casting costs when changing size of rectangle - c++

I have an array of "rays" which I need to measure the costs in relation to the rectangular boxes below. The outer red box is always 1m larger than the dark green box and light green box is 10cm smaller than the dark green box. If a ray
passes through the dark green box I would assign cost c
ands on the dark green box I would assign cost d
lands on the red area i would assign
cost e
does not intersect the dark green box and not land in red box, cost f
and d < f < c < e
I currently have the following data structures and functions to calculate the cost. I am required to calculate the cost for the given rectangles (represented by 4 xy coordinates), but at the same time, find the approximate/local optimal length/width of the dark green rectangle(i.e shrink or grow the dimension by holding the closest corner of the rectangle fixed) such that the cost is minimum.
A concrete example is the screenshot below. The smaller rectangle corresponds to the dark green box in the figure. Green lines are the rays with cost d, yellow lines cost f and the turquoise lines are the ones with cost c. If I fix the top left hand corner of the inner rectangle and reduce the width, I can reduce the turqoise rays from cost c to f.
My question is, I am stuck at how should I alter my code or change my data structure, such that I can find the best dimensions by only recomputing the affected rays (i.e without looping through all the rays again).
struct VRay{
float range, x, y;
enum RayType{ PASSTHROUGH, FREE, SURFACE, OCCLUDED, UNIFORM};
RayType r;
};
struct VScan{
VRay rays[401];
int closestIdx;
int firstIdx;
int lastIdx;
} vscan;
The function to calculate the costs:
for (int i = 0; i < 401; i++){
VRay& r = vscan.rays[i];
Vector2f cray(r.y, -r.x);
bool ppBound = false;
bool ppSurf = false;
Vector2f vertex = outBox.row(0);
Vector2f vertexSurf = surface.row(0);
float init = cray.dot(vertex);
float initSurf = cray.dot(vertexSurf);
//this part finds whether ray intersects rectangle or not
for (int j = 1; j < 4; j++){
Vector2f v2 = outBox.row(j);
Vector2f vSurf = surface.row(j);
float i2 = cray.dot(v2);
float iSurf = cray.dot(vSurf);
if (i2 * init < 0){
ppBound = true;
}
if (iSurf * initSurf < 0){
ppSurf = true;
}
}
//ray does not intersect all rectangles
if (!ppBound){
z += log(1/100.);
continue;
}
//ray is inside red box
if (inPolygon(outBox, r)){
//ray inside dark green box
if (inPolygon(surface, r)){
//ray inside light green box
if (inPolygon(inBox,r))
c = passTCost;
else
c = surfaceCost;
}
else{
c = freeCost; //free space
}
}
else if (ppSurf){
c = passTCost; //before all boxes
}
else { //ray does not intersect dark green box
z += log(1/100.);
continue;
}
z += -(c * c)/(2 * deviation * deviation);
}

If I understand you right, you want vary the size of the dark green rectangle such that it retains a common center with the light green rectangle the edges of both remain parallel. The dark green rectangle will never leave the red one at any point and will never be smaller than the light green one. Red and light green rectangle remain constant. You only want to recalculate those rays that might change their cost if you vary the dark green rectangle (DGR from now on...).
So my proposition is as follows:
Have another std::vector<VRay*> being empty at the start, and a second sum variable. In a first run, calculate your costs as you do. Additionally, for each ray, decide if it might change at all when varying the DGR.
If it could, add a pointer to it to the vector above, otherwise, add its current cost to the second sum. From now on, you only have to re-calculate those rays in the pointer vector and add the pre-calculated sum of the other ones to this new sum.
How to decide, if a ray might change cost? Well, those not crossing the red rectangle will not, of course. Those ending in the light green rectangle won't either, as well as those crossing both the light green and the red rectangle. So the relevant rays are those ending within the red rectangle, but not within the light green one and additionally those entirely crossing the red one but not intersecting the light green one.
A further optimisation can be gatherd if you consider the maximum DGR (if it is not necessarily parallel to the red one): Those lines not intersecting this maximum rectangle or ending in front of it won't ever change either.

Am I correct that a ray can never land in the light green box? i.e. rays are stopped when they reach the light green area? Are there any rules determining if a ray lands on the red area, on the dark green area, or passes through both of them?
If these rules are independent of the size of the car, but only depend on the relative position of the "end point" of the ray, e.g. if rays to the middle of the front of the car surface do always land on the free space around the car, then the relation of the quantity of rays with cost d, c, or e are independent of the size of the car. The quantity of rays with cost f (marked yellow) is just the rest of the rays, i.e. rays that do not have cost d, c, or e.
This means that in a first step, calculate the optimal (minimal) sum of costs, given the constant ratio of costs for d/c/e and knowing that the remainder of the rays have costs f.
Example: you have 5% of rays with cost c (turquoise lines), 10% of rays with cost e (red lines), and 40% of rays with cost d (green lines), and 45% of rays with cost f (yellow lines). Therefore for each ray with cost c you have two rays with cost e and eight rays with cost d. All the remaining rays have cost f.
-> let x be the number of rays with cost c, then total costs are: 1*c*x + 2*e*x + 8*d*x + (totalNumberOfRays - (1+2+8)*x) * f
Now find the minimum of this function (which is easy because it is a linear function, but probably you have some constraints on the size of your car), and use the resulting x to calculate the size of your car: if you had in the beginning e.g. 10 rays with cost c, and the resulting x is 5, you have to find the car size which produces only 5 rays of costs c, i.e. the car width and length each should be multiplied by 0.5.
Now, the only thing I hope, is that my assumptions were right :-)
(Other options that I thought of, in case my assumptions are wrong, are grouping the rays together in a certain way, and only do the calculations per group)

Related

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.

Algorithm for finding number of squares in a given circle

Here is my drawing: CLICK
I need to write a program, that will find the number of squares(1x1), that we can draw into a circle of given radius.The squares can only by drawn fully and placed like lego blocks- one on another. In some cases, vertexes of squares can lie on the circle.
Examples: for 1- it makes 0, for 2- it gives four, for 3- 16 squares, for 4-32, for 5-52.
I have written something, but it doesn't work fine for 5+ (I mean- radius bigger than 5). Here it goes: CLICK. In my code- r is radius of the circle, sum is the sum of all squares and height is the height of triangles I try to "draw" into the circle (using Pythagorean theorem).
Now- any help? Is my algorithm even correct? Should I change something?
There is Gauss's Circle Problem that gives a formula to count integer points inside the circle of given radius. You may use this logic to count squares that lie in the circle.
N = 4 * Sum[i=1..R] (Floor(Sqrt((R^2-i^2)))
example:
R = 3
i=1 n1 = Floor(Sqrt(9-1))~Floor(2.8)=2
i=2 n2 = Floor(Sqrt(9-4))~Floor(2.2)=2
i=3 n2 = Floor(Sqrt(9-9))=0
N=4*(n1+n2+n3)=16
First off - circle with a radius of 5 fits 60 1x1 squares, not 52. My bet would be someone didn't count the points {[3,4],[3,-4],[4,3],[4,-3],[-4,3],[-4,-3],[-3,4],[-3,-4]} when drawing that on paper and counting by hand, being unsure whether they are right on the circle or just outside of it. They are exactly on the circle.
Second - MBo's answer brought me here - I sometimes search StackOverflow for Gauss Circle Problem to see if someone suggested some new, fun algorithm.
Third - here's the code:
int allSquares=0,
squaredRadius=radius*radius,
sideOfQuarterOfInscribedSquare=(int)(long)(radius/sqrt(2));
for(int x=sideOfQuarterOfInscribedSquare+1;
x<radius;
x++){
allSquares+=(long)sqrt(squaredRadius-x*x);
}
allSquares= allSquares*8+4*sideOfQuarterOfInscribedSquare*sideOfQuarterOfInscribedSquare;
return allSquares;
What it does is just count the squares inside one-eighth of the circle, outside an inscribed square. Sorry for my hipster formatting and overly verbose variable names.

Number of Sides Required to draw a circle in OpenGL

Does anyone know some algorithm to calculate the number of sides required to approximate a circle using polygon, if radius, r of the circle and maximum departure of the polygon from circularity, D is given? I really need to find the number of sides as I need to draw the approximated circle in OpenGL.
Also, we have the resolution of the screen in NDC coordinates per pixel given by P and solving D = P/2, we could guarantee that our circle is within half-pixel of accuracy.
What you're describing here is effectively a quality factor, which often goes hand-in-hand with error estimates.
A common way we handle this is to calculate the error for a a small portion of the circumference of the circle. The most trivial is to determine the difference in arc length of a slice of the circle, compared to a line segment joining the same two points on the circumference. You could use more effective measures, like difference in area, radius, etc, but this method should be adequate.
Think of an octagon, circumscribed with a perfect circle. In this case, the error is the difference in length of the line between two adjacent points on the octagon, and the arc length of the circle joining those two points.
The arc length is easy enough to calculate: PI * r * theta, where r is your radius, and theta is the angle, in radians, between the two points, assuming you draw lines from each of these points to the center of the circle/polygon. For a closed polygon with n sides, the angle is just (2*PI/n) radians. Let the arc length corresponding to this value of n be equal to A, ie A=2*PI*r/n.
The line length between the two points is easily calculated. Just divide your circle into n isosceles triangles, and each of those into two right-triangles. You know the angle in each right triangle is theta/2 = (2*PI/n)/2 = (PI/n), and the hypotenuse is r. So, you get your equation of sin(PI/n)=x/r, where x is half the length of the line segment joining two adjacent points on your circumscribed polygon. Let this value be B (ie: B=2x, so B=2*r*sin(PI/n)).
Now, just calculate the relative error, E = |A-B| / A (ie: |TrueValue-ApproxValue|/|TrueValue|), and you get a nice little percentage, represented in decimal, of your error vector. You can use the above equations to set a constraint on E (ie: it cannot be greater than some value, say, 1.05), in order for it to "look good".
So, you could write a function that calculates A, B, and E from the above equations, and loop through values of n, and have it stop looping when the calculated value of E is less than your threshold.
I would say that you need to set the number of sides depending on two variables the radius and the zoom (if you allow zoom)
A circle or radius 20 pixels can look ok with 32 to 56 sides, but if you use the same number of sided for a radios of 200 pixels that number of sides will not be enough
numberOfSides = radius * 3
If you allow zoom in and out you will need to do something like this
numberOfSides = radiusOfPaintedCircle * 3
When you zoom in radiusOfPaintedCircle will be bigger that the "property" of the circle being drawn
I've got an algorithm to draw a circle using fixed function opengl, maybe it'll help?
It's hard to know what you mean when you say you want to "approximate a circle using polygon"
You'll notice in my algorithm below that I don't calculate the number of lines needed to draw the circle, I just iterate between 0 .. 2Pi, stepping the angle by 0.1 each time, drawing a line with glVertex2f to that point on the circle, from the previous point.
void Circle::Render()
{
glLoadIdentity();
glPushMatrix();
glBegin(GL_LINES);
glColor3f(_vColour._x, _vColour._y, _vColour._z);
glVertex3f(_State._position._x, _State._position._y, 0);
glVertex3f(
(_State._position._x + (sinf(_State._angle)*_rRadius)),
(_State._position._y + (cosf(_State._angle)*_rRadius)),
0
);
glEnd();
glTranslatef(_State._position._x, _State._position._y, 0);
glBegin(GL_LINE_LOOP);
glColor3f(_vColour._x, _vColour._y, _vColour._z);
for(float angle = 0.0f; angle < g_k2Pi; angle += 0.1f)
glVertex2f(sinf(angle)*_rRadius, cosf(angle)*_rRadius);
glEnd();
glPopMatrix();
}

rectangle collision

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