calculate sphere in openGL resulted the circle does not aligned - c++

I want to make a sphere without the gluSphere method, and I try to calculate the sphere with this code
void drawCircle(double x, double y, double r)
{
glBegin( GL_QUAD_STRIP );
for(int i=0;i<=360;i++){
glVertex3d(x+sin(i)*r,y+cos(i)*r,-5.0);
}
glEnd();
}
void drawSphere(double x,double y,double r){
glLoadIdentity();
glColor3d(1,0,0);
for(int j=0;j<180;j++){
glTranslated(0,0,r/180);
drawCircle(x,y,r*sin(j));
}
}
The result was like this
But the result was the circle that I made isn't aligned well. Is there any proper calculation so I can make the sphere right?

There is a difference between a Sphere and a Circle. a Circle is a 2 dimensional shape and Sphere is its 3D counterpart. from your code you are not generating points for a sphere but for a cylinder as the z is constant i.e. -0.5. for Sphere all 3 should change within the ranges
if the center is at (xc, yc, zc) then
x => (0-xc) < x < (0+xc)
y => (0-yc) < y < (0+yc)
z => (0-zc) < z < (0+zc)
A sphere may be defined parametrically in terms of (u,v)
x = xo + r cos(theta) cos(phi)
y = yo + r cos(theta) sin(phi)
z = zo + r sin(theta)
Your points should be a the valid combination of x, y z. that means your points can be generated using 3 loops. Only then you would have correct points for sphere.
Also since you ar eusing QuadStrip, the array you pass must have the order of points in counter clockwise or you will not be able to get the correct shape.
Instead of using sin() & cos() you should use the sphere equation: x*x + y*y + z*z = c*c

