OpenGL glcolor for loop - c

i am trying to draw a lorenz attractor where the color changes throughout the attractor. i have written the following for loop which calculates the attractor points.
float x = 1, y = 1, z = 1;
glBegin(GL_LINE_STRIP);
int i;
for (i=0; i < initialIterations; i++) {
glColor3d(0,i/50000,1);
// compute a new point using the lorenz attractor equations
float dx = sigma*(y-x);
float dy = x*(r-z) - y;
float dz = x*y - b*z;
// save the new point
x = x + dx*dt;
y = y + dy*dt;
z = z + dz*dt;
glVertex3f(x/50,y/50,z/50);
}
glEnd();
i am using the glcolor at the top of the code to change the color as a function of i. However i do not see the result i want, all i get is one solid color. i know the color works like a state machine but i need to find a way to change the color throughout.

You're doing integer division : i/50000, so it's always 0.
Try i/50000.0

Related

How to Create asteroids on the x and y axes

I'm doing Asteroids (Atari) in C. I designed the ADT for asteroids, all the ADT is related to 1 asteroid.
I need to create an asteroid in a random position, but random within (0, y) or (x, 0)
I have my function asteroid_create():
asteroid_t *asteroid_create(float x, float y, float radio){
asteroid_t *ast = malloc(sizeof(asteroid_t));
ast->x_pos = x;
ast->y_pos = y;
ast->radio = radio;
ast->vx = rand_float((1000/ast->radio)-100,(1000/ast->radio)+100);
ast->vy = rand_float((1000/ast->radio)-100,(1000/ast->radio)+100);
ast->angle = rand_float(0,2*PI);
size_t rock_rand = rand() % ASTEROIDS_TYPES;
ast->name_rock = rocks_dictionary[rock_rand];
return ast;
}
That creates an asteroid with certain fixed variables. Then, in another file, I create a list of asteroids and I'm inserting as many asteroids I need.
bool asteroids_insert(list_t* l){
asteroid_t *ast = asteroid_create(rand_float(0,WINDOW_WIDTH),rand_float(0,WINDOW_HIGH),AST_INITIAL_RADIO);
if(!list_append(l,ast))
return false;
return true;
}
In the main:
for(size_t i=0; i< ASTEROIDS_INITIAL;i++){
asteroids_insert(list_asteroids);
}
In this way, I am creating asteroids anywhere on the screen. I only need them to be generated on the y axis or the x axis.
The way I am doing it, I can't think of how I can do what I need. How can I do it so that asteroid_create() receive as a parameter positions in (0, y) or (x, 0) randomly?
Imagine you bend the y axis down to the left, so that in effect it becomes the "negative part" of the x axis.
Generate a random number value between -MAX_Y and +MAX_X.
If the resulting number is 0 your point is (0, 0); if it's positive, your point is (value, 0), otherwise it's (0, -value).
Note: if your x axis is larger than y axis, this will make it more probable to generate points on the x axis.

Rotate a triangle around itself in c using three vertixes

