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?
Related
Given a list of spheres described by (xi, yi, ri), meaning the center of sphere i is at the point (xi, yi, 0) in three-dimensional space and its radius is ri, I want to compute all zi where zi = max { z | (xi, yi, z) is a point on any sphere }. In other words, zi is the highest point over the center of sphere i that is in any of the spheres.
I have two arrays
int **vs = (int **)malloc(num * sizeof(int *));
double **vh = (double **)malloc(num * sizeof(double *));
for (int i = 0; i < num; i++){
vs[i] = (int *)malloc(2 * sizeof(int)); // x,y
vh[i] = (double *)malloc(2 * sizeof(double)); r,z
}
The objective is to calculate the maximum z for each point. Thus, we should check if there are larger spheres over each x,y point.
Initially we see vh[i][1]=vh[i][0] for all points, which means that z is the r of each sphere. Then, we check if these z values are inside larger spheres to maximize the z value.
for (int i = 0; i < v; i++) {
double a = vh[i][0] * vh[i][0]; // power of the radius of sphere #1
for (int j = 0; j < v; j++) {
if (vh[i][0] > vh[j][1]) { // check only if r of sphere #1 is larger than the current z of #2
double b = a - (vs[j][0] - vs[i][0]) * (vs[j][0] - vs[i][0])
- (vs[j][1] - vs[i][1]) * (vs[j][1] - vs[i][1]);
// calculating the maximum z value of sphere #2 crossing sphere #1
// (r of sphere #1)**2 = (z of x_j,y_j)**2 + (distance of two centers)**2
if (b > vh[j][1] * vh[j][1]) {
vh[j][1] = sqrt(b);// update the z value if it is larger than the current value
}
}
}
}
it works perfectly, but the nested loop is very slow when the number of points increases. I look for a way to speed up the process.
An illustration for the clarification of the task
When you say
The objective is to calculate the maximum z for each point.
I take you to mean, for the center C of each sphere, the maximum z coordinate among all the points lying directly above C (along the z axis) on any of the spheres. This is fundamentally an O(n2) problem -- there is nothing you can do to prevent the computational expense scaling with the square of the number of spheres.
But there may be some things you can do to reduce the scaling coeffcient. Here are some possibilities:
Use bona fide 2D arrays (== arrays of arrays) instead arrays of pointers. It's easier to implement, more memory-efficient, and better for locality of reference:
int (*vs)[2] = malloc(num * sizeof(*vs));
double (*vh)[2] = malloc(num * sizeof(*h));
// no other allocations needed
Alternatively, it may help to use an array of structures, one per sphere, instead of two 2D arrays of numbers. It would certainly make your code clearer, but it might also help give a slight speed boost by improving locality of reference:
struct sphere {
int x, y;
double r, z;
};
struct sphere *spheres = malloc(num * sizeof(*spheres));
Store z2 instead of z, at least for the duration of the computation. This will reduce the number of somewhat-expensive sqrt calls from O(v2) to O(v), supposing you make a single pass at the end to convert all the results to zs, and it will save you O(v2) multiplications, too. (More if you could get away without ever converting from z2 to z.)
Pre-initialize each vh[i][1] value to the radius of sphere i (or the square of the radius if you are exercising the previous option, too), and add j != i to the condition around the inner-loop body.
Sorting the spheres in decreasing order by radius may help you find larger provisional z values earlier, and therefore to make the radius test in the inner loop more effective at culling unnecessary computations.
You might get some improvement by checking each distinct pair only once. That is, for each unordered pair i, j, you can compute the inter-center distance once only, determine from the relative radii which height to check for a possible update, and go from there. The extra logic involved might or might not pay off through a reduction in other computations.
Additionally, if you are doing this for large enough inputs, then you might be able to reduce the wall time consumed by parallelizing the computation.
Note, by the way, that this comment is incorrect:
// (r of sphere #1)**2 = (r of sphere #2)**2 + (distance of two centers)**2
. However, it also not what you are relying upon. What you are relying upon is that if sphere 1 covers the center of sphere 2 at all, then its height, z, above the center of sphere 2 satisfies the relationship
r12 = z2 + d1,22
. That is, where you wrote r of sphere #2 in the comment, you appear to have meant z.
I am building a particle simulation, and I want to display each particle's position as a dot in a 3D scatter plot using MathGL in C (not C++!). I am having trouble with the C interface.
So far I found two interesting examples:
A C++ example that seems to be close to what I want: http://mathgl.sourceforge.net/doc_en/Dots-sample.html (but this is in C++, I have been unable to find the C-equivalent)
This is a piece of C code that constructs a 3D surf plot with dots.
#include <mgl2/mgl_cf.h>
int main()
{
HMGL gr = mgl_create_graph(600,400);
HMDT a,x,y;
a = mgl_create_data_size(30,40,1);
x = mgl_create_data_size(30,1,1);
y = mgl_create_data_size(40,1,1);
mgl_data_modify(a,"pi*(1-2*x)*exp(-4*y^2-4*(2*x-1)^2)",0);
mgl_data_fill(x,-1.,1.,'x');
mgl_data_fill(y,0.,1.,'x');
mgl_rotate(gr,40.,60.,0.);
mgl_set_light(gr,1);
mgl_box(gr,1);
mgl_surf_xy(gr,x,y,a,".","");
mgl_delete_data(a);
mgl_delete_data(y);
mgl_delete_data(x);
mgl_write_frame(gr,"test.png","");
mgl_delete_graph(gr);
return 0;
}
The example 2 is close to what I want to do, but it is annoying that a is not a linear array of just N particles. It also has to take a function to evaluate the values for a (z-axis) whereas I just want to pass the z-coordinate manually for each dot).
My data is just a 1D array of structs, similar to this:
struct particle {
double x, y, z, velocity;
};
How do I plot these particles as dots in a 3D (scatter) plot with MathGL in C? I guess I have to use mgl_dots, but how does it read from my array of values? (I could use velocity as color coding, but that is optional)
I was right about using mgl_dots, and the data can be prepared using mgl_create_data_sizeand mgl_data_put_val, e.g.:
HMDT z,x,y;
int N = 1000;
x = mgl_create_data_size(N,1,1);
z = mgl_create_data_size(N,1,1);
y = mgl_create_data_size(N,1,1);
for(int i=0; i < N; i++) {
// Set position of particle[i]
printf("%lf\n", i/(double) N);
mgl_data_put_val(x, i/(double) N, i, 0, 0);
mgl_data_put_val(y, i/(double) N, i, 0, 0);
mgl_data_put_val(z, i/(double) N, i, 0, 0);
}
I've got an array of strings that I'd like to draw as a giant spiral. I only have a very, very rough idea of where to begin. First, I will probably need to break the strings into an array of individual characters? Next, I will probably need to apply the following geometry in order to generate the spiral shape?
float r = 0;
float theta = 0;
void setup() {
size(200,200);
background(255);
}
void draw() {
float x = r * cos(theta);
float y = r * sin(theta);
noStroke();
fill(0);
ellipse(x+width/2, y+height/2, 6, 6);
theta += 0.01;
r += 0.05;
}
However, I don't know how to step through my array of characters in order to draw them in a spiral-like format. I apologize for the lack of clarity. Any suggestions would be awesome! I'm very new to all of this (clearly).
Your code for creating the spiral is a good idea. One way to create rotated text would be using rotate(), combined with text(). You would have a for loop, iterate through your character array, increment the radius, and draw your text that way. Note that rotate() has a cumulative effect. Something like:
String str = "asdflkkjsahfdlkadshflkahdslkfajsdf";
float radius = 0;
//so we are rotating around the center, rather than (0,0):
translate(width/2, height/2);
for (int i = 0; i < str.length(); i++) {
radius += 2;
// taken out because of non-constant spacing at large radius:
//rotate(0.5);
// this should give constant spacing, no matter the radius
// change 10 to some other number for a different spacing.
rotate(10/radius);
// drawing at (0,radius) because we're drawing onto a rotated canvas
text(str.charAt(i), 0, radius);
}
You may want to have the angle change be a function of radius, because at large radii, the letters are spaced very far apart. One way to do this would be using the equation s = rθ, where s is the arclength (in this case, distance between letters), r is radius, and θ is the angle change. If you want a constant distance between letters, regardless of radius, then θ would have to be proportional to 1/r. And of course, you can tweak the hard-coded values to your liking.
Also: the rotate() and translate() methods are undone at the end of draw(), so if you aren't doing anything after this code, then it's okay to leave it as is. If you do want to draw more stuff after, then you'll have to undo the rotation and translation manually before you draw anything else.
Edit: I just realized that I assumed you wanted the letters to be rotated as well, and not just positioned in a spiral but still oriented normally. In that case, you could use your existing code and replace the ellipse(...) with text(str.charAt(...)...), with appropriate parameters of course.
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
Imagine the picture above represents a 6*6 array of ints where 0 is black.
Is there a quick algorithm to split the non 0 cells into rectangles?
Ideally the check would be contained within a for loop, without creating any other arrays.
for(x = 0; x < 6; x++)
for(y = 0; y < 6; y++)
if(cellIsBottomRightOfRect(x,y)) {
left = getLeft(x,y);
top = getTop(x,y);
printf("Rect: %d,%d %d,%d \n", left, top, x, y);
}
How about using a recursive method which calls itself everytime it encounters a color different than the one it is trying to group at the moment?
Have you thought about using a dynamic programming approach?
Also, I think that a search algorithm (like A*) would work well here (even though it is has exponential time complexity).