Stop spray and stay in its position - c++

// #include loads up library files, the order can matter
// generally load glut.h last
#include <stdio.h> // this library is for standard input and output
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include "glut.h"// this library is for glut the OpenGL Utility Toolkit
//this defines a constant for the array size
#define SPRAYSIZE 500
// the properties of a spray particle are defined in a struct
struct sprayParticle {
float x = 0; // current position x
float y = 0; // current position y
float startx = 0; // birth position x
float starty = 0; // birth position y
int startTime; // a birthtime in frames when it will be born
int startRange = 100; // the maximum time at which a birth can happen
bool started = false; // tracks whether the particle has benn born or not
float speed = 0.1;
float radius;
float startxd = 0; // starting direction vector x value
float startyd = 0; // startingdirection vestor y value
float xd = 0; // current direction vector x value
float yd = 0; // current direction vector x value
float alpha = 1.0; // transparency
};
int winWidth = 1000, winHeight = 1000;
int counter = 0;
time_t t;
sprayParticle spray[SPRAYSIZE];
float angle = 90; // the angle of the spray: 0 degrees is to the left,
// 90 degrees straight up, 180 to the right etc
float sprayWidth = 30;// the width of the spray in degrees
float sprayCenterX, sprayCenterY;
//variables for spray colour, set once per spray
float fr = 1; float fg = 1; float fb = 1;
// the gravity vector
float gx = 0;
float gy = -0.0005;
// the position of thepartcle ystem emitter, wher the rocket should be drawn
float rocketstartx = winWidth - 100, rocketstarty = winHeight - 100;
void init() {
glClearColor(0.0, 0.0, 0.0, 0.0); // set what colour you want the background to be
glMatrixMode(GL_PROJECTION); // set the matrix mode, we will look at this later
gluOrtho2D(0.0, winWidth, 0.0, winHeight);
}
void circle(double radius, double xc, double yc) {
int i;
double angle = 2 * 3.1415 / 20; // circle is drawn using 20 line.
double circle_xy[40][2];
circle_xy[0][0] = radius + xc;
circle_xy[0][1] = yc;
glBegin(GL_POLYGON);
for (i = 1; i < 20; i++) {
circle_xy[i][0] = radius * cos(i *angle) + xc;
circle_xy[i][1] = radius * sin(i * angle) + yc;
glVertex2f(circle_xy[i - 1][0], circle_xy[i - 1][1]);
glVertex2f(circle_xy[i][0], circle_xy[i][1]);
}
glEnd();
}
void normalise(int i) {
float mag;
mag = sqrt((spray[i].xd*spray[i].xd) + (spray[i].yd*spray[i].yd));
spray[i].xd = spray[i].xd / mag;
spray[i].yd = spray[i].yd / mag;
}
// we calculate the direction vector of the current particle from the global
variable angle and spread
void setDirectionVector(int i) {
float minAngle, maxAngle, range, newangle;
double newAngleInRadians; // variable
int rangeInt;
minAngle = angle - (sprayWidth / 2.0); // calc the minimum angle the particle could move along
maxAngle = angle + (sprayWidth / 2.0); // calc the maximum angle
range = maxAngle - minAngle;
rangeInt = (int)(range*100.0);
newangle = minAngle + ((float)(rand() % rangeInt) / 100.0); // generate a random angle between mi and max angles
newAngleInRadians = (double)(newangle / 360.0)*(2 * 3.1415); // convert it to radians
spray[i].xd = (float)cos(newAngleInRadians);// calc the diection vector x value
spray[i].yd = (float)sin(newAngleInRadians);// calc the diection vector y value
}
void initspray() {
for (int i = 0; i < SPRAYSIZE; i++) {
spray[i].x = winWidth / 2; // set current start x position
spray[i].y = 100;// set current start y position
spray[i].startx = spray[i].x; spray[i].starty = spray[i].y;// set start x and y position
spray[i].speed = 0.1 + (float)(rand() % 150) / 1000.0;// speed is 0.1 to 0.25
spray[i].startTime = rand() % spray[i].startRange;// set birth time
spray[i].radius = (float)(rand() % 15); // random radius
setDirectionVector(i);// set the current direction vector
spray[i].startxd = spray[i].xd; spray[i].startyd = spray[i].yd; // set start direction vector to current
}
// set colour of spray
fr = 0.5 + (float)(rand() % 500) / 1000.0;
fg = 0.5 + (float)(rand() % 500) / 1000.0;
fb = 0.5 + (float)(rand() % 500) / 1000.0;
}
void drawsprayParticle(int i) {
glLineWidth(2);
if (!spray[i].started) {
if (counter == spray[i].startTime) {
spray[i].started = true;
}
}
if (spray[i].started) {
glColor4f(fr, fg, fb, spray[i].alpha); // white particiles
circle(spray[i].radius, spray[i].x, spray[i].y);
spray[i].x = spray[i].x + (spray[i].xd*spray[i].speed);
spray[i].y = spray[i].y + (spray[i].yd*spray[i].speed);
// this produces a direction vector that is a little longer than 1
spray[i].yd = spray[i].yd + gy;
// so the normalise the vector to make length 1
normalise(i);
// reduce transparency
spray[i].alpha -= 0.00015;
}
if (spray[i].x<0 || spray[i].x>winWidth + 500 || spray[i].y<0 || spray[i].y>winHeight) {
spray[i].x = spray[i].startx; spray[i].y = spray[i].starty; //rocketstartx
spray[i].xd = spray[i].startxd; spray[i].yd = spray[i].startyd;
spray[i].alpha = 1.0;
}
}
void drawspray() {
// draw each spray particle
for (int i = 0; i < SPRAYSIZE; i++) {
drawsprayParticle(i);
}
// increment rocket position
rocketstartx += 0.2;
// if the rocket is oof the screen more nad 500 pixels to the right the rest it to 0
if (rocketstartx > winWidth + 500) { rocketstartx = 0; }
counter++;
}
// This is the display function it is called when ever you want to draw something
void display() {
glClear(GL_COLOR_BUFFER_BIT); // clear the screen using the background colour
glColor3f(1.0, 1.0, 1.0); // set colour to white
drawspray();
glFlush(); // force all drawing to finish
}
// This is the idle function it is called whenever the program is idle
void idle() {
display();
}
// As with many programming languages the main() function is the entry point for execution of the program
int main(int argc, char** argv) {
srand((unsigned)time(&t));
// initialise first spray work
initspray();
glutInit(&argc, argv); //perform the GLUT initialization
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); // more initialisation
glutInitWindowSize(winWidth, winHeight); // set window position
glutInitWindowPosition(0, 0); // set window size
glutCreateWindow("Fire"); // create a display with a given caption for the title bar
glEnable(GL_BLEND); //Enable blending.
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
init(); // call init function defined above
glutIdleFunc(idle); // define what function to call when the program is idle
glutDisplayFunc(display); // define what function to call to draw
glutMainLoop();
// this line exits the program
return 0;
}
The original code above normally creates a fountain that sprays particles all over the screen, but I have changed the size and range of the spray, so I can create a flame. The problem is that I can't stop the spread of the particles and it keeps moving up. I want it to stay in its position.
This is how it works:
This is how I want it to work:

With the formula
spray[i].x = spray[i].x + (spray[i].xd*spray[i].speed);
spray[i].y = spray[i].y + (spray[i].yd*spray[i].speed);
the distance of the points to it origin linear increases. You have to decrease the speed by time to smoothly approach to a limit position.
e.g.
spray[i].speed *= 0.9992f;
Of course you have to rest the speed (spray[i].speed), when the point is "restarted" at its origin. If the speed of the point or the alpha value of the point falls below a threshold, then the point has to be "restarted", too:
void drawsprayParticle(int i) {
glLineWidth(2);
if (!spray[i].started) {
if (counter == spray[i].startTime) {
spray[i].started = true;
}
}
if (spray[i].started) {
glColor4f(fr, fg, fb, spray[i].alpha); // white particles
circle(spray[i].radius, spray[i].x, spray[i].y);
spray[i].x = spray[i].x + (spray[i].xd*spray[i].speed);
spray[i].y = spray[i].y + (spray[i].yd*spray[i].speed);
// this produces a direction vector that is a little longer than 1
spray[i].yd = spray[i].yd + gy;
// so the normalize the vector to make length 1
normalise(i);
// reduce transparency
spray[i].alpha -= 0.0003;
spray[i].speed *= 0.9992f;
}
if ( spray[i].x<0 || spray[i].x>winWidth + 500 ||
spray[i].y<0 || spray[i].y>winHeight ||
spray[i].alpha < 1.0f/256.0f ||
spray[i].speed < 0.04f ) {
spray[i].x = spray[i].startx; spray[i].y = spray[i].starty;
spray[i].xd = spray[i].startxd; spray[i].yd = spray[i].startyd;
spray[i].alpha = 1.0;
spray[i].speed = 0.1 + (float)(rand() % 150) / 1000.0;
}
}
This is an empirical algorithm, so you have to play around with the values, to get the effect of your need.
Additionally I increase the start range: int startRange = 1300;
Preview:

Related

A ball animation in simple harmonic motion using SDL2 and C++

I'm trying to emulate the following ball. Notice the simple harmonic motion of the ball, with the very ends of the ball bounce having a smaller velocity compared to the velocity in the middle:
I'm able to implement a bouncing ball, however it's not simple harmonic motion:
The corresponding code is as follows:
Dot::Dot() {
//Initialize the offsets
mPosX = 300;
mPosY = 0;
//Initialize the velocity
mVelX = 0;
mVelY = 4;
}
void Dot::move() {
//Move the dot up or down
mPosY += mVelY;
//If the dot went too far up or down
if( ( mPosY < 0 ) || ( mPosY + DOT_HEIGHT > SCREEN_HEIGHT ) )
{
//Move back
mVelY = -mVelY;
}
}
I have a simple harmonic motion model, like so:
The corresponding code is as follows:
Dot::Dot() {
//Initialize the offsets
mPosX = 300;
mPosY = 0;
//Initialize the velocity
mVelX = 0;
mVelY = 0;
}
void Dot::move() {
time_t current_time;
current_time = time(NULL);
mPosY = int(((460) - 10) * sin(2.4 * 2 * 3.141592 / 60 * current_time + (SCREEN_HEIGHT / 2)
));
//const int SCREEN_HEIGHT = 480
}
The issues with this implementation are that:
(1). the ball image appears every now and then, rather than continuously like in the blue ball model I tried to emulate at the very beginning
(2). the ball goes well beyond the top frame of the window, rather than slowing down at the very top of the window, again like the blue ball model.
For (2), I understand that I need to add a phase shift, i.e x in A*sin(wt + x), however changing this value doesn't do anything to prevent the ball from disappearing at the top of the window.
Any ideas on how to solve these issues?
Edit: I was able to solve (1) by doing += to mPosY rather than =, such as:
mPosY += int(4 * cos(2.4 * 2 * 3.141592 / 60 * current_time + (SCREEN_HEIGHT / 2) ));
However, I'm still unable to get the ball to bounce up and down within the frame of the window I created.
I recommend using actual simple harmonic equations.
For example, if your display dimensions are (500, 500), the center Y is 250. from there say your equation is in the form of x = acos(nt + m) + c where x is displacement (meters), a is amplitude n is for the period, for example the period (T) = 2PI/n t is time (seconds) and m is for phase shift and c is for the center. That way when you need the velocity of the object, you have a function that follows along the lines of
double Velocity(double time){
double vel = derivative_of_displacement_equation(time);
return vel;
}
And so in the program, you adjust the equation to suit the display dimensions, then you set the objects X/Y coordinates as the value returned from the displacement equation (PLUS THE CENTER OFFSET, in this example, if the center is at the middle of the screen, you would set the Y coordinate to the equation PLUS 250). Keep in mind coordinates begin at (0,0) so your displacement equation (at least the part where it involves the proportional factor, which in this case is time), you make that negative instead.
Here is some code that I believe answers your question:
#include <SDL2/SDL.h>
#include <chrono>
#include <math.h>
#include <iostream>
const double PI = 3.14159265358979;
void draw_circle(SDL_Renderer *renderer, int x, int y, int radius, SDL_Color color)
{
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
for (int w = 0; w < radius * 2; w++)
{
for (int h = 0; h < radius * 2; h++)
{
int dx = radius - w; // horizontal offset
int dy = radius - h; // vertical offset
if ((dx*dx + dy*dy) <= (radius * radius))
{
SDL_RenderDrawPoint(renderer, x + dx, y + dy);
}
}
}
}
double Displacement(double time, double a, double n, double m, double c)
{
double displacement = a*cos(n*time + m) + c;
return displacement;
}
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow("SHM", 0, 30, 500, 500, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);// | SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED );
double timeDifference;
std::chrono::steady_clock::time_point start, finish;
start = std::chrono::steady_clock::now();
finish = start;
SDL_Event event;
bool running = true;
while (running){
while (SDL_PollEvent(&event)){
if (event.type == SDL_QUIT){
running = false;
break;
}
}
SDL_SetRenderDrawColor(renderer, 255,255,255,255);
SDL_RenderClear(renderer);
finish = std::chrono::steady_clock::now();
timeDifference = std::chrono::duration_cast<std::chrono::nanoseconds>(finish - start).count();
timeDifference = timeDifference / 1000000000;
///The "-(250-20) is the center y (250) minus the radius of the circle (20), and its - out the front as negative a due to coordinates
double yPosition = round( Displacement(timeDifference, -(250-20), 2, 0, 250 ) );
draw_circle(renderer, 250, yPosition, 20, {255,0,0});
SDL_RenderPresent(renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
In general you have a0 + a/2*cos (2*π₯*t/T + 𝝫) where a0 is the vertical position of the half of the vertical travel, a is the height of the travel, t is time, T the period ie., the time to do a complete cycle for going and coming back to the same state or uple { position, momentum }, and 𝝫 the time shift, ie., the moment where the height is at zero of the cos.
So if you want the ball to be on the floor at t=0, you want cos at the minimum, ie., 𝝫 = -π₯/2.
You want to manage your position in function of your game's time t, so you can decouple the time to compute (which depend on your compute calpabilities) and the game's time (that you want constant from a machine to another).
Therefore you want:
auto VerticalPosition(double t)
-> double { return CorrectedScreenHeight/2*(1 + cos(2*PI*t/T + phi)); }
And you define CorrectedScreenHeight = SCREEN_HEIGHT - DOT_HEIGHT, T and phi outside, as properties of your system.
Between two consecutive images, you increment t, in order to have the correct experienced time. Typically you have 60 images/s (WPF, DirectX, web, etc), hence a period of 1.0/60s between consecutive images, this goes in your function that modifies t. The speed of your ball then depend on T, that you can tune independently.

How could I fill in my circle with a solid color using the distance formula?

I am a beginner in c++ and have coded a for loop to show a hollow circle when I run the code, however, I was wondering how I could achieve a filled-in circle using the distance formula (d = sqrt((ax-bx)^2 + (ay-by)^2). Here's what I have so far! Any help would be appreciated!
int MAX = 728;
for (float t = 0; t < 2 * 3.14; t += 0.01)
SetPixel(MAX / 4 + MAX / 6 * sin(t), MAX / 4 + MAX / 6 * cos(t), 255, 255, 0);
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
HWND consoleWindow = GetConsoleWindow(); // Get a console handle
HDC consoleDC = GetDC(consoleWindow); // Get a handle to device context
int max = 628;
float i = 0;
float t;
float doublePi = 6.29;
for (i = 0.0; i < max; i += 2.0) {
for (t = 0.0; t < doublePi; t += 0.01) {
SetPixel(consoleDC, max / 4 + (max - i) / 6 * sin(t), max / 4 + (max - i) / 6 * cos(t), RGB(255, 255, 0));
}
}
ReleaseDC(consoleWindow, consoleDC);
cin.ignore();
return 0;
}
Working almost well. Draw and fill in! A little slow...
Pffff... do not use sin and cos! instead use the sqrt(1-x^2) approach. You can view the formula rendering a circle in google for example: https://www.google.com/search?q=sqrt(1-x^2)
I edit this answer because it seems that is not clear:
float radius = 50.0f;
for (int x = -radius; x <= radius; ++x) {
int d = round(sqrt(1.0f - (x * x / radius / radius)) * radius);
for (int y = -d; y <= d; ++y) {
SetPixel(x, y, 255, 255, 0);
}
}
Note: each graphic library is different, so I assumed that you used rightfully the "SetPixel" function.
Now, for most people say the sqrt(1-x^2) approach should be enough, but it seem that some downvoters does not think the same XD.
Inefficient as can be, and probably the last way you really want to draw a circle ... but ...
Over the entire square encompassing your circle, calculate each pixel's distance from the center and set if under or equal the radius.
// Draw a circle centered at (Xcenter,Ycenter) with given radius using distance formula
void drawCircle(HDC dc, int XCenter, int YCenter, int radius, COLORREF c) {
double fRad = radius * 1.0; // Just a shortcut to avoid thrashing data types
for (int x = XCenter - radius; x<XCenter + radius; x++) {
for (int y = YCenter - radius; y<YCenter + radius; y++) {
double d = sqrt(((x - XCenter) * (x - XCenter)) + ((y - YCenter) * (y - YCenter)) );
if (d <= fRad) SetPixel(dc, x, y, c);
}
}
}
Caveat: No more caveat, used a C++ environment and tested it this time. :-)
Call thusly:
int main()
{
HWND consoleWindow = GetConsoleWindow();
HDC consoleDC = GetDC(consoleWindow);
drawCircle(consoleDC, 50, 50, 20, RGB(255, 0, 255));
ReleaseDC(consoleWindow, consoleDC);
return 0;
}

Use Kalman Filter to filt noise without delay opencv c++

My task is to detect an orange ball in video. I detected by thresholding image on HSV colorspace and bounding box. Then I have center and radius of ball, with unit is pixel.
When ball is static, I expect center and radius will be static too, but reality, it has noise. I use Kalman Filter to filter noise and it works well. But it delay in real-time. I try to optimize covariance parameters but not work.
So could anyone help me static center and radius when ball is static and without delay?
Are you sure it is the Kalman Filter witch is causing the delay.
Otherwise you can try this lazy filter witch only is noise rejecting but blazingly fast. My suspicion however it is the HSV conversion.
class noiseFilter
{
private:
cv::Point2f ptLast;
float ptMaxTol;
public:
noiseFilter(float maxTol = 1.5f)
{
ptMaxTol = maxTol * maxTol; // we do the pow(2) here so we don't have to do a square root on every update
ptLast = cv::Point2f(0.0f, 0.0f);
}
cv::Point2f update(cv::Point2f &ptNew) // update filter with new found point
{
float dist = pDistance2(ptLast, ptNew);
if (dist > ptMaxTol) ptLast = ptNew; // update only if distance is more than threshold
return ptLast;
}
cv::Point2f getResult() // get result of filter
{
return ptLast;
}
private:
// calculate distance between 2 point without doing a sqrt
float pDistance2(cv::Point2f &p1, cv::Point2f &p2)
{
float dx = p1.x - p2.x;
float dy = p1.y - p2.y;
return (dx * dx + dy * dy);
}
};
int main()
{
cv::Point2f pt;
noiseFilter filter(2.1f); // initialize filter wit max 2.1 pixels noise rejection.
int x = 100, y = 120;
for (int i = 0; i < 100; i++)
{
// generate some noise with 2 pixels variation
pt.x = ((rand() % 200) - 100) * 0.01f + x;
pt.y = ((rand() % 200) - 100) * 0.01f + y;
cv::Point2f pts = filter.update(pt);
printf("input x=%6.2f y=%6.2f output x=%6.2f y=%6.2f\r\n", pt.x, pt.y, pts.x, pts.y);
// do som random big update on random intervals
if ((rand() % 50) == 1) {
x += 15;
printf("big update on X\r\n");
}
if ((rand() % 50) == 1){
y += 25;
printf("big update on Y\r\n");
}
}
return 0;
}
Below a noise filter with smoothing.
Works on slow and fast moving objects.
class noiseFilterSmooth
{
private:
static const int maxHist = 10;
cv::Point2f ptLast;
float ptMaxTol;
cv::Point2f hist[maxHist];
int histHead,histSize;
public:
noiseFilterSmooth(float maxTol = 1.5f)
{
histHead = histSize = 0;
ptMaxTol = maxTol * maxTol; // we do the pow(2) here so we don't have to do a square root on every update
ptLast = cv::Point2f(0.0f, 0.0f);
}
cv::Point2f& update(cv::Point2f &ptNew) // update filter with new found point
{
float dist = pDistance2(ptLast, ptNew);
if (dist > ptMaxTol) histSize = histHead = 0; // reset smoothing filter if distance is more than threshold
// update smoothing filter with last result
hist[histHead] = ptNew; // update smoothing filter with last
histHead = (histHead + 1) % maxHist;
if (histSize < maxHist) histSize++;
return getResult();
}
cv::Point2f& getResult() // get result of filter
{
float sumx = 0, sumy = 0;
for (int i = 0; i < histSize; i++)
{
sumx += hist[i].x;
sumy += hist[i].y;
}
ptLast.x = sumx / histSize;
ptLast.y = sumy / histSize;
return ptLast;
}
private:
// calculate distance between 2 point without doing a sqrt
float pDistance2(cv::Point2f &p1, cv::Point2f &p2)
{
float dx = p1.x - p2.x;
float dy = p1.y - p2.y;
return (dx * dx + dy * dy);
}
};

Negative row and column in terrain following algorithm

I'm trying to do terrain following, and I get a negative camera position in the xz plane. Now I get an out of boundary exception, because the row or the col is negative. How would I transform the cell of the grid to the origin correctly, giving negative camera coordinates.
Here is the two functions
int cGrid::getHeightmapEntry(int row, int col)
{
return m_heightmap[row * 300 + col];
}
float cGrid::getHeight(float x, float z, float _width, float _depth, int _cellSpacing)
{
// Translate on xz-plane by the transformation that takes
// the terrain START point to the origin.
x = ((float)_width / 2.0f) + x;
z = ((float)_depth / 2.0f) - z;
// Scale down by the transformation that makes the
// cellspacing equal to one. This is given by
// 1 / cellspacing since; cellspacing * 1 / cellspacing = 1.
x /= (float)_cellSpacing;
z /= (float)_cellSpacing;
// From now on, we will interpret our positive z-axis as
// going in the 'down' direction, rather than the 'up' direction.
// This allows to extract the row and column simply by 'flooring'
// x and z:
float col = ::floorf(x);
float row = ::floorf(z);
if (row < 0 || col<0)
{
row = 0;
}
// get the heights of the quad we're in:
//
// A B
// *---*
// | / |
// *---*
// C D
float A = getHeightmapEntry(row, col);
float B = getHeightmapEntry(row, col + 1);
float C = getHeightmapEntry(row + 1, col);
float D = getHeightmapEntry(row + 1, col + 1);
//
// Find the triangle we are in:
//
// Translate by the transformation that takes the upper-left
// corner of the cell we are in to the origin. Recall that our
// cellspacing was nomalized to 1. Thus we have a unit square
// at the origin of our +x -> 'right' and +z -> 'down' system.
float dx = x - col;
float dz = z - row;
// Note the below compuations of u and v are unneccessary, we really
// only need the height, but we compute the entire vector to emphasis
// the books discussion.
float height = 0.0f;
if (dz < 1.0f - dx) // upper triangle ABC
{
float uy = B - A; // A->B
float vy = C - A; // A->C
// Linearly interpolate on each vector. The height is the vertex
// height the vectors u and v originate from {A}, plus the heights
// found by interpolating on each vector u and v.
height = A + Lerp(0.0f, uy, dx) + Lerp(0.0f, vy, dz);
}
else // lower triangle DCB
{
float uy = C - D; // D->C
float vy = B - D; // D->B
// Linearly interpolate on each vector. The height is the vertex
// height the vectors u and v originate from {D}, plus the heights
// found by interpolating on each vector u and v.
height = D + Lerp(0.0f, uy, 1.0f - dx) + Lerp(0.0f, vy, 1.0f - dz);
}
return height;
}
float height = m_Grid.getHeight(position.x, position.y, 49 * 300, 49 * 300, 6.1224489795918367f);
if (height != 0)
{
position.y = height + 10.0f;
}
m_Camera.SetPosition(position.x, position.y, position.z);
bool cGrid::readRawFile(std::string fileName, int m, int n)
{
// A height for each vertex
std::vector<BYTE> in(m*n);
std::ifstream inFile(fileName.c_str(), std::ios_base::binary);
if (!inFile)
return false;
inFile.read(
(char*)&in[0], // buffer
in.size());// number of bytes to read into buffer
inFile.close();
// copy BYTE vector to int vector
m_heightmap.resize(n*m);
for (int i = 0; i < in.size(); i++)
m_heightmap[i] = (float)((in[i])/255)*50.0f;
return true;
}
m_Grid.readRawFile("castlehm257.raw", 50, 50);
I infer that you’re storing a 50 by 50 matrix inside a 300 by 300 matrix, to represent a grid of 49 by 49 cells. I also infer that m_Grid is an object of type cGrid. Your code appears to contain the following errors:
Argument(2) of call m_Grid.getHeight is not a z value.
Argument(3) of call m_Grid.getHeight is inconsistent with argument(5).
Argument(4) of call m_Grid.getHeight is inconsistent with argument(5).
Implicit cast of literal float to int in argument(5) of call m_Grid.getHeight - the value will be truncated.
Try changing your function call to this:
float height = m_Grid.getHeight(position.x, position.z, 49 * cellspacing, 49 * cellspacing, cellspacing);
-- where cellspacing is as defined in your diagram.
Also, try changing parameter(5) of cGrid::getHeight from int _cellSpacing to float _cellSpacing.
(I have edited this answer a couple of times as my understanding of your code has evolved.)

zooming mandelbrot set second time doesnot let it zoom in desired place

I am using opengl/c++ to draw mandelbrot set and trying to zoom into. I am able to zoom for the first time and zooms where i want (by clicking), but when i try to zoom next time it does not zoom where i intended to zoom instead it shift and zoom little bit far from the place i want to zoom.
I use
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
double dividecubesby = 700;
double left = -2.0;
double right = 2.0;
double bottom = -2.0;
double top = 2.0;
int maxiteration = 128;
int zoomlevel = 3;
double baseSize = 4.0;
double Size = 0.0;
double xco=0.0;
double yco=0.0;
void SetXYpos(int px,int py)
{
xco = left+(right-left)*px/dividecubesby;
yco = top-(top-bottom)*py/dividecubesby;
}
void keyPressed(unsigned char key, int x, int y)
{
int xx= x;
int yy= y;
setXYpos(xx,yy);
Size = 0.5*(pow(2.0, (-zoomlevel)));
switch(key){
case 'z':
left = xco - Size;
right = xco + Size;
bottom = yco - Size;
top = yco + Size;
dividecubesby = dividecubesby+100;
maxiteration = maxiteration+100;
zoomlevel=zoomlevel+1;
glutPostRedisplay();
break;
}
}
int mandtest(double Cr, double Ci)
{
double Zr = 0.0;
double Zi = 0.0;
int times = 0;
double temp;
Zr = Zr+Cr;
Zi = Zi+Ci;
while ((((Zr*Zr)+(Zi*Zi))<=4) && (times < maxiteration)){
temp = (Zr*Zr)-(Zi*Zi);
Zi = 2*Zr*Zi;
Zr = temp+Cr;
Zi = Zi+Ci;
times = times+1;
}
return times;
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f,1.0f,1.0f);
double deltax = ((right - left)/(dividecubesby-1));
double deltay = ((top- bottom)/(dividecubesby-1));
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(left,right,bottom,top);
glBegin(GL_POINTS);
for(double x= left;x<=right;x += deltax ){
for(double y= bottom; y<=top;y += deltay ){
if((mandtest(x,y))==maxiteration){
glColor3f(1.0f,1.0f,1.0f);
glVertex2f(x,y);
}
else {
glColor3f((float)mandtest(x,y)/10,0.0f,(float)mandtest(x,y)/30);
glVertex2f(x,y);
}
}
}
glEnd();
glFlush();
}
to calculate where the mouse is clicked interms of the cartesian co-ordinate [-2,2]
px and py are pixel coordinate
You have too many variables. What defines the width of your image? (right - left)? baseSize + f(zoomLevel)? SizeReal? It's not clear whose job it is to set whom and who is used by whom, so you cannot hope to update everything consistently.
Also, why does dividecubesby increase by a flat 500 while the image size halves with every zoom? Where is the width/height of your window system window which define the limits of the clicked coordinates?
My suggestion is to start from scratch and maybe draw a graph of who updates whom (left/right -> imageWidth). Make sure that you get the correct clicked coordinates independent of what your drawing window (left/right/top/bottom) is, and go on from there. As it is, I think your first zoom works correctly by accident.