I need to rotate a triangle (called ship) around itself.
Here is what I got so far, but it doesn't work. It keeps getting smaller and smaller until it disappears.
void RotatePoint(Point *P, float angle)
{
float theta = angle * (180/3.1415);
P->x = (P->x * cos(theta)) - (P->y * sin(theta));
P->y = (P->y * cos(theta)) + (P->x * sin(theta));
}
void RotateShip(Ship *ship)
{
Rotate(&ship->A, rotateAngle);
Rotate(&ship->B, rotateAngle);
Rotate(&ship->C, rotateAngle);
}
Point P is the Point I want to rotate, and Point C is the center of the triangle. I thought that if I rotate all three vertixes, the triangle will rotate.
In my case, I initialize this way:
void initShip(Ship *ship)
{
ship->center.x = (SCREEN_W)/2.0;
ship->center.y = (SCREEN_H)/2.0;
ship->A.x = 0;
ship->A.y = -5;
ship->B.x = 15;
ship->B.y = 25;
ship->C.x = -15;
ship->C.y = 25;
ship->color = al_map_rgb(255, 255, 255);
}
Ship A, B and C are the distance from the center of the triangle. I draw it adding the A, B and C to the center vertix.
A=-0.699857,-19.963261
A=-0.000857,-19.951065
A=-0.699001,-19.914387
A=-0.001712,-19.902250
A=-0.698147,-19.865631
A=-0.002565,-19.853554
Im pressing one key back and one key forth, making it rotate clockwise and anticlockwise. notice how A is shrinking.
I don't know what I do. I should be going back to 20.00 when it reaches the top. This way my triangle is shrinking.
I'm using cos(0.035) and sin(0.035), meaning 2 degrees.
The OP has a classic bug: using a temporary (or intermediate) value where the original/initial value should be used instead.
As a simplified example, consider a case where you have three variables, a, b, and c, and want to rotate their values one variable to the left:
a = b;
b = c;
c = a; /* Oops! Won't work! */
The last assignment is a problem, because a is no longer the original value! You cannot order the assignments in a way that would avoid this problem; the only thing that changes is which variable will suffer from the problem. To fix the problem, you need to use a new temporary variable to hold the original value:
t = a;
a = b;
b = c;
c = t;
In OP's case, the ship structure should not mix the current shape of the ship, and the true/unrotated shape of the ship, in the same variables. Even if you avoid the abovementioned problem, you'll still suffer from accumulated rounding errors; it might take hours of gameplay, but eventually your ship would end up looking different.
The solution is to describe the ship shape in separate variables, or using constants in the ship update function.)
Let's say we have a variable dir that specifies the direction in radians, rotated counterclockwise from up, 0 being up (towards negative y axis), π/2 (and -3π/2) left (towards negative x axis), π (and -π) down, 3π/2 (and -π/2) right, and so on. If deg is in degrees, dir = deg * 3.14159265358979323846 / 180.0. We can also use the atan2() function to find out dir: dir = atan2(-x, y).
When dir = 0, OP wants A = { 0, -5 }, B = { 15, 25 }, and C = { -15, 25 }. If we define Adir = 3.14159, Ar = 5, Bdir = -0.54042, Br = sqrt(15*15+25*25) = 29.15476, Cdir = 0.54042, and Cr = 29.15476, then the ship vertices are
A.x = center.x + Ar*sin(dir + Adir);
A.y = center.y + Ar*cos(dir + Adir);
B.x = center.x + Br*sin(dir + Bdir);
B.y = center.y + Br*cos(dir + Bdir);
C.x = center.x + Cr*sin(dir + Cdir);
C.y = center.y + Cr*cos(dir + Cdir);
If the OP wants to fix the ship shape in the rotateShip function, then
void rotateShip(Ship *s, double rotateAngle)
{
s->A.x = s->center.x + 5.00000 * sin(rotateAngle + 3.14159);
s->A.y = s->center.y + 5.00000 * cos(rotateAngle + 3.14159);
s->B.x = s->center.x + 29.15476 * sin(rotateAngle - 0.54042);
s->B.y = s->center.y + 29.15476 * cos(rotateAngle - 0.54042);
s->C.x = s->center.x + 29.15476 * sin(rotateAngle + 0.54042);
s->C.y = s->center.y + 29.15476 * cos(rotateAngle + 0.54042);
}
Personally, I'd define the ship shape using a variable number of vertices:
typedef struct {
double x;
double y;
} vec2d;
typedef struct {
vec2d center;
size_t vertices;
const vec2d *shape; /* Un-rotated ship vertices */
double direction; /* Ship direction, in radians */
vec2d *vertex; /* Rotated ship vertices */
} Ship;
const vec2d default_shape[] = {
{ 0.0, -5.0 },
{ -15.0, 25.0 },
{ 15.0, 25.0 },
};
void updateShip(Ship *ship)
{
const double c = cos(ship->direction);
const double s = sin(ship->direction);
size_t i;
for (i = 0; i < ship->vertices; i++) {
ship->vertex[i].x = ship->center.x + c*ship->shape[i].x - s*ship->shape[i].y;
ship->vertex[i].y = ship->center.y + s*ship->shape[i].x + c*ship->shape[i].y;
}
}
void initShip(Ship *ship, const size_t vertices, const vec2d *shape)
{
ship->center.x = 0.5 * SCREEN_W;
ship->center.y = 0.5 * SCREEN_H;
if (vertices > 2 && shape != NULL) {
ship->vertices = vertices;
ship->shape = shape;
} else {
ship->vertices = (sizeof default_shape) / (sizeof default_shape[0]);
ship->shape = default_shape;
}
ship->direction = 0;
ship->vertex = malloc(ship->vertices * sizeof ship->vertex[0]);
if (!ship->vertex) {
fprintf(stderr, "Out of memory.\n");
exit(EXIT_FAILURE);
}
updateShip(ship);
}
In updateShip, we use 2D rotation by ship->direction, to rotate the ship model speficied by the vertices in shape[], saving the rotated and translated coordinates to vertex[].
x_current = x_center + x_original * cos(direction) - y_original * sin(direction);
y_current = y_center + x_original * sin(direction) + y_original * cos(direction);
as defined in e.g. the Wikipedia article on rotation. Note that the original coordinates, x_original and y_original (or the values in the shape[] array in the Ship structure) are never modified.
This way you can let the player "upgrade" their ship by just changing the shape to point to a new ship shape, and vertices to reflect that number.
I can reproduce fast shrinking (while also rotating) with coordinates in int.
(It would have been so much easier based on an MCVE....).
With coordinates in float, it shrinks much slower, but it still shrinks.
I relate that to the fact that your implementation collects all math errors (which computers always make) in a very visible way.
In order to avoid shrinking altogether:
Do not manipulate the relative coordinates in order to rotate. Instead store relative coordinates as constants, together with the ships orientation as an angle in double.
Then rotate by increasing/reducing the angle (wrapping around, to stay within -Pi ... +Pi).
Then draw by always applying the changing angle to the constant relative coordinates.
(I can only show you in detail, if you provide a MCVE.)
This way, the collected errors will only result in a slight and slowly growing misorientation,
which most likely will not be noticed by the pilot - and then be corrected by the pilot.
"Hmm, the ship has not yet completed the 360 I wanted. Oh well, I will turn a little more."
On a side note, I do not trust the way you use angles as parameters to cos() and sin().
Or to put it differently, I think
theta = angle * (180/3.1415); -> theta = angle; for a U-turn via Pi.
theta = angle * (180/3.1415); -> theta = angle * (3.1415/180); for a U-turn via 180.
For your implementation you get a U-turn for the angle (Pi*3.1415/180), which I cannot see a reason for.
I also recommend to use appropriate constants from math.h (e.g. M_PI), instead of your own constant with 4 decimal places.

