OpenGl Implicit Circle function-- incomplete circle - opengl

I am having a little issue drawing a circle. The function draws an almost complete circle and I am just missing a tiny bit of the loop. I am assuming that the issue has something to do with an automatic redraw of something?
Here is the function
for(x = radius; x >= -radius; x -= 0.05) // draw the plot
{
double temp = (radius * radius) - (x * x);
y = sqrt(temp);
glVertex2f(x, y);
}
for(x = -radius; x <= radius; x += 0.05) // draw the plot
{
double temp = (radius * radius) - (x * x);
y = sqrt(temp);
glVertex2f(x, -y);
}
Would any of the other code be helpful?

I think what you're experiencing is just a floating point precision issue. You assume your x values to go to exactly -radius (or radius repsectively) at the end of each loop, which it probably doesn't due to accumulated rounding errors from all the additions.
This is no problem at -radius since its merged with the start of the second loop anyway, but at the end it won't end at radius. Try to make the whole thing a GL_LINE_LOOP instead of a GL_LINE_STRIP to merge the first and last vertices into a line.

Related

gluLookAt Issues

I've been trying to create a roller coaster simulator in OpenGL which uses a series of gluLookAt calls to make the camera 'ride' the roller coaster. The coaster itself is based on a b-spline curve with control points in the coords array. b0(u), b1(u) etc are the blending functions for b-spline curves, with bprime0(u) etc being their derivatives. Here's the relevant part of my code:
for (int i = 0; i <= 10; i++){
for (float u = 0; u <= 1.1; u+=0.1){
x = (b0(u)*coords[(i)%10].x + b1(u)*coords[(i+1)%10].x
+ b2(u)*coords[(i+2)%10].x + b3(u)*coords[(i+3)%10].x)*2.0f;
y = (b0(u)*coords[(i)%10].y + b1(u)*coords[(i+1)%10].y
+ b2(u)*coords[(i+2)%10].y + b3(u)*coords[(i+3)%10].y)*2.0f;
z = (b0(u)*coords[(i)%10].z + b1(u)*coords[(i+1)%10].z
+ b2(u)*coords[(i+2)%10].z + b3(u)*coords[(i+3)%10].z)*2.0f;
xprime = (bprime0(u)*coords[(i)%10].x + bprime1(u)*coords[(i+1)%10].x
+ bprime2(u)*coords[(i+2)%10].x + bprime3(u)*coords[(i+3)%10].x)*-2.0f;
yprime = (b0(u)*coords[(i)%10].y + bprime1(u)*coords[(i+1)%10].y
+ bprime2(u)*coords[(i+2)%10].y + bprime3(u)*coords[(i+3)%10].y)*-2.0f;
zprime = (b0(u)*coords[(i)%10].z + bprime1(u)*coords[(i+1)%10].z
+ bprime2(u)*coords[(i+2)%10].z + bprime3(u)*coords[(i+3)%10].z)*-2.0f;
Coords nvector = {xprime,yprime,zprime};
float magn = sqrt(nvector.x*nvector.x+nvector.y*nvector.y+nvector.z*nvector.z);
nvector.x= nvector.x/magn;
nvector.y= nvector.y/magn;
nvector.z= nvector.z/magn;
glLoadIdentity();
if (rotateCam == 1){
theta+=0.0001;
if (theta > 360) {
theta = 0;
}
gluLookAt(20*cos(theta),15,20*sin(theta),0,0,0,0,1,0);
}//if
else{
printf("%f\t%f\t%f\n", x+xprime,y+yprime,z+zprime);
gluLookAt(x,y+1,z,x+xprime,y+yprime,z+zprime,0,1,0);
}//else
}//for
}//for
The spacebar switches the 'rotateCam' variable, which is supposed to switch between two viewing modes; one which circles the camera around the coaster (the 'if' statement) and one which rides the coaster (the 'else' statement).
Here's the thing: the circling mode works fine, and switching between modes works fine, but the camera is always stationary in the 'ride' mode. The printf statement shows that x, xprime, y, yprime etc are all changing with each timer tick, but the camera never moves.
If more code is needed let me know.
gluLookAt doesn't position the cemera, it only rotates it to the correct angle. After this it is up to you to also translate it. So this should do the trick:
gluLookAt(x,y+1,z,x+xprime,y+yprime,z+zprime,0,1,0);
gluTranslated(x,y+1,z);

Drawing circles on a diagonal line in C++

