I'm trying to calculate the angles of two points in 2D space. It works with the following:
double angle;
x = player->x - x;
z = player->z - y;
angle = atan2 (x, y);
angle *= (180.0 / M_PI);
if(angle < 0) angle += 360;
if(angle >= 360) angle -= 360;
return angle;
However I want to use a table for better results:
x = player->x - x;
z = player->y - y;
return atanTable[x+32][y+32];
With init:
int xp = -32;
int yp = -32;
for (int x = 0; x < 64; x++, xp++)
for (int y = 0; y < 64; y++, yp++){
double angle;
angle = atan2 (xp, yp);
angle *= (180.0 / M_PI);
if(angle < 0) angle += 360;
if(angle >= 360) angle -= 360;
atanTable[x][y] = angle;
}
The angle is only calculated for values -32 to 32 for x and y.
The table is not properly produced however. I get values of only around 359 and 0, while I should get a range of 0 to 360 degrees.
Am I misusing atan2 somehow?
You need to reset yp within the first loop, not before it.
int xp = -32;
for (int x = 0; x < 64; x++, xp++)
{
int yp = -32; // Note, needs to be reset each time x changes.
for (int y = 0; y < 64; y++, yp++)
{
Nit: atan2() returns an angle in [-pi,pi] always. Your second if statement is redundant. It's also likely a bad design: very often you want to test later on for angles in [pi,2pi], which can be done with a simple <0 for the default range. Basically, atan2() is your friend, the reason the function exists is to save you from the hassle of doing modular math on angles.
Related
I found the following code in this page to compute a double integral. Whenever I run it with all variables being declared as float, it gives the right result for the example integral, which is 3.91905. However, if I just change all float variables to double, the program gives a completely wrong result (2.461486) for this integral.
Could you help me undestanding why this happens? I expected to have a better result using double precision, but that's evidently not the case here.
Below is the code pasted from the aforementioned website.
// C++ program to calculate
// double integral value
#include <bits/stdc++.h>
using namespace std;
// Change the function according to your need
float givenFunction(float x, float y)
{
return pow(pow(x, 4) + pow(y, 5), 0.5);
}
// Function to find the double integral value
float doubleIntegral(float h, float k,
float lx, float ux,
float ly, float uy)
{
int nx, ny;
// z stores the table
// ax[] stores the integral wrt y
// for all x points considered
float z[50][50], ax[50], answer;
// Calculating the number of points
// in x and y integral
nx = (ux - lx) / h + 1;
ny = (uy - ly) / k + 1;
// Calculating the values of the table
for (int i = 0; i < nx; ++i) {
for (int j = 0; j < ny; ++j) {
z[i][j] = givenFunction(lx + i * h,
ly + j * k);
}
}
// Calculating the integral value
// wrt y at each point for x
for (int i = 0; i < nx; ++i) {
ax[i] = 0;
for (int j = 0; j < ny; ++j) {
if (j == 0 || j == ny - 1)
ax[i] += z[i][j];
else if (j % 2 == 0)
ax[i] += 2 * z[i][j];
else
ax[i] += 4 * z[i][j];
}
ax[i] *= (k / 3);
}
answer = 0;
// Calculating the final integral value
// using the integral obtained in the above step
for (int i = 0; i < nx; ++i) {
if (i == 0 || i == nx - 1)
answer += ax[i];
else if (i % 2 == 0)
answer += 2 * ax[i];
else
answer += 4 * ax[i];
}
answer *= (h / 3);
return answer;
}
// Driver Code
int main()
{
// lx and ux are upper and lower limit of x integral
// ly and uy are upper and lower limit of y integral
// h is the step size for integration wrt x
// k is the step size for integration wrt y
float h, k, lx, ux, ly, uy;
lx = 2.3, ux = 2.5, ly = 3.7,
uy = 4.3, h = 0.1, k = 0.15;
printf("%f", doubleIntegral(h, k, lx, ux, ly, uy));
return 0;
}
Thanks in advance for your help!
Due to numeric imprecisions, this line:
ny = (uy - ly) / k + 1; // 'ny' is an int.
Evaluates to 5 when the types of uy, ly and k are float. When the type is double, it yields 4.
You may use std::round((uy - ly) / k) or a different formula (I haven't checked the mathematical correctness of the whole program).
I've been working on drawing the Julia set using a distance estimator instead of the normalized iteration count. I usually use the code below and play around with the iteration count until I get a decent enough picture
double Mandelbrot::getJulia(double x, double y)
{
complex<double> z(x, y);
complex<double> c(-0.7269, 0.1889);
double iterations = 0;
while (iterations < MAX)
{
z = z * z + c;
if (abs(z) > 2) {
return iterations + 1.0 - log(log2(abs(z)));
break;
}
iterations++;
}
return double(MAX);
}
I then call this for each point and draw to a bitmap;
ZoomTool zt(WIDTH, HEIGHT);
zt.add(Zoom(WIDTH / 2, HEIGHT / 2, 4.0 / WIDTH));
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
pair<double, double> coords = zt.zoomIn(x, y);
double iterations = Mandelbrot::getJulia(coords.first,
coords.second);
double ratio = iterations / Mandelbrot::MAX;
double h = 0;
double s= 0;
double v = 0;
if (ratio != 1)
{
h = 360.0*ratio;
s = 1.0;
v = 1.0;
}
HSV hsv(h, s, v);
RGB rgb(0, 0, 0);
rgb = toRGB(hsv);
bitmap.setPixel(x, y, rgb._r, rgb._g, rgb._b);
}
}
At 600 iterations, I get this;
Which is not great but better than what I get with the distance estimator which I am attempting to now use. I've implemented the distance estimator as below;
double Mandelbrot::getJulia(double x, double y)
{
complex<double> z(x,y);
complex<double> c(-0.7269, 0.1889);
complex<double> dz = 0;
double iterations = 0;
while (iterations < MAX)
{
dz = 2.0 * dz * z + 1.0;
z = z * z + c;
if (abs(z) > 2)
{
return abs(z) * log(abs(z)) / abs(dz);
}
iterations++;
}
return Mandelbrot::MAX;
}
At 600 iterations, I get the following image
Am I not normalizing the colors correctly? I'm guessing this is happening because I'm normalizing to 360.0 and doing a conversion from HSV to RGB. Since the distances are quite small, I get a very condensed distribution of colors.
I'm making a 2d game and I'm trying to stop enemy sprites moving over each other. I've implemented the following method that is supposed to check that enemies are not overlapping, then move one of them back in the direction they came. However this method seems to crash my game as only one enemy is ever rendered.
This is my check method:
size = enemys.size();
for (int i = 0; i<size; i++){
double x = enemys[i].getEnemyX();
double y = enemys[i].getEnemyY();
for (int s = 1; s<size; s++){
double enemyX = enemys[s].getEnemyX();
double enemyY = enemys[s].getEnemyY();
if (x >= enemyX-5.0 && x <= enemyX+5.0 && y >= enemyY-5.0 && y <= enemyY + 5.0){
double xDir = x - enemyX;
double yDir = y - enemyY;
double hyp = sqrt(xDir*xDir + yDir*yDir);
xDir /= hyp;
yDir /= hyp;
x -= xDir * 5;
y -= yDir * 5;
enemys[s].setEnemyCoord(x,y);
}
}
}*
Your code will end up checking each enemy against itself.
Make your inner loop start from s=i+1
I try to fill a grid with points and only keep the points inside a imaginary circle.
First i did this with:
createColorDetectionPoints(int xSteps, int ySteps)
But for me it's a lot easier to set it with a target in mind:
void ofxDTangibleFinder::createColorDetectionPoints(int nTargetPoints)
The target doesn't have to be too precise. But at the moment when i want 1000 points for example i get 2289 points.
I think my logic is wrong but i can't figure it out.
The idea is to get the right amount of xSteps and ySteps.
Can someone help?
void ofxDTangibleFinder::createColorDetectionPoints(int nTargetPoints) {
colorDetectionVecs.clear();
// xSteps and ySteps needs to be calculated
// the ratio between a rect and ellipse is
// 0.7853982
int xSteps = sqrt(nTargetPoints);
xSteps *= 1.7853982; // make it bigger in proportion to the ratio
int ySteps = xSteps;
float centerX = (float)xSteps/2;
float centerY = (float)ySteps/2;
float fX, fY, d;
float maxDistSquared = 0.5*0.5;
for (int y = 0; y < ySteps; y++) {
for (int x = 0; x < xSteps; x++) {
fX = x;
fY = y;
// normalize
fX /= xSteps-1;
fY /= ySteps-1;
d = ofDistSquared(fX, fY, 0.5, 0.5);
if(d <= maxDistSquared) {
colorDetectionVecs.push_back(ofVec2f(fX, fY));
}
}
}
// for(int i = 0; i < colorDetectionVecs.size(); i++) {
// printf("ellipse(%f, %f, 1, 1);\n", colorDetectionVecs[i].x*100, colorDetectionVecs[i].y*100);
// }
printf("colorDetectionVecs: %lu\n", colorDetectionVecs.size());
}
I am working on a college compsci project and I would like some help with a field of view algorithm. I works mostly, but in some situations the algorithm sees through walls and hilights walls the player should not be able to see.
void cMap::los(int x0, int y0, int radius)
{ //Does line of sight from any particular tile
for(int x = 0; x < m_Height; x++) {
for(int y = 0; y < m_Width; y++) {
getTile(x,y)->setVisible(false);
}
}
double xdif = 0;
double ydif = 0;
bool visible = false;
float dist = 0;
for (int x = MAX(x0 - radius,0); x < MIN(x0 + radius, m_Height); x++) { //Loops through x values within view radius
for (int y = MAX(y0 - radius,0); y < MIN(y0 + radius, m_Width); y++) { //Loops through y values within view radius
xdif = pow( (double) x - x0, 2);
ydif = pow( (double) y - y0, 2);
dist = (float) sqrt(xdif + ydif); //Gets the distance between the two points
if (dist <= radius) { //If the tile is within view distance,
visible = line(x0, y0, x, y); //check if it can be seen.
if (visible) { //If it can be seen,
getTile(x,y)->setVisible(true); //Mark that tile as viewable
}
}
}
}
}
bool cMap::line(int x0,int y0,int x1,int y1)
{
bool steep = abs(y1-y0) > abs(x1-x0);
if (steep) {
swap(x0, y0);
swap(x1, y1);
}
if (x0 > x1) {
swap(x0,x1);
swap(y0,y1);
}
int deltax = x1-x0;
int deltay = abs(y1-y0);
int error = deltax/2;
int ystep;
int y = y0;
if (y0 < y1)
ystep = 1;
else
ystep = -1;
for (int x = x0; x < x1; x++) {
if ( steep && getTile(y,x)->isBlocked()) {
getTile(y,x)->setVisible(true);
getTile(y,x)->setDiscovered(true);
return false;
} else if (!steep && getTile(x,y)->isBlocked()) {
getTile(x,y)->setVisible(true);
getTile(x,y)->setDiscovered(true);
return false;
}
error -= deltay;
if (error < 0) {
y = y + ystep;
error = error + deltax;
}
}
return true;
}
If anyone could help me make the first blocked tiles visible but stops the rest, I would appreciate it.
thanks,
Manderin87
You seem to be attempting to create a raycasting algorithm. I assume you have knowledge of how Bresenham's lines work, so I'll cut to the chase.
Instead of checking the visibility of each cell in the potential field of view, you only need to launch Bresenham lines from the FOV centre towards each cell at the very perimetre of the potential FOV area (the square you loop through). At each step of the Bresenham line, you check the cell status. The pseudocode for each ray would go like this:
while (current_cell != destination) {
current_cell.visible = true;
if (current_cell.opaque) break;
else current_cell = current_cell.next();
}
Please remember that raycasting produces tons of artifacts and you might also need postprocessing after you have calculated your field of view.
Some useful resources:
ray casting on Roguebasin
ray casting FOV implementation in libtcod (in C, you can dig through the repository for a C++ wrapper to it)
a FOV study