How do I zoom on cursor position in mandelbrot or julia set?

I am writing a fractal explorer at the moment and I got stuck at zooming on a certain point in the set. My drawing function for the Julia set for example looks like this:
void *julia_thread(void *param)
{
int x, y, temp;
long double re, aux, im;
int start = ((int *)param)[0];
int end = ((int *)param)[1];
int iterations;
for (x = start; x < end; x++)
for (y = 0; y < WIN_SIZE; y++)
{
re = range_change(zoom_factor, x, mv_x);
im = range_change(zoom_factor, y, mv_y);
iterations = 0;
while (!blowing_up(re, im) && iterations < max_iter)
{
aux = re;
re = re * re - im * im + re_c;
im = 2 * aux * im + im_c;
iterations++;
}
put_pixel(img, x, y, color_table[iterations]);
}
return NULL;
}
The function that calculates the initial values for the real and imaginary part of Z is this:
long double range_change(long double zoom_factor, int value, long double mv)
{
long double newmax = 2 / zoom_factor;
long double newmin = -2 / zoom_factor;
return ((long double)value * (newmax - newmin)) / WIN_SIZE + newmin + mv;
}
So I get a scaled down value that is part of the interval where the fractal exists and according to the number of iterations I assign a colour to that certain pixel. Zooming works fine by making the real interval (-2, 2) smaller by dividing both of the ends with a factor. This works but I can't seem to be figure out how to zoom on a certain spot other than the centre. I can move around and reach that spot eventually by adding to the real and imaginary part (x, y) a number but I can't zoom on a point determined by the screen (x, y) given to me by the cursor position.
It is a very bad idea to do indiscriminate integer divisions:
2 / zoom_factor
will return 0 if zoom_factor is larger than 2. Replace 2 by 2.0 to force floating point division, this should be sufficient to repair the code.
If I interpret this correctly, you want that the screen window represents a square in the coordinate or fractal plane with the width and height 4.0/zoom_factor around the point (mv_x, mv_y).
mv is situated at WIN_SIZE/2, so that
coord = mv + ( 4*value/WIN_SIZE - 2 )/zoom_factor
which can be implemented exactly as this
return mv + ( (4.0*value)/WIN_SIZE - 2.0 )/zoom_factor;
and with the factor 4.0 the denominator gets type double and division is carried out in double.
Slow derivation
What the function range_change wants to achieve is a linear change of coordinates
coord = A*screen + B
where screen is the input screen coordinate and coord is the coordinate in the Cartesian plane playing host for the Julia fractal. The endpoint mapping is
screen=0 --> coord = center - 2.0/zoom
screen=WIN_SIZE --> coord = center + 2.0/zoom
From the first we read B=center - 2.0/zoom and from the second formula
A*WIN_SIZE + center - 2.0/zoom = center + 2.0/zoom
A*WIN_SIZE = 4.0/zoom
A = 4.0/(zoom*WIN_SIZE)
which gives the transformation formula
coord = (4.0*value)/(zoom*WIN_SIZE) + center - 2.0/zoom
= ( (4.0*value)/WIN_SIZE - 2.0 )/zoom + center