I've been working on this for about an hour now and I can't figure out what I'm doing wrong. This is the problem statement for the problem:
Draw a series of circles along one diagonal of a window. The circles
should be different colors and each circle should touch (but not
overlap) the one above and below it. Allow the program user to
determine how many circles are to be drawn.
These are some hints that have been given to me:
You will find the geometry involved in putting geometric elements on
the diagonals easier if you make your window square. Rather than using
getmaxheight() and getmaxwidth(), consider using getmaxheight() for
both dimensions.
Don't forget the Pythagorean theorem when working out distances in
your code such as the length of the diagonal. Keep in mind, though,
that the units on the screen are pixels, so fractions in the
computations are not too useful. This is definitely a place for
integer arithmetic.
Use the number of elements you are going to draw (squares, circles,
etc) to divide up the total length into steps for your loops to work
with.
Use for loops to draw figures when you know how many to draw, and what
size they are to be. Determine the count and size before the loop.
So far this is the code that I have created. Inputting 4 circles only draws 3 on screen, with the third one partially off screen. The circles also do not touch, which makes no sense to me because moving the center of the next circle down and over by the length of the diameter should have to the two circles touching. This is the code I have:
#include <graphics.h>
#include <cmath>
#include <iostream>
using namespace std;
int main()
{
int foreColor;
int diagLength;
int radius,diameter;
int centerX = 0, centerY = 0;
int numCircles; // number of circles.
int width, height; // screen width and height
cout << "Enter number of circles: ";
cin >> numCircles;
width = getmaxheight();
height = getmaxheight();
initwindow(width, height, "Circles");
diagLength = sqrt((width * width) + (height * height));
diameter = diagLength / numCircles;
radius = diameter / 2;
centerX = radius;
centerY = radius;
for (int i = 1; i <= numCircles; i++)
{
foreColor = i % 16; // 0 <= foreColor <= 15
setcolor(foreColor);
setfillstyle(i % 12, foreColor); // Set fill style
fillellipse(centerX, centerY, radius, radius);
centerX = centerX + diameter;
centerY = centerY + diameter;
}
getch(); // pause for user
closegraph();
}
Here's a diagram of what I think you want:
The basic problem comes down to determining
What the diameter D of each circle is
Where the center of each circle is.
The diameter is easy. First calculate the length L of the diagonal using Pythagoras' theorem, then divide by the desired number of circles N. Of course, if you need the radius just divide again by 2.
L = Sqrt(Width * Width + Height * Height);
D = L / N;
The trick to working out the position of the circle centers is to realise that the X are evenly spaced along the X axis, and same with the Y coordinates - so you can work out the distances I've labelled Dx and Dy really easily using the same division:
Dx = Width / N;
Dy = Height / N;
From there the center of each circle is easily calculated:
for (i = 0; i < N; i++)
{
centerX = (Dx / 2) + i * Dx;
centerY = (Dy / 2) + i * Dy;
/* Draw the circle at (centerX, centerY) with diameter D */
}
That's all there is to it!
By the way, if you were wondering why your code was drawing circles further apart than they should be, the reason is because you were adding D to centerX and centerY rather than Dx and Dy.

c++ Bresenham's line algorithm draw arc and rotate

