Related
i have an assignment for Programming class.
i have finished 80 percent of it, i am not able to complete the last part.
We have to find the distance between the shore and the boat(Point C) And Coordinates Of The Boat (Point C).
We are given (X,Y) coordinates And Angles of Points A and B.
Given A(76,316) B(57,516) Angle A = 17° and B = 17° Angle.
So Far i found AB= 200.9 AC= 105.04 BC = 105.04 C = 146° And the distance between the shore and the boat d = 30.71.
I tried everything but i am not able to find the Coordinates of Point C (Boat).
The Output is also Given : d = 30.71, Coordinates of C = C(97.07,418.90)
Please help me to find coordinates of Point C.
#include <stdio.h>
#include <math.h>
float radian(int degree);
float get_watchtowers_distance(int x1,int y1,int x2,int y2);
float get_boat_distance(float d,int alpha,int beta);
int main(){
get_watchtowers_distance(76,316,57,516);
get_boat_distance(200.90,17,17);
}
float radian(int degree){
return degree * (M_PI/180);
}
float get_watchtowers_distance(int x1,int y1,int x2,int y2){
return sqrtf(powf(x2-x1,2.0f)+powf(y2-y1,2.0f));
}
float get_boat_distance(float d,int alpha,int beta){
float a,b,c = 180 - (float)alpha - (float)beta;
a = (float)radian(alpha);
b = (float)radian(beta);
c = (float)radian(c);
printf("%.2f %.2f %.2f\n",a,b,c);
float B,A = d*sinf(a)/sinf(c);
B = d*sinf(b)/sinf(c);
float dist,area = 1.0f/2.0f*A*B*sinf(c);
dist = 2*area/d;
printf("AC Distance : %.2f , BC distance : %.2f\n",A,B);
printf("Boat Distance : %.2f\n", dist);
return dist;
}
Simpler approach to find d distance. We can express lengths of the left and right parts of base through d and cotangents
aa = d * ctg(alpha)
bb = d * ctg(beta)
aa + bb = l
d * (ctg(alpha) + ctg(beta)) = l
d = l / (ctg(alpha) + ctg(beta)) =
= l * sin(alpha) * sin(beta) / sin(alpha+beta)
Now you can find C coordinates using normalized vector ab and perpendicular component
abx = (b.x - a.x) / l
aby = (b.y - a.y) / l
aalen = d / tg(alpha)
c.x = a.x + abx * aalen - aby * d
c.y = a.y + aby * aalen + abx * d
There you go I have written some code for your question..
float get_coordinates(int x1, int y1, int x2, int y2, float alpha, float beta){
float a_angle_alpha, b_angle_beta, c_angle_delta;
c_angle_delta = 180 - (float)alpha - (float)beta;
printf("Alpha Angle in Degrees = %.2f\nBeta Angle in Degrees = %.2f\nDelta Angle in Degrees = %.2f\n", alpha, beta, c_angle_delta);
a_angle_alpha = (float)radian(alpha);
b_angle_beta = (float)radian(beta);
c_angle_delta = (float)radian(c_angle_delta);
printf("Alpha in radiance: %.2f\nBeta in radiance: %.2f\nDelta in radiance: %.2f\n", a_angle_alpha, b_angle_beta, c_angle_delta);
int u, v;
float d;
u = x2 - x1;
v = y2 -y1;
printf("u = %.d\nv = %.d\n", u, v);
float d1_distance_AB, d2_distance_BC, d3_distance_AC;
d1_distance_AB = sqrtf((u*u)+ (v*v));
d2_distance_BC = d1_distance_AB*sinf(b_angle_beta)/sinf(c_angle_delta);
d3_distance_AC = d1_distance_AB*sinf(a_angle_alpha)/sinf(c_angle_delta);
printf("Distance between A and B: %.2f\nDistance between B and C: %.2f\nDistance between A and C: %.2f\n",d1_distance_AB, d2_distance_BC, d3_distance_AC);
float RHS1, RHS2;
float x3, y3;
RHS1 = ((x1 * u) + (y1 * v) + (d2_distance_BC * d1_distance_AB * cosf(a_angle_alpha)));
RHS2 = ((y2 * u) - (x2 * v) - (d2_distance_BC * d1_distance_AB * sinf(a_angle_alpha)));
x3 = ((1 / (d1_distance_AB * d1_distance_AB)) * ((u * RHS1) - (v * RHS2)));
y3 = ((1 / (d1_distance_AB * d1_distance_AB)) * ((v * RHS1) + (u * RHS2)));
printf("Coordinates of Boat at point C is = %.2f:%.2f (x:y)", x3, y3);
float coordinates[2] = {x3,y3};
return coordinates;
}
Full Code:
#include <stdio.h>
#include <math.h>
float radian(int degree);
float get_watchtowers_distance(int x1,int y1,int x2,int y2);
float get_boat_distance(float d,int alpha,int beta);
float get_coordinates(int x1, int y1, int x2, int y2, float alpha, float beta);
int main(){
get_watchtowers_distance(76,316,57,516);
get_boat_distance(200.90,17,17);
get_coordinates(76,316,57,516,17,17);
}
float radian(int degree){
return degree * (M_PI/180);
}
float get_watchtowers_distance(int x1,int y1,int x2,int y2){
return sqrtf(powf(x2-x1,2.0f)+powf(y2-y1,2.0f));
}
float get_boat_distance(float d,int alpha,int beta){
float a,b,c = 180 - (float)alpha - (float)beta;
a = (float)radian(alpha);
b = (float)radian(beta);
c = (float)radian(c);
printf("%.2f %.2f %.2f\n", a, b, c);
float B,A = d*sinf(a)/sinf(c);
B = d*sinf(b)/sinf(c);
float dist,area = 1.0f/2.0f*A*B*sinf(c);
dist = 2*area/d;
printf("AC Distance : %.2f , BC distance : %.2f\n",A,B);
printf("Boat Distance : %.2f\n", dist);
return dist;
}
float get_coordinates(int x1, int y1, int x2, int y2, float alpha, float beta){
float a_angle_alpha, b_angle_beta, c_angle_delta;
c_angle_delta = 180 - (float)alpha - (float)beta;
printf("Alpha Angle in Degrees = %.2f\nBeta Angle in Degrees = %.2f\nDelta Angle in Degrees = %.2f\n", alpha, beta, c_angle_delta);
a_angle_alpha = (float)radian(alpha);
b_angle_beta = (float)radian(beta);
c_angle_delta = (float)radian(c_angle_delta);
printf("Alpha in radiance: %.2f\nBeta in radiance: %.2f\nDelta in radiance: %.2f\n", a_angle_alpha, b_angle_beta, c_angle_delta);
int u, v;
float d;
u = x2 - x1;
v = y2 -y1;
printf("u = %.d\nv = %.d\n", u, v);
float d1_distance_AB, d2_distance_BC, d3_distance_AC;
d1_distance_AB = sqrtf((u*u)+ (v*v));
d2_distance_BC = d1_distance_AB*sinf(b_angle_beta)/sinf(c_angle_delta);
d3_distance_AC = d1_distance_AB*sinf(a_angle_alpha)/sinf(c_angle_delta);
printf("Distance between A and B: %.2f\nDistance between B and C: %.2f\nDistance between A and C: %.2f\n",d1_distance_AB, d2_distance_BC, d3_distance_AC);
float RHS1, RHS2;
float x3, y3;
RHS1 = ((x1 * u) + (y1 * v) + (d2_distance_BC * d1_distance_AB * cosf(a_angle_alpha)));
RHS2 = ((y2 * u) - (x2 * v) - (d2_distance_BC * d1_distance_AB * sinf(a_angle_alpha)));
x3 = ((1 / (d1_distance_AB * d1_distance_AB)) * ((u * RHS1) - (v * RHS2)));
y3 = ((1 / (d1_distance_AB * d1_distance_AB)) * ((v * RHS1) + (u * RHS2)));
printf("Coordinates of Boat at point C is = %.2f:%.2f (x:y)", x3, y3);
float coordinates[2] = {x3,y3};
return coordinates;
}
Output:
0.30 0.30 2.55
AC Distance : 105.04 , BC distance : 105.04
Boat Distance : 30.71
Alpha Angle in Degrees = 17.00
Beta Angle in Degrees = 17.00
Delta Angle in Degrees = 146.00
u = -19
v = 200
Distance between A and B: 200.90
Distance between B and C: 105.04
Distance between A and C: 105.04
Coordinates of Boat at point C is = 97.07:418.90 (x:y)
To find the distance d directly without determining point C, first, you can calculate the area S of the triangle in two ways.
S = 0.5 * l * d
S = 0.5 * l * l * sin(a) * sin(b) / sin(a + b)
Equating the two and canceling out 0.5 * l gives d = l * sin(a) * sin(b) / sin(a + b).
I'm using SDL2.
The only way I can find to draw a shape is with the line, rect and pixel functions, as explained here.
Apart from using trig or the "equation of a circle", how could I draw a curve? How about general vector graphics?
Is SDL an appropriate starting point or should I look elsewhere?
This is an example of the Midpoint Circle Algorithm as referenced above. It doesn't require a math library and is very fast. (Renders in about 500 microseconds) This is what Windows uses/used to rasterize circles.
void DrawCircle(SDL_Renderer * renderer, int32_t centreX, int32_t centreY, int32_t radius)
{
const int32_t diameter = (radius * 2);
int32_t x = (radius - 1);
int32_t y = 0;
int32_t tx = 1;
int32_t ty = 1;
int32_t error = (tx - diameter);
while (x >= y)
{
// Each of the following renders an octant of the circle
SDL_RenderDrawPoint(renderer, centreX + x, centreY - y);
SDL_RenderDrawPoint(renderer, centreX + x, centreY + y);
SDL_RenderDrawPoint(renderer, centreX - x, centreY - y);
SDL_RenderDrawPoint(renderer, centreX - x, centreY + y);
SDL_RenderDrawPoint(renderer, centreX + y, centreY - x);
SDL_RenderDrawPoint(renderer, centreX + y, centreY + x);
SDL_RenderDrawPoint(renderer, centreX - y, centreY - x);
SDL_RenderDrawPoint(renderer, centreX - y, centreY + x);
if (error <= 0)
{
++y;
error += ty;
ty += 2;
}
if (error > 0)
{
--x;
tx += 2;
error += (tx - diameter);
}
}
}
If you want to write your own circle drawing function, then I'd suggest adapting the midpoint algorithm to SDL2 by drawing pixels.
Curves would be done similarly, but would use more of an ellipses drawing algorithm.
Actual vector graphics start to get much more complicated, and you'd probably have to find something that renders SVG files, which I'm not sure there are many options for SDL2.
However, if you would rather simply have functions that you can work with I'd suggest going straight to SDL2_gfx instead. It has many more functions already implemented for you to work with.
SDL allows for third party libs to draw on a texture. If cairo was desirable, it could be used in a function like this:
cairo_t*cb(cairo_t*cr)
{cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_rectangle(cr, 10, 20, 128, 128);
cairo_stroke(cr);
return cr;
}
then cb can be passed to this function:
cairo_t*cai(SDL_Window*w,SDL_Renderer*r,cairo_t*(*f)(cairo_t*))
{int width, height, pitch;void *pixels;
SDL_GetWindowSize(w, &width, &height);
SDL_Texture*t=SDL_CreateTexture(r,SDL_PIXELFORMAT_ARGB8888,SDL_TEXTUREACCESS_STREAMING,width,height);
SDL_LockTexture(t, NULL, &pixels, &pitch);
cairo_surface_t *cs=cairo_image_surface_create_for_data(pixels,CAIRO_FORMAT_ARGB32,width,height,pitch);
cairo_t*s=cairo_create(cs);
cairo_t*fr=f(s);SDL_UnlockTexture(t);SDL_RenderCopy(r,t,NULL,NULL);SDL_RenderPresent(r);
return fr;
}
If you want to do a circle or ellipse without 3rd party libraries, include math.h and use the function below I wrote. It will draw aliased ellipse or circles very well. Tested on SDL 2.0.2 and works. It draws one quadrant arc, and mirrors the other arcs, reducing calls to cosf and sinf.
//draw one quadrant arc, and mirror the other 4 quadrants
void sdl_ellipse(SDL_Renderer* r, int x0, int y0, int radiusX, int radiusY)
{
float pi = 3.14159265358979323846264338327950288419716939937510;
float pih = pi / 2.0; //half of pi
//drew 28 lines with 4x4 circle with precision of 150 0ms
//drew 132 lines with 25x14 circle with precision of 150 0ms
//drew 152 lines with 100x50 circle with precision of 150 3ms
const int prec = 27; // precision value; value of 1 will draw a diamond, 27 makes pretty smooth circles.
float theta = 0; // angle that will be increased each loop
//starting point
int x = (float)radiusX * cos(theta);//start point
int y = (float)radiusY * sin(theta);//start point
int x1 = x;
int y1 = y;
//repeat until theta >= 90;
float step = pih/(float)prec; // amount to add to theta each time (degrees)
for(theta=step; theta <= pih; theta+=step)//step through only a 90 arc (1 quadrant)
{
//get new point location
x1 = (float)radiusX * cosf(theta) + 0.5; //new point (+.5 is a quick rounding method)
y1 = (float)radiusY * sinf(theta) + 0.5; //new point (+.5 is a quick rounding method)
//draw line from previous point to new point, ONLY if point incremented
if( (x != x1) || (y != y1) )//only draw if coordinate changed
{
SDL_RenderDrawLine(r, x0 + x, y0 - y, x0 + x1, y0 - y1 );//quadrant TR
SDL_RenderDrawLine(r, x0 - x, y0 - y, x0 - x1, y0 - y1 );//quadrant TL
SDL_RenderDrawLine(r, x0 - x, y0 + y, x0 - x1, y0 + y1 );//quadrant BL
SDL_RenderDrawLine(r, x0 + x, y0 + y, x0 + x1, y0 + y1 );//quadrant BR
}
//save previous points
x = x1;//save new previous point
y = y1;//save new previous point
}
//arc did not finish because of rounding, so finish the arc
if(x!=0)
{
x=0;
SDL_RenderDrawLine(r, x0 + x, y0 - y, x0 + x1, y0 - y1 );//quadrant TR
SDL_RenderDrawLine(r, x0 - x, y0 - y, x0 - x1, y0 - y1 );//quadrant TL
SDL_RenderDrawLine(r, x0 - x, y0 + y, x0 - x1, y0 + y1 );//quadrant BL
SDL_RenderDrawLine(r, x0 + x, y0 + y, x0 + x1, y0 + y1 );//quadrant BR
}
}
My answer extends Scotty Stephens answer by making it a bunch more performant by reducing the API calls to a single one.
// rounding helper, simplified version of the function I use
int roundUpToMultipleOfEight( int v )
{
return (v + (8 - 1)) & -8;
}
void DrawCircle( SDL_Renderer * renderer, SDL_Point center, int radius )
{
// 35 / 49 is a slightly biased approximation of 1/sqrt(2)
const int arrSize = roundUpToMultipleOfEight( radius * 8 * 35 / 49 );
SDL_Point points[arrSize];
int drawCount = 0;
const int32_t diameter = (radius * 2);
int32_t x = (radius - 1);
int32_t y = 0;
int32_t tx = 1;
int32_t ty = 1;
int32_t error = (tx - diameter);
while( x >= y )
{
// Each of the following renders an octant of the circle
points[drawCount+0] = { center.x + x, center.y - y };
points[drawCount+1] = { center.x + x, center.y + y };
points[drawCount+2] = { center.x - x, center.y - y };
points[drawCount+3] = { center.x - x, center.y + y };
points[drawCount+4] = { center.x + y, center.y - x };
points[drawCount+5] = { center.x + y, center.y + x };
points[drawCount+6] = { center.x - y, center.y - x };
points[drawCount+7] = { center.x - y, center.y + x };
drawCount += 8;
if( error <= 0 )
{
++y;
error += ty;
ty += 2;
}
if( error > 0 )
{
--x;
tx += 2;
error += (tx - diameter);
}
}
SDL_RenderDrawPoints( renderer, points, drawCount );
}
A circle of radius 141 would have had 800 SDL_RenderDrawPoint calls in Scottys version, this new version does only execute one single SDL_RenderDrawPoints call, making it much more performant.
One could also strip the rendering portion out of this function, to allow the result to be cached and reused like shown below.
std::vector<SDL_Point> PixelizeCircle( SDL_Point center, int radius )
{
std::vector<SDL_Point> points;
// 35 / 49 is a slightly biased approximation of 1/sqrt(2)
const int arrSize = roundUpToMultipleOfEight( radius * 8 * 35 / 49 );
points.reserve( arrSize );
const int32_t diameter = (radius * 2);
int32_t x = (radius - 1);
int32_t y = 0;
int32_t tx = 1;
int32_t ty = 1;
int32_t error = (tx - diameter);
while( x >= y )
{
// Each of the following renders an octant of the circle
points.push_back( { center.x + x, center.y - y } );
points.push_back( { center.x + x, center.y + y } );
points.push_back( { center.x - x, center.y - y } );
points.push_back( { center.x - x, center.y + y } );
points.push_back( { center.x + y, center.y - x } );
points.push_back( { center.x + y, center.y + x } );
points.push_back( { center.x - y, center.y - x } );
points.push_back( { center.x - y, center.y + x } );
if( error <= 0 )
{
++y;
error += ty;
ty += 2;
}
if( error > 0 )
{
--x;
tx += 2;
error += (tx - diameter);
}
}
return points; // RVO FTW
}
int main()
{
std::vector<SDL_Point> circle = PixelizeCircle( SDL_Point{ 84, 72 }, 79 );
//...
while( true )
{
//...
SDL_RenderDrawPoints( renderer, circle.data(), circle.size() );
//...
}
}
I am trying my attempt at Perlin Noise (3-dimensional) as outlined in this document: http://lodev.org/cgtutor/randomnoise.html
However, this is what I'm getting.
It looks like the smoothing isn't working. You can see blocks the size of the 'size' parameter. Can someone point out what I'm doing wrong?
Here's my code:
%ffp
ctl(1):standard,"Size",range=(1,256), pos=(300,20), size=(120,*),val=64,track, action=preview
onFilterStart:
{
allocArray(9,64,64,64,4); // Array for noise depth
for(int z = 0; z < 64; z++)
for(int y = 0; y < 64; y++)
for(int x = 0; x < 64; x++) {
fputArray(9,x,y,z,(float)(rand() % 32768) / 32768.0);
}
return false;
}
forEveryTile:
{
double fractX,fractY,fractZ,xx,yy,zz;
int x1,y1,z1,x2,y2,z2,col;
double value = 0.0, value2 = 0.0, size, isize=(float)ctl(1);
// int X=screen Width, int Y=screen Height
for(int y = 0; y < Y; y++) {
for(int x = 0; x < X; x++) {
//for(int z = 0; z < 64; z++) {
value2 = 0.0;
size = isize;
while (size >=1.0) {
xx=(float)x/size;
yy=(float)y/size;
zz=(float)clock()/size;
fractX = xx - (int)(xx);
fractY = yy - (int)(yy);
fractZ = zz - (int)(zz);
x1 = ((int)(xx) + 64) % 64;
y1 = ((int)(yy) + 64) % 64;
z1 = ((int)(zz) + 64) % 64;
x2 = (x1 + 64- 1) % 64;
y2 = (y1 + 64- 1) % 64;
z2 = (z1 + 64- 1) % 64;
value=0.0;
value += fractX * fractY * fractZ * fgetArray(9,z1,y1,x1);
value += fractX * (1 - fractY) * fractZ * fgetArray(9,z1,y2,x1);
value += (1 - fractX) * fractY * fractZ * fgetArray(9,z1,y1,x2);
value += (1 - fractX) * (1 - fractY) * fractZ * fgetArray(9,z1,y2,x2);
value += fractX * fractY * (1 - fractZ) * fgetArray(9,z2,y1,x1);
value += fractX * (1 - fractY) * (1 - fractZ) * fgetArray(9,z2,y2,x1);
value += (1 - fractX) * fractY * (1 - fractZ) * fgetArray(9,z2,y1,x2);
value += (1 - fractX) * (1 - fractY) * (1 - fractZ) * fgetArray(9,z2,y2,x2);
value2 += value*size;
size /= 2.0;
}
col=(int)((float)(128.0 * value2 / isize));
col=max(min(col,255),0);
psetp(x,y,RGB(col,col,col));
//} //z
} //x
} //y
return true;
}
Your code is kind of hard to read as written.
For Perlin noise start out with a integer noise function, that behaves like a hash.
float noise(int x, int y, int z) { return hash(x+y*5+z*7); }
or
float noise(int x, int y, int z) { return array[x%w+y%h*w+z%d*w*h]; }
Those are just examples. The important part is that noise(x,y,z) = noise(x,y,z). The noise function has to return the same value for the same parameters every time.
There is a problem though: The noise function only takes integer parameters! But we would like to sample it at float values.
float noisesample (float x, float y, float z) { ... }
The easiest way to to that is using linear filtering. Any positive float value is between (int)pos and ((int)pos)+1. At sub-position pos-(int)pos. This gets us:
float Lerp(float a, float b, float f) { return a+(b-a)*f; }
Where f is the sub-position in the [0..1] range and a,b are the values to the left and right. If f is 0, Lerp returns a, if it is 1, it returns b. In between it does linear interpolation.
So use this for a simple 1D noisesample function:
float noisesample(float x) { return Lerp(noise((int)x), noise((int)x+1), fract(x) }
with
float fract(float x) { return x-(int)x; }
I am using (int)x liberally here, it is the same as floor(x) if x is positive.
To go from a single parameter noisesample to x,y is easy: Do the Lerp twice for x at y and y+1, and Lerp between those:
float noisesample(float x, float y) {
float y0 = Lerp(noise((int)x,(int)y), noise((int)x+1,(int)y), fract(x) }
float y1 = Lerp(noise((int)x,(int)y+1), noise((int)x+1,(int)y+1), fract(x) }
return Lerp ( y0, y1, fract(y) );
}
First interpolate x, twice, then interpolate between the results in y. In total we sample noise() 4 times. I leave it as an exercise how to write noisesample ( float x, float y, float z). It will sample noise() eight times and call Lerp 7 times.
All that got us is that we can sample noise (somewhat smooth - there are smoother ways!) at float coordinates. And that is what we need to make perlin noise!
float perlin(float x, float y, float z, int oc=4) {
// maybe: x = x*2^oc, y, z...
float r = 0;
float s = 1;
for ( int i=0; i<oc; i++ ) {
r += noisesample(x,y,z) * s;
s/=2.0f; // to taste
x/=2.0f;
y/=2.0f;
z/=2.0f;
}
return r;
}
The key idea is to understand sampling. It's just a combination of sampling a simple integer noise function.
I was just wondering what I'm doing wrong here? The errors are mostly from my first function, am I calling it wrong?
typedef struct{ //typedef and function prototype
int x, y, radius;
}circle;
int intersect(circle c1, circle c2);
part of the main function that I need for my function
circle c1 = {5, 6, 3.2};
circle c2 = {6, 8, 1.2};
returns 1 if its two circle arguments intersect. How do I call the arrays using struct properly? I keep getting errors
int intersect(circle c1, circle c2){
float cx, cy, r, distance;
cx = (circle c1[0].x - circle c2[0].x) * (circle c1[0].x - circle c2[0].x);
cy = (circle c1[1].x - circle c2[1].x) * (circle c1[1].x - circle c2[1].x);
r = (circle c1[2].x - circle c2[2].x);
distance = sqrt(cx + cy);
if (r <= distance){
return 1;
}else{
return 0;
}
}
I'm preparing for finals, so help will be appreciated
There are no arrays in your code, so don't try using array notation. Also, don't declare local variables that have the same names as the function parameters.
int intersect(circle c1, circle c2)
{
float dx, dy, r, distance;
dx = (c1.x - c2.x) * (c1.x - c2.x);
dy = (c1.y - c2.y) * (c1.y - c2.y); // x changed to y throughout
r = (c1.r + c2.r); // rewritten too
distance = sqrt(cx + cy);
if (r <= distance)
return 1;
else
return 0;
}
I'm working a MS paint-like application on OpenGL using Bresenham's midpoint algorithm as homework. So far I can draw lines and ellipses. I lose them all when resizing the window. How can I keep them drawn?
Full code:
#include "GL/glut.h"
#include <stdio.h>
#include <math.h>
int i;
//int mainWindow, subWindow;
int X1, Y1, X2, Y2;
int modoDeDibujo;
int W = 1000, H = 1000;
/*void menuApp (int value)
{
if (value == 1) printf("Linea\n");
if (value == 2) printf("Circulo\n");
if (value == 3) printf("Elipsis\n");
if (value == 4) exit(0);
}
void crearMenu()
{
//inicio Creando el menu
int submenu;
submenu = glutCreateMenu(menuApp);
glutAddMenuEntry("Linea", 1);
glutAddMenuEntry("Elipse",3);
glutAddMenuEntry("Salir",4);
glutCreateMenu(menuApp);
glutAddSubMenu("SubMenu", submenu);
glutAttachMenu(GLUT_RIGHT_BUTTON);
//fin Creando el menu
}*/
void renderPoint(void) /*REVISAR ESTO*/
{
glClear (GL_COLOR_BUFFER_BIT);
glBegin (GL_POINTS);
glVertex2f (-0.98, 0.98);
glEnd ();
glFlush ();
}
void renderPoint(double x, double y)
{
//printf("BEFORE TRANSFORM %f\t%f\t# renderPoint\n", x, y);
W = glutGet(GLUT_WINDOW_WIDTH);
H = glutGet(GLUT_WINDOW_HEIGHT);
float X;
float Y;
glBegin (GL_POINTS);
X = (2*x/W) - 1;
Y = (-2*y/H) + 1;
glVertex2f (X, Y);
//printf("TRANSFORMED POINT %f\t%f\t# renderPoint\n", X, Y);
glEnd ();
glFlush ();
}
/*wiki pseudo:
function line(x0, x1, y0, y1) //x1
boolean steep := abs(y1 - y0) > abs(x1 - x0)//x2
if steep then//x3
swap(x0, y0) //x4
swap(x1, y1) //x5
if x0 > x1 then //x6
swap(x0, x1) //x7
swap(y0, y1) //x8
int deltax := x1 - x0 //x9
int deltay := abs(y1 - y0) //x10
int error := deltax / 2 //x11
int ystep //x12
int y := y0 //x13
if y0 < y1 then ystep := 1 else ystep := -1 //x14
for x from x0 to x1 //x15
if steep then plot(y,x) else plot(x,y) //x16
error := error - deltay //x17
if error < 0 then //x18
y := y + ystep //x19
error := error + deltax //x20
*/
void bresenham1(GLint x0, GLint x1, GLint y0, GLint y1) //function line(x0, x1, y0, y1)
{
//double result1 = fabs((double)y1 - y0); //abs(y1 - y0)
//double result2 = fabs((double)x1 - x0); //abs(x1 - x0)
int result1 = abs(y1-y0);
int result2 = abs(x1-x0);
bool steep = (result1 > result2); //boolean steep := abs(y1 - y0) > abs(x1 - x0)
if (steep){ //if steep then
GLint aux1 = x0; //swap(x0, y0)
x0=y0;
y0 = aux1;
GLint aux2 = x1; // swap (x1,y1)
x1=y1;
y1=aux2;
}
if(x0>x1){ // if (x0>x1)
GLint aux3=x0; //swap(x0,x1)
x0=x1;
x1=aux3;
GLint aux4=y0;//swap(y0,y1)
y0=y1;
y1=aux4;
}
int deltax = x1-x0; // deltax = x1-x0
int deltay = abs(y1-y0); // int deltay := abs(y1 - y0) - revisar
int error = (deltax / 2); //int error := deltax / 2
int ystep; // int ystep
int y = y0; //int y := y0
if (y0<y1){ //if y0 < y1 then ystep := 1 else ystep := -1
ystep=1;
}
else {ystep=-1;}
for (int x=x0; x<=x1; x++){ //for x from x0 to x1
if (steep){ // if steep then plot(y,x) else plot(x,y)
renderPoint(y,x);
}
else {
renderPoint(x,y);
}
error = error - deltay; //error := error - deltay
if (error<0) { //if error < 0 then
y = y + ystep; // y := y + ystep
error = error + deltax; //error := error + deltax
} // end if (error<0)
}// end for from x0 to x1
}// end bresenham
void Plot4EllipsePoints(int X, int Y,int CX,int CY){
renderPoint(CX+X, CY+Y); //point in quadrant 1
renderPoint(CX-X, CY+Y); // point in quadrant 2
renderPoint(CX-X, CY-Y); // point in quadrant 3
renderPoint(CX+X, CY-Y); // point in quadrant 4
}
void PlotEllipse (int CX, int CY, int XRadius, int YRadius) {
int X, Y;
int XChange, YChange;
int EllipseError;
int TwoASquare, TwoBSquare;
int StoppingX, StoppingY;
TwoASquare = 2 * XRadius * XRadius;
TwoBSquare = 2 * YRadius * YRadius;
X = XRadius;
Y =0;
XChange = YRadius*YRadius*(1-(2*XRadius));
YChange = XRadius * XRadius;
EllipseError =0;
StoppingX = TwoBSquare*XRadius;
StoppingY = 0;
while(StoppingX >= StoppingY){
Plot4EllipsePoints(X,Y,CX,CY);
Y++;
StoppingY=StoppingY + TwoASquare;
EllipseError= EllipseError+ YChange;
YChange= YChange+ TwoASquare;
if( ((2*EllipseError) + XChange)>0)
{
X--;
StoppingX = StoppingX - TwoBSquare;
EllipseError= EllipseError + XChange;
XChange = XChange + TwoBSquare;
}
}
//1st set of points done, start second set
X=0;
Y= YRadius;
XChange= YRadius*YRadius;
YChange = XRadius*XRadius*(1-2*YRadius);
EllipseError=0;
StoppingX =0;
StoppingY= TwoASquare * YRadius;
while(StoppingX <= StoppingY){ // 2nd set of points, y'<-1
Plot4EllipsePoints(X,Y, CX,CY);
X++;
StoppingX = StoppingX + TwoBSquare;
EllipseError = EllipseError + XChange;
XChange = XChange + TwoBSquare;
if (((2*EllipseError) + YChange)>0){
Y--;
StoppingY = StoppingY - TwoASquare;
EllipseError = EllipseError + YChange;
YChange = YChange + TwoASquare;
}
}
}
void renderAll (void)
{
/*glutSetWindow(mainWindow);
glutPostRedisplay();
glutSetWindow(subWindow);
glutPostRedisplay();*/
}
void movimiento(int boton, int estado, int x, int y)
{
if((estado == GLUT_DOWN) && (boton == GLUT_LEFT_BUTTON))//mouse down
{
X1 = x; Y1 = y;
PlotEllipse (x, y, 200, 100);
renderPoint(x,y);
}
if((estado == GLUT_UP) && (boton == GLUT_LEFT_BUTTON))//mouse up
{
//printf(" Up|x:%d, y:%d\n",x,y);
X2 = x; Y2 = y;
//renderLine();
bresenham1(X1,X2,Y1,Y2);
//PRUEBA USANDO LA PRIMITIVA DE OPENGL
glBegin( GL_LINES );
glEnd();
//renderPoint(x, y);
}
}
void MouseMove(int x, int y)
{
//printf("x:%d | y:%d\n", x,y);
X2 = x; Y2 = y;
//renderLine();
//bresenham1(X1, Y1, X2, Y2);
}
void teclado(unsigned char key, int x, int y)
{
if(key==1){
modoDeDibujo=1; // dibuja lineas
printf("Modo de dibujo: linea");
}
if (key==2){
modoDeDibujo=2; //dibuja elipses
}
if(key == 27)exit(0);
}
void especiales(int key, int x, int y)
{
if(key == GLUT_KEY_F1) exit(0);
}
static void
key(unsigned char k, int x, int y)
{
switch (k) {
case 27: /* Escape */
exit(0);
break;
default:
return;
}
glutPostRedisplay();
}
int main (int argc, char *argv [])
{
i = 0;
//inicializa las operaciones de OpenGL/GLUT, db cr antes de usar funciones GLUT
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition (100, 100);
glutInitWindowSize (W, H);
//Crea una ventana de Opengl
glutCreateWindow ("tarea");
glutDisplayFunc (renderPoint);
glutMouseFunc(movimiento);
glutKeyboardFunc(teclado);//teclas ASCII
glutSpecialFunc(especiales);//captura las teclas [f1..f12]
//glutPassiveMotionFunc(pasivo);
glutKeyboardFunc(key);
glutMotionFunc(MouseMove);
//crearMenu();
glutMainLoop ();
}
First of all , you need to arrange the code. You must have one and only one display function, that clears the buffer,calls the other draw-functions and flushes them to the screen ( or swaps the buffer if you are using a double buffer).
On resizing the window,GLUT will call the Display Function which is renderPoint() as you know :
glutDisplayFunc (renderPoint);
renderPoint clears the buffer before redrawing the "points" , for example :
void renderPoint(void) /*REVISAR ESTO*/
{
glClear (GL_COLOR_BUFFER_BIT);
glBegin (GL_POINTS);
glVertex2f (-0.98, 0.98);
glEnd ();
glFlush ();
}
Since the buffer has been cleared , all the points that are drawn outside the function renderPoint ( the points of circles, the points of lines .. ) has no meaning , because you did not call them from the "main display function which is renderPoint.
How to keep the points on the screen ?
You must store the points ( any point you want to draw ) in a buffer such as an array , a dynamic array, std::vector or anything else. in the display function , write a loop statement to visit each point and extract the x and y .. then draw them.
for example , instead of the above function , replace it with :
class MyPoint {
public:
float x;
float y;
MyPoint(float x, float y)
{
this->x = x;
this->y = y;
} };
#include <vector>
std::vector<MyPoint> testPoints;
void renderPoint(void) /*REVISAR ESTO*/ {
testPoints.push_back(MyPoint(-0.58,0.58));
testPoints.push_back(MyPoint(0.58,0.58));
testPoints.push_back(MyPoint(0.58,-0.58));
glClear (GL_COLOR_BUFFER_BIT);
glPointSize(2);
glBegin (GL_POINTS);
for(int i=0;i<testPoints.size();i++)
{
glVertex2f (testPoints[i].x, testPoints[i].y);
}
glEnd ();
glFlush ();
}
as you can see , by using a dynamic array such as (std::vector) to store the points and by using a for loop statement , we able to keep the three points visible.
what else ?
do the same method with other shapes , so that for each "mouse click " event , you may add or push_back two points represents a line end points in an array or std::vector called lineArray . in the display function , make a for loop statement to draw each line after extracting the two line points.
you should use glutReshapeFunc and glViewport to make sure that the viewport has the same dimenstions as the window after the resizing event. and I think that gluOrtho2d is more elegant than trying to mapping from Windows coordinates space to OpenGL coordinates space
arrange your code , so that you just use one display function.
Your program could be Something like this:
void drawTestPoints()
{
for(int i=0;i<length;i++)
{
renderPoint(pointsArray[i].x,pointsArray[i].y);// vector of points/(MyPoint)
}
}
void drawLines()
{
for(int i=0;i<length;)
{
MyPoint startPoint = linesArray[i];
MyPoint endPoint = linesArray[i+1];
bresenham1(startPoint.x,endPoint.x,startPoint.y,endPoint.y);
i+=2;
}
}
void drawAll()
{
glClear (GL_COLOR_BUFFER_BIT);
drawTestPoints();
drawLines();
drawOtherShapes();
glFlush();
}
.
.
.
// in the main func:
glutDisplayFunc (drawAll);
==
Don't think of it as "keeping them drawn". Think instead in terms of events and "when do I need to redraw my objects".
For this you will need to handle the resize event and rerun your drawing code. I'm also guessing that your objects might not redraw themselves after another application is moved over them, or if it is moved off screen a little and then brought back. If this is the case you'll need to figure out what events to handle that will cause a redraw as well.
Here is a quick example for windows :
http://www.falloutsoftware.com/tutorials/gl/gl2.htm