Alternative method of making heightmap

I was thinking of creating a 2x2 array with randomly generated values which then be drawn using glVertex3i, for example:
glBegin(GL_POLYGON);
int x = 5;
int z = 5;
for (int i=0; i<width; i++)
{
for (int j=0; j<height; j++)
{
glVertex3i(x, heightmap[i][j], z);
}
x -= 0.5;
z -= 0.5;
}
glEnd();
The only problem I'm having is that, the map isn't drawn on the z dimension I think, because all I get is 1 side essentially.
What might be wrong? Obviously the algorithm is basic for now, but its just a starting point.
What might be wrong?
Let's start here:
glBegin(GL_POLYGON);
A polygon is required to be planar. All of the vertices must lie in a single plane. If they don't, then OpenGL is not responsible for how it gets rendered. You cannot draw a heightmap as a single polygon and expect to get reasonable results. You must draw triangles, either with a series of GL_TRIANGLE_STRIPs or with GL_TRIANGLES.
Then, there's what Christian said.
Maybe you mean
float x = 5.0f;
for (int i=0; i<width; i++)
{
float z = 5.0f;
for (int j=0; j<height; j++)
{
glVertex3f(x, heightmap[i][j], z);
z -= 0.5f;
}
x -= 0.5f;
}
Or with x and z switched, depends on your convention. But first, don't subtract 0.5 from an int, it will draw the same vertex twice. And second, one variable needs to run in the inner loop, the other in the outer loop. Or did I misundertand the question?
And are you sure you want the whole heightmap to make up a single polygon? Maybe I really misunderstood the question?

Find LineSegment that contains a Point

I have a Path and when user click on a segment I have to split it into two segments.
I have the point where user click but I can't find a method to get the LineSegment that contains that point.
I don't have to find the Path element... but the LineSegment of a collection of Segment that create the PathGeometry of the Path clicked.
How can i do?
I have some code that does this. Each of my points are stored in a Points collection rather than being stored as LineSegments, but it should work for you I think. The thickness parameter is the thickness of the line.
public int HitTestSegments(Point point, double thickness)
{
for (int i = 0; i < Points.Count; ++i)
{
Point p0 = Points[i];
Point p1 = (i + 1 < Points.Count) ? Points[i + 1] : Points[0];
Vector v = p1 - p0;
Vector w = point - p0;
double c1 = w * v;
double c2 = v * v;
double b = c1 / c2;
Point pb = p0 + b * v;
double distance = (point - pb).Length;
if (distance < thickness)
{
return i;
}
}
return -1;
}
I hacked this together from various samples on the internet, and my maths isn't amazing. It may not be the best code - if not, please suggest improvements.
But you have Point property, so basically you've got a Collecion of n+1 Points. Line between points is a simple linien equation. You have to check if your mouse's point solve this equation (interates through the collection for all lines).
The equation: 0 = Ax + By + C or simply y = ax + b
There are many ways to get the parameters of it.
From geometry we know, that (y1 - y2) * x + (x2 - x1) * y + (x1*y2 - x2*y1) = 0, where x1, y1 is the firs point of your line segment and x2, y2 is the second one. This is the formula of the line. To determine, if a given point P(X, Y) belongs to the line, you have to substitute it's coordinates to your line formula's left side and the result on the right side should be 0, or 0 +- \epsilon.
But you have not a line, you have it's segment, so you will have to add more checks, for instance, Px should not be less than x1, and no more than x2, etc.
To expand on what Shaman & lukas have said - what you really want to do is find the line segment that is nearest to to click point (As the user could not be expected to click exactly on the line)
To do this,go through each of the line segments and apply the `(y1 - y2) * x + (x2 - x1) * y + (x1*y2 - x2*y1)' formula to it and remove the sign of the answer - the line segmet that produces the smallest result is the one that is nearest to the click point.
If you have a lot of segments in your path, this might take a long time to execute, so there are probably some optimisations to be done - but that, as they say, is a whole new story.

Resources