I'm searching way to make arc with Bresenham's line algorithm. This algoritm draw perfect circle, but what if i need draw arc (from 0 to Pi) and rotate it for 30 degrees (for example)?
void DrawCircle(HDC hdc,int x0, int y0, int radius)
{
int x = 0;
int y = radius;
int delta = 2 - 2 * radius;
int error = 0;
while(y >= 0) {
//SetPixel(hdc,x0 + x, y0 + y,pencol);
SetPixel(hdc,x0 + x, y0 - y,pencol);
//SetPixel(hdc,x0 - x, y0 + y,pencol);
SetPixel(hdc,x0 - x, y0 - y,pencol);
error = 2 * (delta + y) - 1;
if(delta < 0 && error <= 0) {
++x;
delta += 2 * x + 1;
continue;
}
error = 2 * (delta - x) - 1;
if(delta > 0 && error > 0) {
--y;
delta += 1 - 2 * y;
continue;
}
++x;
delta += 2 * (x - y);
--y;
}
}
To get 1/2 a circle (to pi), only call one of your SetPixel routines. To have your arc rotated 30 degrees requires some trig. You could let the above loop run until your x/y ratio is equal to tan(30 degrees), then start actually drawing until your ratio hits the value at which you want to stop. Not the most efficient way, but it will work. To get it better, you'd need to pre-calculate your starting 4 var values. You could take the values from the above run and plug them in as starting values and that would be very efficient.
Did you get the above algorithm from Michael Abrash's Black Book stuff? If not, I'd google for that as a second point of reference on fast circle/arc drawing.
Well, alas, the ellipses that rip chapter wasn't included in there. Here's something I found on the web that claims to be from Abrash:
/* One of Abrash's ellipse algorithms */
void draw_ellipse(int x, int y, int a, int b, int color)
{
int wx, wy;
int thresh;
int asq = a * a;
int bsq = b * b;
int xa, ya;
draw_pixel(x, y+b, color);
draw_pixel(x, y-b, color);
wx = 0;
wy = b;
xa = 0;
ya = asq * 2 * b;
thresh = asq / 4 - asq * b;
for (;;) {
thresh += xa + bsq;
if (thresh >= 0) {
ya -= asq * 2;
thresh -= ya;
wy--;
}
xa += bsq * 2;
wx++;
if (xa >= ya)
break;
draw_pixel(x+wx, y-wy, color);
draw_pixel(x-wx, y-wy, color);
draw_pixel(x+wx, y+wy, color);
draw_pixel(x-wx, y+wy, color);
}
draw_pixel(x+a, y, color);
draw_pixel(x-a, y, color);
wx = a;
wy = 0;
xa = bsq * 2 * a;
ya = 0;
thresh = bsq / 4 - bsq * a;
for (;;) {
thresh += ya + asq;
if (thresh >= 0) {
xa -= bsq * 2;
thresh = thresh - xa;
wx--;
}
ya += asq * 2;
wy++;
if (ya > xa)
break;
draw_pixel(x+wx, y-wy, color);
draw_pixel(x-wx, y-wy, color);
draw_pixel(x+wx, y+wy, color);
draw_pixel(x-wx, y+wy, color);
}
}
The idea being you draw an 8th of the circle at a time x4 and then flip to get the other 8ths drawn. Still doesn't directly answer your question though. Working on that...
Again, your code above should work, you just need to control the starting and ending conditions carefully. The y >= 0 needs to become whatever the y would be upon finishing your 'arc' length and the starting values need to be calculated to be the start of your arc.
This will not be a straight forward task with things as they are. Might just be easier to use a floating point routine instead. The math is much more straight forward and processors tend to handle them better now than when these integer routines were crafted.
If you don't need for sure Bresenham, there is a fast step method introduced in this SO post, where you can set center point, starting point and arc angle. It doesn't need stopping criterion, because it is already included in algorithm (by arc angle). What makes it fast is the precalculation of tangential and radial movement factors and the actual loop has no trig function calls, only multiply, add and subtract.
AFAIK there is three types of methods:
A) Incremental like Bresenham
B) Subdivide method like this
C) Step (or segment) method
I'll take an slow example of step method (don't use this if speed is important):
// I know the question is tagged c++, but the idea comes clear in javascript
var start_angle = 0.5, end_angle = 1.1, r = 30;
for(var i = start_angle; i < end_angle; i = i + 0.05)
{
drawpixel(x: 50 + Math.cos(i) * r, y: 100 + Math.sin(i) * r); // center point is (x = 50, y = 100)
}
The slowness comes from cos and sin which are repeated (unnecessarily) in loop. This can be solved by precalculating cos and sin as described in the above mentioned SO post. This means huge speedup (average 12x in top5 javascript engines).
I made a non-full-comparable speedtest of various circle and arc drawing algorithms. The Bresenham is fast, but the starting and stopping criterion logic need to be added, which slows down the algo a little. If you really need Bresenham and arc, I have no ready solution for this and not found such yet. It surely is possible. By the way, the step method using precalculated trigs is not so bad in performance compared to Bresenham (in javascript at least). Please test in c++ and report.

Bullet algorithm having trouble with rotation on the X

