This is my fist time studying Computer Graphics and i was given the code below from my professor. I think i have understood how the algorithm is implemented in general, but what i fail to understand is in what way the incx,incy,inc1,inc2 lines work. I obviously know they are there to increase something but since i haven't fully understood the algorithm i'm kinda baffled. This is the full code:
#include <gl/glut.h>
#include <stdio.h>
int xstart, ystart, xend, yend;
void myInit() {
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0, 0.0, 0.0, 1.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0, 500, 0, 500);
}
void draw_pixel(int x, int y) {
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
}
void draw_line(int xstart, int xend, int ystart, int yend) {
int dx, dy, i, e;
int incx, incy, inc1, inc2;
int x,y;
dx = xend-xstart;
dy = yend-ystart;
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
incx = 1;
if (xend < xstart) incx = -1;
incy = 1;
if (yend < ystart) incy = -1;
x = xstart;
y = ystart;
if (dx > dy) {
draw_pixel(x, y);
e = 2 * dy-dx;
inc1 = 2*(dy-dx);
inc2 = 2*dy;
for (i=0; i<dx; i++) {
if (e >= 0) {
y += incy;
e += inc1;
}
else
e += inc2;
x += incx;
draw_pixel(x, y);
}
} else {
draw_pixel(x, y);
e = 2*dx-dy;
inc1 = 2*(dx-dy);
inc2 = 2*dx;
for (i=0; i<dy; i++) {
if (e >= 0) {
x += incx;
e += inc1;
}
else
e += inc2;
y += incy;
draw_pixel(x, y);
}
}
}
void myDisplay() {
draw_line(xstart, xend, ystart, yend);
glFlush();
}
void main(int argc, char **argv) {
printf( "Enter (xstart, ystart, xend, yend)\n");
scanf("%d %d %d %d", &xstart, &ystart, &xend, ¥d);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("Bresenham's Line Algorithm Visualization");
myInit();
glutDisplayFunc(myDisplay);
glutMainLoop();
}
Related
I have a simple 2D simulation which has particles travelling at given velocities and could collide with each other and the walls. But the fps drops when there are more than 500 particles. I want to simulate at least 5000 particles smoothly because I'll be adding more features to the program. Is there a different and efficient approach to this? Thanks!
gas.cpp:
#include<cstdlib>
#include<vector>
#include<glut.h>
#include "gas.h"
#include<time.h>
float t = 1; //time step
void gas::p(float pos_x, float pos_y, float vx, float vy, float mass)
{
srand(time(0));
m = mass;
x = pos_x;
y = pos_y;
velx = vx;
vely = vy;
size = 3;
}
void gas::draw()
{
glColor3f(1, 1, 1);
glVertex2f(x, y);
}
void gas::move(float t)
{
x += velx * t;
y += vely * t;
}
float temp;
//Function to be ran at every frame:
void run(std::vector <gas>& bn)
{
int it = 0;
for (gas& i : bn)
{
int jt = 0;
for (gas& j : bn)
{
if (it != jt)
{
//Handling collisions:
if (abs(i.y - (j.y + j.size)) < 1 && (abs(j.x - i.x) <= i.size + 1) && i.vely < 0)
{
temp = i.vely;
i.vely = j.vely;
j.vely = temp;
}
if (abs(j.y - (i.y + i.size)) < 1 && (abs(i.x - j.x) <= j.size + 1) && i.vely > 0)
{
temp = i.vely;
i.vely = j.vely;
j.vely = temp;
}
if (abs(j.x - (i.x + i.size)) < 1 && (abs(i.y - j.y) <= i.size + 1) && i.velx > 0)
{
temp = i.velx;
i.velx = j.velx;
j.velx = temp;
}
if (abs(i.x - (j.x + j.size)) < 1 && (abs(j.y - i.y) <= i.size + 1) && i.velx < 0)
{
temp = i.velx;
i.velx = j.velx;
j.velx = temp;
}
}
jt += 1;
}
//Boundary Collisions:
if (i.x > 600 - i.size) { i.x = 600 - i.size; i.velx = -i.velx; }
if (i.x < i.size) { i.x = i.size; i.velx = -i.velx; }
if (i.y > 600 - i.size) { i.y = 600 - i.size; i.vely = -i.vely; }
if (i.y < i.size) { i.y = i.size; i.vely = -i.vely; }
i.move(t);
it += 1;
}
}
gas.h:
#pragma once
class gas
{
public:
float m = 1;
float x = 0;
float y = 0;
float velx = 0;
float vely = 0;
float size = 3;
float density = 100;
float r = 1; float g = 1; float b = 1;
void p(float pos_x, float pos_y, float vx, float vy, float mass);
void draw();
void move(float t);
};
void run(std::vector<gas>& bn);
simulate.cpp (main file):
#include<cstdlib>
#include<glut.h>
#include<vector>
#include "gas.h"
#include<thread>
#include<time.h>
void display();
void reshape(int, int);
const int n = 600; //Number of particles
void init()
{
glClearColor(0, 0, 0, 1);
}
std::vector <gas> b(n);
void timer(int)
{
run(b);
glutPostRedisplay();
glutTimerFunc(1000 / 60, timer, 0);
}
void show(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowPosition(300, 60);
glutInitWindowSize(600, 600);
glutCreateWindow("Particles");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutTimerFunc(1000, timer, 0); // Args: Time delay per frame in milliseconds, function to be called
init();
glutMainLoop();
}
int main(int argc, char** argv)
{
int it = 0;
for (gas& i : b)
{
srand(it);
i.p(rand() % 600, rand() % 600, (rand() % 10) * pow(-1, it + 1), (rand() % 10) * pow(-1, it), 1);
it += 1;
}
show(argc, argv);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glPointSize(3);
glBegin(GL_POINTS);
for (gas& i : b)
{
i.draw();
}
glEnd();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, 600, 0, 600);
glMatrixMode(GL_MODELVIEW);
}
I've done some research and there are many methods to doing this if the vertices and points are predetermined as seen here. However in my case, everything is specified by the user. The code I have put together (with the help of others), allows the user to create the polygon, and place points. I wrote functions to try and create vectors from the point to the vertices and then compute the angle. If it comes to 360 it should be inside and it should be colored green. Else it should be outside and red.
This is what I've been working on, but I cant seem to figure it out:
(Edit: Included my entire code)
GLint vert[100][2];
int width = 400, height = 600, n = 0, m = 0, type = GL_LINE_STRIP, v;
bool rubberbanding = false;
bool closed = false;
double testx, testy;
bool isitin;
double dotp(double x1, double y1, double x2, double y2) {
double a;
a = (x1 * x2) + (y1 * y2);
return a;
}
double mag(double x1, double y1, double x2, double y2) {
double a;
double x = (x2 - x1);
double y = (y2 - y1);
a = sqrt((x*x) + (y*y));
return a;
}
bool inpoly(int numv, GLint vx[][2], GLint vy[][2], double tx, double ty) {
double angle = 0.0;
int n = 0;
while (n != numv) {
//vector from point to vertex
double newv1x = vx[n][0] - tx;
double newv1y = vy[n][1] - ty;
double magv1 = mag(tx, ty, vx[n][0], vy[n][1]); //magnitude of vector
//vector from point to next vertex
double newv2x = vx[n + 1][0] - tx;
double newv2y = vy[n + 1][1] - ty;
double magv2 = mag(tx, ty, vx[n+1][0], vy[n+1][1]);//magnitude of vector
//dot product between the two vectors
double dp = dotp(newv1x, newv1y, newv2x, newv2y);
//angle between two vectors
double vang = acos(dp / (magv1*magv2));
angle += vang;
n++;
}
//vector from point to last vertex
double newv1x = vx[numv][0] - tx;
double newv1y = vy[numv][1] - ty;
double magv1 = mag(tx, ty, vx[numv][0], vy[numv][1]); //magnitude of vector
//vector from point to first vertex
double newv2x = vx[0][0] - tx;
double newv2y = vy[0][1] - ty;
double magv2 = mag(tx, ty, vx[0][0], vy[0][1]);//magnitude of vector
//dot product between the two vectors
double dp = dotp(newv1x, newv1y, newv2x, newv2y);
//angle between two vectors
double vang = acos(dp / (magv1*magv2));
angle += vang;
if (angle == 360.0) return true;
return false;
}
void display(){
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1, 1, 0);
glBegin(closed ? GL_LINE_LOOP : GL_LINE_STRIP);
for(int i = 0; i < m; i++){
glVertex2iv(vert[i]);
}
glEnd();
/*
glColor3f(0, 0, 1);
glBegin(GL_POINTS);
for (int i = m; i < n; i++) {
glVertex2iv(vert[i]);
}
*/
isitin = inpoly(m, vert, vert, testx, testy);
if (isitin == true) {
glColor3f(0, 1, 0);
glBegin(GL_POINTS);
for (int i = m; i < n; i++) {
glVertex2iv(vert[i]);
}
}
else {
glColor3f(1, 0, 0);
glBegin(GL_POINTS);
for (int i = m; i < n; i++) {
glVertex2iv(vert[i]);
}
}
glEnd();
glutSwapBuffers();
glutPostRedisplay();
}
void keyboard(unsigned char key, int x, int y){
switch(key){
case 'r': n = 0; m = 0; closed = false; break;
case 'c': closed = true; break;
}
glutPostRedisplay();
}
int findVertex(int x, int y){
int dx, dy;
for(int i = 0; i < n; i++){
dx = vert[i][0] - x;
dy = vert[i][1] - y;
if(dx*dx + dy*dy < 16) return i;
}
return - 1;
}
void mousemove(int x, int y)
{
testx = x;
testy = height - 1 - y;
}
void mouse(int button, int state, int x, int y){
switch(button){
case GLUT_LEFT_BUTTON:
if(state == GLUT_DOWN){
if (n < 100) {
v = n++;
vert[v][0] = x;
vert[v][1] = height - 1 - y;
// n++;
rubberbanding = true;
glutPostRedisplay();
if (!closed) m = n;
}
}
else{
rubberbanding = false;
}
break;
}
}
void motion(int x, int y){
if(rubberbanding){
vert[v][0] = x;
vert[v][1] = height - 1 - y;
glutPostRedisplay();
}
}
void main(int argc, char** argv){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
glutInitWindowSize(width,height);
glutInitWindowPosition(50,100);
glutCreateWindow("Project 3");
glClearColor(0.0,0.0,0.0,0.0);
glColor3f( 1, 1, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, 0, height);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse);
glutPassiveMotionFunc(mousemove);
glutMotionFunc(motion);
glutMainLoop();
}
When I run the program in Visual Studio, I can draw the polygon, and I can specify
points, but for some reason all the points appear red. If anyone has any ideas on how to fix this, it would be greatly appreciated.
Probably your error is that acos returns in radians, and you're testing if the sum equals 360 degrees.
Also, you shouldn't compare doubles that way, since that calculation is probably adding rounding error in each sum. See here for more information.
I'm trying to make Bezier curve by control point.
I have some examples and followed it. But it did not work.
It shows the line is going to (0, 0) points during working.
I still don't get it why.
Here's the code in the C++ language, using OpenGL.
#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <gl/glut.h>
#include <gl/GLU.h>
#include <gl/GL.h>
#include <math.h>
#define CTRL_COUNT 100
void display();
void init();
float getNextBezierPointX(float t);
float getNextBezierPointY(float t);
void drawline();
int ctrlPointsCount;
int ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
int X1[20] = { 10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105 };
int Y1[20] = { 50,60,40,70,40,60,35,80,45,55,30,60,40,60,40,55,35,70,40,50 };
void main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(500, 300);
glutCreateWindow("Bezier");
glutDisplayFunc(display);
init();
glutMainLoop();
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 0.0, 0.0);
ctrlPointsCount = 20;
for (int i = 0; i < 20; i++) {
ctrlPointsX[i] = X1[i];
ctrlPointsY[i] = Y1[i];
}
drawline();
glFlush();
}
void init() {
glClearColor(0.0, 0.0, 0.0, 0.0);
glColor3f(1.0, 0.0, 0.0);
glPointSize(8.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 128.0, 0.0, 96.0);
}
float getNextBezierPointX(float t) {
float x = 0.0;
int c;
for (int i = 0; i < ctrlPointsCount; i ++) {
if (i == 0 || i == ctrlPointsCount - 1)
c = 1;
else
c = ctrlPointsCount - 1;
x = x + c * pow(t, i) * pow(1 - t, ctrlPointsCount - 1 - i) * ctrlPointsX[i];
}
return x;
}
float getNextBezierPointY(float t) {
float y = 0.0;
int c;
for (int i = 0; i < ctrlPointsCount; i ++) {
if (i == 0 || i == ctrlPointsCount - 1)
c = 1;
else
c = ctrlPointsCount - 1;
y = y + c * pow(t, i) * pow(1 - t, ctrlPointsCount - 1 - i) * ctrlPointsY[i];
}
return y;
}
void drawline() {
float x, y;
for (int i = 0; i < 20; i++) {
glBegin(GL_POINTS);
glVertex2i(ctrlPointsX[i], ctrlPointsY[i]);
glEnd();
glFlush();
}
float oldX = ctrlPointsX[0], oldY = ctrlPointsY[0];
for (double t = 0.0; t <= 1.0; t += 0.01) {
x = getNextBezierPointX(t);
y = getNextBezierPointY(t);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINES);
glVertex2f(oldX, oldY);
glVertex2f(x, y);
glEnd();
glFlush();
oldX = x;
oldY = y;
}
}
For a bezier curve like this you have to calculate Bernstein polynomials:
double factorial(int n)
{
double x = 1.0;
for (int i = 1; i <= n; i++)
x *= (double)i;
return x;
}
double Ni(int n, int i)
{
double a1 = factorial(n);
double a2 = factorial(i);
double a3 = factorial(n - i);
double ni = a1/ (a2 * a3);
return ni;
}
double Bernstein(int n, int i, double t)
{
double ti = (t == 0.0 && i == 0) ? 1.0 : pow(t, i); /* t^i */
double tni = (n == i && t == 1.0) ? 1.0 : pow((1 - t), (n - i)); /* (1 - t)^i */
double basis = Ni(n, i) * ti * tni; //Bernstein basis
return basis;
}
The code to create the curve may look like this:
struct vec2
{
double x, y;
};
vec2 getBezierPoint(float t, int n, int x[], int y[] )
{
vec2 pt{ 0.0, 0.0 };
for (int i = 0; i < n; i ++) {
double b = Bernstein( n - 1, i, t );
pt.x += b * x[i];
pt.y += b * y[i];
}
return pt;
}
float oldX = ctrlPointsX[0], oldY = ctrlPointsY[0];
for (double t = 0.0; t <= 1.0; t += 0.01)
{
vec2 pt = getBezierPoint( t, ctrlPointsCount, ctrlPointsX, ctrlPointsY );
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINES);
glVertex2f(oldX, oldY);
glVertex2f((float)pt.x, (float)pt.y);
glEnd();
glFlush();
oldX = (float)pt.x; oldY = (float)pt.y;
}
An other solution is provided in the answer to the Stack Overflow question How do I implement a Bézier curve in C++?:
#include <vector>
vec2 getBezierPoint2( float t, int n, int x[], int y[] )
{
std::vector<double> tmpx( n ), tmpy( n );
for ( int i=0; i<n; ++ i )
{
tmpx[i] = x[i];
tmpy[i] = y[i];
}
int i = n - 1;
while (i > 0)
{
for (int k = 0; k < i; k++)
{
tmpx[k] = tmpx[k] + t * ( tmpx[k+1] - tmpx[k] );
tmpy[k] = tmpy[k] + t * ( tmpy[k+1] - tmpy[k] );
}
i--;
}
return { tmpx[0], tmpy[0] };
}
But may be the result is not what you expect it to be, because you create a Higher-order Bézier curve which results in a very flat curve:
Maybe you want to connect any number of points with square bezier curves: Quadratic Bézier Curve: Calculate Points
I am trying to draw a Bezier curve in OpenGL using floating point values. I have tried using many different code examples. My current code below, runs ,but does not show the curve on screen. The usual way to draw Bezier curves are with integer values, which means using the GLUORTHO2D() function for drawing the curve. But I want to draw a curve using floating point values. Such as x range(-1,1) and y range(-1,1).
like if x=(500) then consider it (-1 to 1) and if y=(800) then consider it (-1,1).
I have already tried using integer values and it worked for me. my code using integer values is below:
#include <GL/glut.h>
#include <math.h>
#include <stdio.h>
#define CTRL_COUNT 100
int ctrlPointsCount;
int ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
int X1[3]={20,25,20}, Y1[3]={5,24,38}; //first point(x1[0],y1[0]) second(x1[1],y1[1]) third(x1[2],y1[2])
void myInit()
{
glClearColor(0.0,0.0,0.0,0.0);
glColor3f(1.0,0.0,0.0);
glPointSize(8.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,128.0,0.0,96.0);
}
//p(t)=(1-t)^3*p0+3t(1-t)^2*p1+3t^2(1-t)p2+t^3p3
float getNextBezierPointX(float t)
{
float x=0.0;
for(int i=0; i<ctrlPointsCount; i++)
{
int c;
if(i==0 || i==ctrlPointsCount-1)
c = 1;
else
{
c = ctrlPointsCount-1;
}
x += c * pow(t, i) * pow(1-t, ctrlPointsCount-1-i) * ctrlPointsX[i];
}
return x;
}
float getNextBezierPointY(float t)
{
float y=0.0;
for(int i=0; i<ctrlPointsCount; i++)
{
int c;
if(i==0 || i==ctrlPointsCount-1)
c = 1;
else
{
c = ctrlPointsCount-1;
}
y += c * pow(t, i) * pow(1-t, ctrlPointsCount-1-i) * ctrlPointsY[i];
}
return y;
}
void drawline()
{
// draw control points using red color
for(int i=0; i < 3; i++)
{
glBegin(GL_POINTS);
glVertex2i(ctrlPointsX[i], ctrlPointsY[i]);
glEnd();
glFlush();
}
// draw bezier curve using control poitns by calculating next points using cubic bezier curve formula
float oldX=ctrlPointsX[0], oldY=ctrlPointsY[0];
for(double t = 0.0;t <= 1.0; t += 0.01) {
float x = getNextBezierPointX(t);
float y = getNextBezierPointY(t);
//glColor3f(1.0,t,1.0);
glColor3f(1.0,1.0,1.0);
glBegin(GL_LINES);
glVertex2f(oldX, oldY);
glVertex2f(x, y);
glEnd();
glFlush();
oldX = x;
oldY = y;
}
}
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
ctrlPointsCount=3;
for(int i=0;i<3;i++)
{
ctrlPointsX[i] = X1[i];
ctrlPointsY[i] = Y1[i];
}
drawline();
glFlush();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(640,480);
glutInitWindowPosition(100,150);
glutCreateWindow("Bezier Curve");
glutDisplayFunc(myDisplay);
myInit();
glutMainLoop();
return 0;
}
But when i tried using floating point values , it does not work for me. It does not show the curved line on screen. My code using floating point values is below:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>
using namespace std;
#define CTRL_COUNT 100
int ctrlPointsCount;
int ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
double X1[3] = { 0.26015037593985, 0.43609022556391, 0.6 }, Y1[3] = { 0.946875, 0.884375, 0.946875 };
//Initializes 3D rendering
void initRendering() {
glEnable(GL_DEPTH_TEST);
}
float getNextBezierPointX(float t)
{
float x = 0.0;
for (int i = 0; i<ctrlPointsCount; i++)
{
int c;
if (i == 0 || i == ctrlPointsCount - 1)
c = 1;
else
{
c = ctrlPointsCount - 1;
}
x += c * pow(t, i) * pow(1 - t, ctrlPointsCount - 1 - i) * ctrlPointsX[i];
}
return x;
}
float getNextBezierPointY(float t)
{
float y = 0.0;
for (int i = 0; i<ctrlPointsCount; i++)
{
int c;
if (i == 0 || i == ctrlPointsCount - 1)
c = 1;
else
{
c = ctrlPointsCount - 1;
}
y += c * pow(t, i) * pow(1 - t, ctrlPointsCount - 1 - i) * ctrlPointsY[i];
}
return y;
}
void drawline()
{
// draw control points using red color
for (int i = 0; i < 3; i++)
{
glBegin(GL_POINTS);
glVertex2i(ctrlPointsX[i], ctrlPointsY[i]);
glEnd();
glFlush();
}
// draw bezier curve using control poitns by calculating next points using cubic bezier curve formula
float oldX = ctrlPointsX[0], oldY = ctrlPointsY[0];
for (double t = 0.0; t <= 1.0; t += 0.01)
{
float x = getNextBezierPointX(t);
float y = getNextBezierPointY(t);
//glColor3f(1.0,t,1.0);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINES);
glVertex2f(oldX, oldY);
glVertex2f(x, y);
glEnd();
glFlush();
oldX = x;
oldY = y;
}
}
//Called when the window is resized
void handleResize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (double)w / (double)h, 1.0, 200.0);
}
float _angle = 0.0;
float _cameraAngle = 0.0;
float _ang_tri = 0.0;
//Draws the 3D scene
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); //Reset the drawing perspective
ctrlPointsCount = 3;
for (int i = 0; i<3; i++)
{
ctrlPointsX[i] = X1[i];
ctrlPointsY[i] = Y1[i];
}
drawline();
glutSwapBuffers();
}
void update(int value) {
_angle += 2.0f;
if (_angle > 360) {
_angle -= 360;
}
_ang_tri += 2.0f;
if (_ang_tri > 360) {
_ang_tri -= 360;
}
glutPostRedisplay(); //Tell GLUT that the display has changed
//Tell GLUT to call update again in 25 milliseconds
glutTimerFunc(25, update, 0);
}
int main(int argc, char** argv) {
//Initialize GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(1331, 641);
glutInitWindowPosition(0, 0);
//Create the window
glutCreateWindow("Our cg project");
initRendering();
//Set handler functions
glutDisplayFunc(drawScene);
glutReshapeFunc(handleResize);
glutTimerFunc(25, update, 0); //Add a timer
glClearColor(0.0, 0.7, 1.5,0.0);
glutMainLoop();
return 0;
}
The problem is this here:
int ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
double X1[3] = { 0.26015037593985, 0.43609022556391, 0.6 }, Y1[3] = {0.946875, 0.884375, 0.946875 };
for (int i = 0; i<3; i++)
{
ctrlPointsX[i] = X1[i];
ctrlPointsY[i] = Y1[i];
}
ctrlPointsX and ctrlPointsYcan only hold integer values. So when you do ctrlPointsX[i] = X1[i] and ctrlPointsY[i] = Y1[i] you are converting the floats to integers, which will round them down. So all your controlPoints will be 0.
You have to declare the controlPoints arrays as type double too:
double ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
double X1[3] = { 0.26015037593985, 0.43609022556391, 0.6 }, Y1[3] = {0.946875, 0.884375, 0.946875 };
This should fix your problem.
I have a self intersecting polygon that I am trying to fill using the odd-even rule like so :
I use a scan line and when I detect an edge of the polygon I change the fill color. Here's my code so far :
Edited code :
#include<GL/glut.h>
#include<vector>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<limits>
using namespace std;
const int n = 7;
class Point{
public:
int x, y;
Point(){
};
Point(int a, int b){
x = a;
y = b;
};
void set(int a, int b){
x = a;
y = b;
};
};
Point P[n];
int min(int x, int y)
{
if (x <= y) return x;
else return y;
}
int max(int x, int y)
{
if (x >= y) return x;
else return y;
}
Point solve(Point A, Point B, Point C, Point D)
{ //returns the intersection point between line segments [AB] and [CD]
Point rez;
rez.x = -1;
rez.y = -1;
//[AB]
int A1 = B.y - A.y, B1 = A.x - B.x, C1 = (A1 * A.x) + (B1 * A.y);
//[CD]
int A2 = D.y - C.y, B2 = C.x - D.x, C2 = (A2 * C.x) + (B2 * C.y);
int det = A1*B2 - A2*B1;
if (det == 0){
return Point(-1, -1);
}
else
{
rez.x = (B2*C1 - B1*C2) / det;
rez.y = (A1*C2 - A2*C1) / det;
}
if (!(rez.x >= min(A.x, B.x) && rez.x <= max(A.x, B.x) && rez.x >= min(C.x, D.x) && rez.x <= max(C.x, D.x)))
{
rez.x = -1;
rez.y = -1;
}
return rez;
}
bool intComparison(int i, int j) { return (i < j); }
void scanfill()
{
int i, j, color = 1, k; //alb
vector<int> inter[501];
Point T;
for (j = 0; j < 500; j++) //go line by line
{
for (k = 0; k < n - 1; k++) //loop through all the line segments
{
T = solve(Point(0, j), Point(499, j), P[k], P[k + 1]);
if (!(T.x == -1 && T.y == -1))
{
inter[j].push_back(T.x); // save the x coord. of the intersection point between the line and the sweep line when y = j
}
}
T = solve(Point(0, j), Point(499, j), P[n - 1], P[0]);
if (!(T.x == -1 && T.y == -1))
{
inter[j].push_back(T.x);
}
}
for (j = 0; j < 500; j++)
{
sort(inter[j].begin(), inter[j].end(), intComparison);
}
for (j = 0; j < 500; j++)
{
glColor3f(0.0, 0.0, 1.0);
glBegin(GL_LINES);
for (vector<int>::iterator it = inter[j].begin(); it != inter[j].end(); it++)
{
glVertex2i(*it, j); //draw the actual lines
}
glEnd();
}
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 0.0, 0.0);
P[0] = Point(100, 235);
P[1] = (Point(100, 100));
P[2] = (Point(230, 140));
P[3] = (Point(40, 200));
P[4] = (Point(20, 60));
P[5] = (Point(300, 150));
P[6] = (Point(150, 111));
glBegin(GL_LINE_LOOP);
for (int i = 0; i < n; i++)
{
glVertex2i(P[i].x, P[i].y);
}
glEnd();
scanfill();
glFlush();
}
void init()
{
glClearColor(1.0, 1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 499.0, 0.0, 499.0);
}
void main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("scanline");
glutDisplayFunc(display);
init();
glutMainLoop();
}
It seems to detect more intersections between the sweep line and the actual lines than it should for some reason.
Result with the above code :
Desired Result :
I managed to solve the problem. Here's the code if anyone else is interested :
#include<GL/glut.h>
#include<vector>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<limits>
using namespace std;
const int n = 7;
class Point{
public:
int x, y;
Point(){
};
Point(int a, int b){
x = a;
y = b;
};
void set(int a, int b){
x = a;
y = b;
};
};
Point P[n];
int min(int x, int y)
{
if (x <= y) return x;
else return y;
}
int max(int x, int y)
{
if (x >= y) return x;
else return y;
}
double solve(int y, Point A, Point B)
{
if (y >= min(A.y, B.y) && y <= max(A.y, B.y))
{
return ((y * B.x) - (y * A.x) - (A.y * B.x) + (A.x * B.y)) / (B.y - A.y);
}
else return -1;
}
bool doubleComparison(double i, double j) { return (i < j); }
bool isVertex(int x, int y)
{
for (int i = 0; i < n; i++)
{
if (P[i].x == x && P[i].y == y) return 1;
}
return 0;
}
void scanfill()
{
int i, j, color = 1, k;
double x;
vector<double> inter[501];
for (j = 0; j < 500; j++)
{
for (k = 0; k < n - 1; k++)
{
x = solve(j, P[k], P[k + 1]);
if (x != -1 && !isVertex(x,j))
{
inter[j].push_back(x);
}
}
x = solve(j, P[n - 1], P[0]);
if (x != -1 && !isVertex(x, j))
{
inter[j].push_back(x);
}
}
for (j = 0; j < 500; j++)
{
sort(inter[j].begin(), inter[j].end(), doubleComparison);
}
for (j = 0; j < 500; j++)
{
glColor3f(0.0, 0.0, 1.0);
glBegin(GL_LINES);
for (vector<double>::iterator it = inter[j].begin(); it != inter[j].end(); it++)
{
glVertex2d(*it, j);
}
glEnd();
}
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 0.0, 0.0);
P[0] = Point(100, 235);
P[1] = (Point(100, 100));
P[2] = (Point(230, 140));
P[3] = (Point(40, 200));
P[4] = (Point(20, 60));
P[5] = (Point(300, 150));
P[6] = (Point(150, 111));
glBegin(GL_LINE_LOOP);
for (int i = 0; i < n; i++)
{
glVertex2i(P[i].x, P[i].y);
}
glEnd();
scanfill();
glFlush();
}
void init()
{
glClearColor(1.0, 1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 499.0, 0.0, 499.0);
}
void main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("scanline");
glutDisplayFunc(display);
init();
glutMainLoop();
}