I agree with #SimpleFellow that another approach would be better. But let me show you what else is not quite how you wanted it in your code.
Your main problem is that you pass degrees to the sin and cos functions instead of radians.
The easiest remedy is to just define a function deg2rad or functions like
double sind(double val){return std::sin(val*M_PI / 180.0);}
double cosd(double val){return std::cos(val*M_PI / 180.0);}
Also, the distance between rings should be
//glTranslated(0,0,r/180); //equidistance will give you something like a pyramid
glTranslated(0, 0, r*(cosd(j)-cosd(j-1));
then the result from your code looks something like this:
When you reduce the sample points you see what's happening:
Then you'll see that you're connecting 4 successive points in a ring to a quad, which is not what you want, so if you change glBegin( GL_QUAD_STRIP ); to glBegin( GL_LINE_STRIP ) you'll see this:
If you increase the points to 360 again then you'll have this:
So now you have a sphere made of circles, but I assume that you wanted a sphere with a surface, for that have a look at this question.

Related

How to calculate how many points with coordinates (x;y) is in/on/outside of circle

I have program to write in my C++ course. In coordinate plane we have circle with radius R.Circle center is at the point (xc,yc). Also I have n point with coordinates( for example n=2 and coordinates is (1;1) (-1;-1). I need to calculate how many points there is in a circle, on it and outside of it.. Please help :)
You need to calculate distance between circle center and the point. The formula of distance between two points is:
d = sqrt( (xc - x)^2 + (yc - y)^2 )
where: (xc, yc) - coordinates of circle center, (x, y) - coordinates of your point.
if the distance is greater then radius then point is outside the circle (d > R)
Then you need repeat this for n points and remember how many of them are inside and how many are outside. and that's all.
Now you have an algorithm you can try to code it!
Simple math...
Surface of a square is calculated by S = pi*r^2
given r in pixels, S would come in pixels...
it is worthy to note, that this method is approximation, because it is not over a discrete plane
In order to be more precise (though, considerably slower):
refer to #Sandro answer, and check the distance to each point on your plane..
with two optimizations that you may want to consider:
exclude the outer Bounding box
You need to check only the pixels x in [xc - r, xc + r] U y in [yc - r, yc + r]
automatically include inscribed square
You can include every pixel in x in (xc - sqrt(2)r, xc + sqrt(2)r) U (yc - sqrt(2)r, yc + sqrt(2)r)
references:
Circles Inscribed in Squares
Squares Circumscribed by Circles
Equation of a circle: R^2 = (xc - x)^2 + (yc-y)^2 where (xc, yc) are coordinates of circle center. (x, y) - coordinates of point, R - radius. So:
double distance = sqrt((xc - x)*(xc - x) + (yc-y)*(yc-y));
if (distance < R)
{
// inside
}
else if(distance > R)
{
// outside
}
else
{
// on circle
}

Algorithm to find points along a sphere that do not intersect with other spheres with a specific radius

In 3D cartesian space, I have a sphere at XYZ of a radius of 240 (main sphere), within that sphere are many other spheres of radius 100 (other objects). I need to be able to find points along the boundary of the border sphere, that are not intersected by ANY of the other objects inside it.
For simplicity, we can say the main sphere is at 0 0 0 with a radius of 240, and there are ~33 objects inside, each with a radius of 100 at different coordinates.
Mostly writing in Lua, but C/C++ is fine as well.
Any help is appreciated, even just pointing me in the right direction on how to solve it mathematically.
Edit: Using the links and info provided by David Eisenstat below, this is the code I am using.
It /seems/ to work, but have not had a chance to fully test it.
function randomSpherePoint(x, y, z, r)
local acos, sin, cos = math.acos, math.sin, math.cos
local u, v = math.random(), math.random()
local theta = 2 * PI * u
local phi = acos(2 * v - 1)
local px = x + (r * sin(phi) * cos(theta))
local py = y + (r * sin(phi) * sin(theta))
local pz = z + (r * cos(phi))
return px, py, pz
end
function fun_bordercheck()
local results = { }
local bx, by, bz, radius = -9197.944, 0, 0, 240 -- Border location and radius
for i = 1, 1000 do -- 1000 random points
local px, py, pz = randomSpherePoint(bx, by, bz, radius)
local n = 0
while (n < #space_objs) do
n = n + 1
if (xyz2range(space_objs[n].x, space_objs[n].y, space_objs[n].z, px, py, pz) <=100) then
break -- It hits, no point in checking any other objects. Skip to next random point
end
if (n == #space_objs) then -- We reached the end of the list. If we got this far, this is a possible location. Store it
results[#results+1] = { x = px, y = py, z = pz }
end
end -- while()
end -- for()
if (#results < 1) then
print("No points found.")
return
end
print(string.format("BorderCheck(): Found %d results.", #results))
for i = 1, #results do
Note(string.format("Point %d: %.3f %.3f %.3f", i, results[i].x, results[i].y, results[i].z))
end
end -- function()
Probably the simplest approach is to generate points at random on the boundary of the main sphere and test them for intersections with the excluded balls. Proximity structures (e.g., kd-trees) would help the intersection tests asymptotically but hardly seem worth it in prospect for 33 objects. Computing a Voronoi diagram also could be a solution, but a Voronoi diagram of circularly bounded regions on a sphere would be an unusual setting and likely require a fair amount of new, intricate code.
create map of main sphere surface
for example:
const int na=128;
const int nb=256;
int map[na][nb];
so map[a][b] is surface area around a (latitude), b (longitude)
test all of your small spheres if they intersect main sphere
if main sphere is at (0,0,0) wtih radius R
then sphere at P (x,y,z) with radius r
intersect main sphere if
if ((|P|<=R+r)&&(|P|>=R-r))
in that case compute latitude ,longitude from P (see spherical coordinate system)
remap it to a,b from radians to na,nb sizes
and mark map[a][b] (plus its surrounding up to radius r) as intersected
after all spheres are tested you have map of non intersecting areas on surface

Rotate tetris blocks at runtime

I have a class tetronimo (a tetris block) that has four QRect types (named first, second, third, fourth respectively). I draw each tetronimo using a build_tetronimo_L type functions.
These build the tetronimo in a certain direction, but as in tetris you're supposed to be able to rotate the tetronimo's, I'm trying to rotate a tetronimo by rotating each individual square of the tetronimo.
I have found the following formula to apply to each (x, y) coordinate of a particular square.
newx = cos(angle) * oldx - sin(angle) * oldy
newy = sin(angle) * oldx + cos(angle) * oldy
Now, the QRect type of Qt, does only seem to have a setCoords function that takes the (x, y) coordinates of top-left and bottom-right points of the respective square.
I have here an example (which doesn't seem to produce the correct result) of rotating the first two squares in my tetronimo.
Can anyone tell me how I'm supposed to rotate these squares correctly, using runtime rotation calculation?
void tetromino::rotate(double angle) // angle in degrees
{
std::map<std::string, rect_coords> coords = get_coordinates();
// FIRST SQUARE
rect_coords first_coords = coords["first"];
//top left x and y
int newx_first_tl = (cos(to_radians(angle)) * first_coords.top_left_x) - (sin(to_radians(angle)) * first_coords.top_left_y);
int newy_first_tl = (sin(to_radians(angle)) * first_coords.top_left_x) + (cos(to_radians(angle)) * first_coords.top_left_y);
//bottom right x and y
int newx_first_bl = (cos(to_radians(angle)) * first_coords.bottom_right_x) - (sin(to_radians(angle)) * first_coords.bottom_right_y);
int newy_first_bl = (cos(to_radians(angle)) * first_coords.bottom_right_x) + (sin(to_radians(angle)) * first_coords.bottom_right_y);
//CHANGE COORDINATES
first->setCoords( newx_first_tl, newy_first_tl, newx_first_tl + tetro_size,newy_first_tl - tetro_size);
//SECOND SQUARE
rect_coords second_coords = coords["second"];
int newx_second_tl = (cos(to_radians(angle)) * second_coords.top_left_x) - (sin(to_radians(angle)) * second_coords.top_left_y);
int newy_second_tl = (sin(to_radians(angle)) * second_coords.top_left_x) + (cos(to_radians(angle)) * second_coords.top_left_y);
//CHANGE COORDINATES
second->setCoords(newx_second_tl, newy_second_tl, newx_second_tl - tetro_size, newy_second_tl + tetro_size);
first and second are QRect types. rect_coords is just a struct with four ints in it, that store the coordinates of the squares.
The first square and second square calculations are different, as I was playing around trying to figure it out.
I hope someone can help me figure this out?
(Yes, I can do this much simpler, but I'm trying to learn from this)
It seems more like a math question than a programming question. Just plug in values like 90 degrees for the angle to figure this out. For 90 degrees, a point (x,y) is mapped to (-y, x). You probably don't want to rotate around the origin but around a certain pivot point c.x, c.y. For that you need to translate first, then rotate, then translate back:
(x,y) := (x-c.x, y-c.y) // translate into coo system w/ origin at c
(x,y) := (-y, x) // rotate
(x,y) := (x+c.x, y+c.y) // translate into original coo system
Before rotating you have to translate so that the piece is centered in the origin:
Translate your block centering it to 0, 0
Rotate the block
Translate again the center of the block to x, y
If you rotate without translating you will rotate always around 0, 0 but since the block is not centered it will be rotated around the center. To center your block is quite simple:
For each point, compute the median of X and Y, let's call it m
Subtract m.X and m.Y to the coordinates of all points
Rotate
Add again m.X and m.Y to points.
Of course you can use linear algebra and vector * matrix multiplication but maybe it is too much :)
Translation
Let's say we have a segment with coordinates A(3,5) B(10,15).
If you want to rotate it around its center, we first translate it to our origin. Let's compute mx and my:
mx = (10 - 3) / 2
my = (15 - 5) / 2
Now we compute points A1 and B1 translating the segment so it is centered to the origin:
A1(A.X - mx, A.Y - my)
B1(B.X - mx, B.Y - my)
Now we can perform our rotation of A1 and B1 (you know how).
Then we have to translate again to the original position:
A = (rotatedA1.X + mx, rotatedA1.y + my)
B = (rotatedB1.X + mx, rotatedB1.y + my)
If instead of having two points you have n points you have of course do everything for n points.
You could use Qt Graphics View which does all the geometric calculations for you.
Or are you just wanting to learn basic linear geometrical transformations? Then reading a math textbook would probably be more appropriate than coding.

How to orbit around the Z-axis in 3D

I'm primarily a Flash AS3 dev, but I'm jumping into openframeworks and having trouble using 3D (these examples are in AS)
In 2D you can simulate an object orbiting a point by using Math.Sin() and Math.cos(), like so
function update(event:Event):void
{
dot.x = xCenter + Math.cos(angle*Math.PI/180) * range;
dot.y = yCenter + Math.sin(angle*Math.PI/180) * range;
angle+=speed;
}
I am wondering how I would translate this into a 3D orbit, if I wanted to also orbit in the third dimension.
function update(event:Event):void
{
...
dot.z = zCenter + Math.sin(angle*Math.PI/180) * range;
// is this valid?
}
An help is greatly appreciated.
If you are orbiting around the z-axis, you are leaving your z-coordinate fixed and changing your x- and y-coordinates. So your first code sample is what you are looking for.
To rotate around the x-axis (or y-axes), just replace x (or y) with z. Use Cos on whichever axis you want to be 0-degrees; the choice is arbitrary.
If what you actually want is to orbit an object around a point in 3d-space, you'll need two angles to describe the orbit: its elevation angle and its inclination angle. See here and here.
For reference, those equations are (where θ and φ are your angles)
x = x0 + r sin(θ) cos(φ)
y = y0 + r sin(θ) sin(φ)
z = z0 + r cos(θ)
If you are orbiting around Z axis, then you just do your first code, and leave Z coordinate as is.
I would pick two unit perpendicular vectors v, w that define the plane in which to orbit, then loop over the angle and pick the proper ratio of these vectors v and w to build your vector p = av + bw.
More details are coming.
EDIT:
This might be of help
http://en.wikipedia.org/wiki/Orbit_equation
EDIT: I think it is actually
center + sin(angle) * v * radius1 + cos(angle) * w * radius2
Here v and w are your unit vectors for the circle.
In 2D they were (1,0) and (0,1).
In 3D you will need to compute them - depends on orientation of the plane.
If you set radius1 = radius 2, you will get a circle. Otherwise, you should get an ellipse.
If you just want the orbit to happen at an angled plane and don't mind it being elliptic you can just do something like z = 0.2*x + 0.2*y, or any combination you fancy, after you have determined the x and y coordinates.

gluProject on NDS?

I've been struggling with this for a good while now. I'm trying to determine the screen coordinates of the vertexes in a model on the screen of my NDS using devKitPro. The library seems to implement some functionality of OpenGL, but in particular, the gluProject function is missing, which would (I assume) allow me to do just exactly that, easily.
I've been trying for a good while now to calculate the screen coordinates manually using the projection matricies that are stored in the DS's registers, but I haven't been having much luck, even when trying to build the projection matrix from scratch based on OpenGL's documentation. Here is the code I'm trying to use:
void get2DPoint(v16 x, v16 y, v16 z, float &result_x, float &result_y)
{
//Wait for the graphics engine to be ready
/*while (*(int*)(0x04000600) & BIT(27))
continue;*/
//Read in the matrix that we're currently transforming with
double currentMatrix[4][4]; int i;
for (i = 0; i < 16; i++)
currentMatrix[0][i] =
(double(((int*)0x04000640)[i]))/(double(1<<12));
//Now this hurts-- take that matrix, and multiply it by the projection matrix, so we obtain
//proper screen coordinates.
double f = 1.0 / tan(70.0/2.0);
double aspect = 256.0/192.0;
double zNear = 0.1;
double zFar = 40.0;
double projectionMatrix[4][4] =
{
{ (f/aspect), 0.0, 0.0, 0.0 },
{ 0.0, f, 0.0, 0.0 },
{ 0.0, 0.0, ((zFar + zNear) / (zNear - zFar)), ((2*zFar*zNear)/(zNear - zFar)) },
{ 0.0, 0.0, -1.0, 0.0 },
};
double finalMatrix[4][4];
//Ugh...
int mx = 0; int my = 0;
for (my = 0; my < 4; my++)
for (mx = 0; mx < 4; mx++)
finalMatrix[mx][my] =
currentMatrix[my][0] * projectionMatrix[0][mx] +
currentMatrix[my][1] * projectionMatrix[1][mx] +
currentMatrix[my][2] * projectionMatrix[2][mx] +
currentMatrix[my][3] * projectionMatrix[3][mx] ;
double dx = ((double)x) / (double(1<<12));
double dy = ((double)y) / (double(1<<12));
double dz = ((double)z) / (double(1<<12));
result_x = dx*finalMatrix[0][0] + dy*finalMatrix[0][1] + dz*finalMatrix[0][2] + finalMatrix[0][3];
result_y = dx*finalMatrix[1][0] + dy*finalMatrix[1][1] + dz*finalMatrix[1][2] + finalMatrix[1][3];
result_x = ((result_x*1.0) + 4.0)*32.0;
result_y = ((result_y*1.0) + 4.0)*32.0;
printf("Result: %f, %f\n", result_x, result_y);
}
There are lots of shifts involved, the DS works internally using fixed point notation and I need to convert that to doubles to work with. What I'm getting seems to be somewhat correct-- the pixels are translated perfectly if I'm using a flat quad that's facing the screen, but the rotation is wonky. Also, since I'm going by the projection matrix (which accounts for the screen width/height?) the last steps I'm needing to use don't seem right at all. Shouldn't the projection matrix be accomplishing the step up to screen resolution for me?
I'm rather new to all of this, I've got a fair grasp on matrix math, but I'm not as skilled as I would like to be in 3D graphics. Does anyone here know a way, given the 3D, non-transformed coordinates of a model's vertexes, and also given the matricies which will be applied to it, to actually come up with the screen coordinates, without using OpenGL's gluProject function? Can you see something blatantly obvious that I'm missing in my code? (I'll clarify when possible, I know it's rough, this is a prototype I'm working on, cleanliness isn't a high priority)
Thanks a bunch!
PS: As I understand it, currentMatrix, which I pull from the DS's registers, should be giving me the combined projection, translation, and rotation matrix, as it should be the exact matrix that's going to be used for the translation by the DS's own hardware, at least according to the specs at GBATEK. In practise, it doesn't seem to actually have the projection coordinates applied to it, which I suppose has something to do with my issues. But I'm not sure, as calculating the projection myself isn't generating different results.
That is almost correct.
The correct steps are:
Multiply Modelview with Projection matrix (as you've already did).
Extend your 3D vertex to a homogeneous coordinate by adding a W-component with value 1. E.g your (x,y,z)-vector becomes (x,y,z,w) with w = 1.
Multiply this vector with the matrix product. Your matrix should be 4x4 and your vector of size 4. The result will be a vector of size4 as well (don't drop w yet!). The result of this multiplication is your vector in clip-space. FYI: You can already do a couple of very useful things here with this vector: Test if the point is on the screen. The six conditions are:
x &lt -w : Point is outside the screen (left of the viewport)
x &gt W : Point is outside the screen (right of the viewport)
y &lt -w : Point is outside the screen (above the viewport)
y &gt w : Point is outside the screen (below the viewport)
z &lt -w : Point is outside the screen (beyond znear)
z &gt w : Point is outside the screen (beyond zfar)
Project your point into 2D space. To do this divide x and y by w:
x' = x / w;
y' = y / w;
If you're interested in the depth-value (e.g. what gets written to the zbuffer) you can project z as well:
z' = z / w
Note that the previous step won't work if w is zero. This case happends if your point is equal to the camera position. The best you could do in this case is to set x' and y' to zero. (will move the point into the center of the screen in the next step..).
Final Step: Get the OpenGL viewport coordinates and apply it:
x_screen = viewport_left + (x' + 1) * viewport_width * 0.5;
y_screen = viewport_top + (y' + 1) * viewport_height * 0.5;
Important: The y coordinate of your screen may be upside down. Contrary to most other graphic APIs in OpenGL y=0 denotes the bottom of the screen.
That's all.
I'll add some more thoughts to Nils' thorough answer.
don't use doubles. I'm not familiar with NDS, but I doubt it's got any hardware for double math.
I also doubt model view and projection are not already multiplied if you are reading the hardware registers. I have yet to see a hardware platform that does not use the full MVP in the registers directly.
the matrix storage into registers may or may not be in the same order as OpenGL. if they are not, the multiplication matrix-vector needs to be done in the other order.