Here is what I'm trying to do. I'm trying to make a bullet out of the center of the screen. I have an x and y rotation angle. The problem is the Y (which is modified by rotation on the x) is really not working as intended. Here is what I have.
float yrotrad, xrotrad;
yrotrad = (Camera.roty / 180.0f * 3.141592654f);
xrotrad = (Camera.rotx / 180.0f * 3.141592654f);
Vertex3f Pos;
// get camera position
pls.x = Camera.x;
pls.y = Camera.y;
pls.z = Camera.z;
for(float i = 0; i < 60; i++)
{
//add the rotation vector
pls.x += float(sin(yrotrad)) ;
pls.z -= float(cos(yrotrad)) ;
pls.y += float(sin(twopi - xrotrad));
//translate camera coords to cube coords
Pos.x = ceil(pls.x / 3);
Pos.y = ceil((pls.y) / 3);
Pos.z = ceil(pls.z / 3);
if(!CubeIsEmpty(Pos.x,Pos.y,Pos.z)) //remove first cube that made contact
{
delete GetCube(Pos.x,Pos.y,Pos.z);
SetCube(0,Pos.x,Pos.y,Pos.z);
return;
}
}
This is almost identical to how I move the player, I add the directional vector to the camera then find which cube the player is on. If I remove the pls.y += float(sin(twopi - xrotrad)); then I clearly see that on the X and Z, everything is pointing as it should. When I add pls.y += float(sin(twopi - xrotrad)); then it almost works, but not quite, what I observed from rendering out spheres of the trajector is that the furthur up or down I look, the more offset it becomes rather than stay alligned to the camera's center. What am I doing wrong?
Thanks
What basically happens is very difficult to explain, I'd expect the bullet at time 0 to always be at the center of the screen, but it behaves oddly. If i'm looking straight at the horizon to +- 20 degrees upward its fine but then it starts not following any more.
I set up my matrix like this:
void CCubeGame::SetCameraMatrix()
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(Camera.rotx,1,0,0);
glRotatef(Camera.roty,0,1,0);
glRotatef(Camera.rotz,0,0,1);
glTranslatef(-Camera.x , -Camera.y,-Camera.z );
}
and change the angle like this:
void CCubeGame::MouseMove(int x, int y)
{
if(!isTrapped)
return;
int diffx = x-lastMouse.x;
int diffy = y-lastMouse.y;
lastMouse.x = x;
lastMouse.y = y;
Camera.rotx += (float) diffy * 0.2;
Camera.roty += (float) diffx * 0.2;
if(Camera.rotx > 90)
{
Camera.rotx = 90;
}
if(Camera.rotx < -90)
{
Camera.rotx = -90;
}
if(isTrapped)
if (fabs(ScreenDimensions.x/2 - x) > 1 || fabs(ScreenDimensions.y/2 - y) > 1) {
resetPointer();
}
}
You need to scale X and Z by cos(xradrot). (In other words, multiply by cos(xradrot)).
Imagine you're pointing straight down the Z axis but looking straight up. You don't want the bullet to shoot down the Z axis at all, this is why you need to scale it. (It's basically the same thing that you're doing between X and Z, but now doing it on the XZ vector and Y.)
pls.x += float(sin(yrotrad)*cos(xrotrad)) ;
pls.z -= float(cos(yrotrad)*cos(xrotrad)) ;
pls.y += float(sin(twopi - xrotrad));

How to draw an Arc in OpenGL

While making a little Pong game in C++ OpenGL, I decided it'd be fun to create arcs (semi-circles) when stuff bounces. I decided to skip Bezier curves for the moment and just go with straight algebra, but I didn't get far. My algebra follows a simple quadratic function (y = +- sqrt(mx+c)).
This little excerpt is just an example I've yet to fully parameterize, I just wanted to see how it would look. When I draw this, however, it gives me a straight vertical line where the line's tangent line approaches -1.0 / 1.0.
Is this a limitation of the GL_LINE_STRIP style or is there an easier way to draw semi-circles / arcs? Or did I just completely miss something obvious?
void Ball::drawBounce()
{ float piecesToDraw = 100.0f;
float arcWidth = 10.0f;
float arcAngle = 4.0f;
glBegin(GL_LINE_STRIP);
for (float i = 0.0f; i < piecesToDraw; i += 1.0f) // Positive Half
{ float currentX = (i / piecesToDraw) * arcWidth;
glVertex2f(currentX, sqrtf((-currentX * arcAngle)+ arcWidth));
}
for (float j = piecesToDraw; j > 0.0f; j -= 1.0f) // Negative half (go backwards in X direction now)
{ float currentX = (j / piecesToDraw) * arcWidth;
glVertex2f(currentX, -sqrtf((-currentX * arcAngle) + arcWidth));
}
glEnd();
}
Thanks in advance.
What is the purpose of sqrtf((-currentX * arcAngle)+ arcWidth)? When i>25, that expression becomes imaginary. The proper way of doing this would be using sin()/cos() to generate the X and Y coordinates for a semi-circle as stated in your question. If you want to use a parabola instead, the cleaner way would be to calculate y=H-H(x/W)^2