A implementação segue abaixo, e para mais informações sobre o algoritmo clique aqui.
/*
* Implementacao do algoritmo de Cohen-Sutherland
* para o recorte de segmentos de reta
*
* Implementacao baseada no livro:
* Computer Graphics: Principles and Practice
*
* COMANDOS:
* r - recorta
* espaco - apaga vertices e linha
*
*/
//diretivas de compilacao condicional
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
//macro que define numero de vertices
#define N_VERTEX 2
//macros que definem as posicoes das regioes
#define TOP 8
#define BOTTOM 4
#define LEFT 1
#define RIGHT 2
//macros que definem os limites para a regiao 0000
#define X_MAX 0.5 //xmax
#define X_MIN -0.5 //xmin
#define Y_MAX 0.5 //ymax
#define Y_MIN -0.5 //ymin
GLint currentVertex = 0; //Vertice corrente
GLdouble modelview[16]; //matriz modelview
GLdouble projection[16]; //matriz projecao
/*
Dados do vetor viewport:
viewport[0]=x
viewport[1]=y
viewport[2]=width
viewport[3]=height
*/
GLint viewport[4];
//variaveis utilizadas para pegar as coordenadas do mouse
GLfloat winX, winY, winZ;
GLdouble posX, posY, posZ;
//Matriz que guarda as coordenadas dos vertices
GLfloat vertexes[6][3] = {
{0.0, 0.0, 0.0},
{0.0, 0.0, 0.0},
{0.0, 0.0, 0.0},
{0.0, 0.0, 0.0},
{0.0, 0.0, 0.0},
{0.0, 0.0, 0.0}
};
typedef int outcode;
outcode code;
//Desenha pontos
void
drawPoints(){
glPointSize(5.0);//Definindo expessura do ponto
glBegin(GL_POINTS);
if(currentVertex > 0){
for (int i = 0; i < currentVertex; i++)
glVertex3fv(&vertexes[i][0]);//desenha
}
glEnd();
}
//verifica posicao
outcode
CompOutCode (double x, double y){
code = 0;//dentro de 0000
if (y > Y_MAX){
code = TOP; //topo
}
else{
if(y < Y_MIN){
code = BOTTOM; //baixo
}
if(x > X_MAX){
code = RIGHT; //direita
}
if(x < X_MIN){
code = LEFT; //esquerda
}
}
return code;
}
//Algoritmo de Cohen-Sutherland
void
CohenSutherlandLineClipAndDraw(double x0, double y0, double x1,double y1, double xmin, double xmax, double ymin, double ymax){
bool accept, done;//variaveis de verificacao
outcode outcode0, outcode1, outcodeOut;//declaracao das variaveis do tipo outcode
accept = done = false;//inicializando variaveis de verificacao
outcode0 = CompOutCode(x0, y0);//pega posicao a qual o ponto1 se encontra
outcode1 = CompOutCode(x1, y1);//pega posicao a qual o ponto2 se encontra
while (!done){
if (!outcode0 && !outcode1){
accept = done = true;//aceita e sai do loop
}
else{
if(outcode0 & outcode1){//quanto esta totalmente fora de 0000
done = true;//termina o loop
currentVertex = 0;//zera a quantidade de vertices
}
else{
//Houve falha em ambos dos testes, entao e' calculado o segmento da linha
//a partir de um ponto fora de uma intersecção com a borda do retangulo.
//Pelo menos um ponto de extremidade está fora do retângulo, aqui e' pego esse ponto
outcodeOut = outcode0 ? outcode0 : outcode1;
double x,y;
//Agora achando o ponto de interseccao
if(outcodeOut & TOP){//Divide linha ao topo do retangulo
x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0);
y = ymax;
}
else{
if(outcodeOut & BOTTOM){//Divide linha na parte de baixo do retangulo
x = x0 + (x1 - x0) * (ymin - y0) / (y1 - y0);
y = ymin;
}
else{
if(outcodeOut & RIGHT){//Divide linha na borda direita do retangulo
y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0);
x = xmax;
}
else{
if(outcodeOut & LEFT){//Divide linha na borda esquerda do retangulo
y = y0 + (y1 - y0) * (xmin - x0) / (x1 - x0);
x = xmin;
}
}
}
}
//Agora movemos o ponto que esta fora p/ a interseccao do retangulo
if (outcodeOut == outcode0) {
x0 = x;
y0 = y;
outcode0 = CompOutCode(x0, y0);
} else {
x1 = x;
y1 = y;
outcode1 = CompOutCode(x1, y1);
}
}
}
}
if(accept){//Atribui novos valores para os vertices
vertexes[0][0] = x0;//Coordenada x do ponto 1
vertexes[0][1] = y0;//Coordenada y do ponto 1
vertexes[1][0] = x1;//Coordenada x do ponto 2
vertexes[1][1] = y1;//Coordenada y do ponto 2
}
}
//Imprime strings com o codigo de 4 bits de cada regiao
//parametros: float posStrX: posicao x da string
// float posStrY: posicao y da string
// const char *str: string a ser exibida
void
printStrings(float posStrX, float posStrY, const char *str){
//mudando cor da linha para verde
glColor3f (0.0, 1.0, 0.0);
//posicionando string na tela
glRasterPos2f(posStrX, posStrY);
//String exibida na tela
char* p = (char*) str; //atribui da variavel *p
while (*p != '\0') {//percorre string ate o final
//funcao da glut que imprime char por char na tela
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,*p++);
}
}
//Desenha linhas que delimitam as regioes
void
drawRegionLines(){
glBegin(GL_LINES);
//mudando cor da linha para branco
glColor3f (1.0, 1.0, 1.0);
//desenha linhas das regioes
for(float i = -0.5;i <= 0.5; i = i + 1)
{
glVertex2f( -1, i);//coordenada inicial da linha
glVertex2f( 1, i);//coordenada final da linha
}
//desenha linhas das regioes
for(float i = -0.5;i <= 0.5; i = i + 1){
glVertex2f( i, -1);//coordenada inicial da linha
glVertex2f( i, 1);//coordenada final da linha
}
glEnd();
}
//linha entre os vertices e' desenhada aqui
void
drawLineBetweenVertexes(){
glBegin(GL_LINE_STRIP);
//Setando a cor da linha para amarelo
glColor3f(1.0f, 1.0f, 0.0f);
//se a quantidade de vertices for satisfeita
if(currentVertex == N_VERTEX){//entao as linhas entre os vertices sao desenhadas
for (int i = 0; i < N_VERTEX; i++)
glVertex3fv(&vertexes[i][0]); //a linha e' desenhada com a funcao glVerte3fv
}
glEnd();
}
//rotina callback de display OpenGL
void
renderScene(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Define valores p/ glClear
glClearColor(0.0, 0.0, 0.0, 0.0);
// Mudando a cor para vermelho
// R G B
glColor3f(1.0f, 0.0f, 0.0f);
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );
//Aqui sao desenhados os pontos(mostrados a partir do clique do mouse)
drawPoints();
//linha entre os vertices e' desenhada aqui
drawLineBetweenVertexes();
printStrings(-0.8, 0.7, "1001");//imprimindo string 1001
printStrings(-0.05, 0.7, "1000");//imprimindo string 1000
printStrings( 0.7, 0.7, "1010");//imprimindo string 1010
printStrings(-0.8, 0.0, "0001");//imprimindo string 0001
printStrings(-0.05, 0.0, "0000");//imprimindo string 0000
printStrings( 0.7, 0.0, "0010");//imprimindo string 0010
printStrings(-0.8, -0.8, "0101");//imprimindo string 0101
printStrings(-0.05,-0.8, "0100");//imprimindo string 0100
printStrings( 0.7, -0.8, "0110");//imprimindo string 0110
drawRegionLines();//Desenha linhas que delimitam as regioes
glutSwapBuffers();//Fazendo troca de Buffers
}
//Funcao callback p/ teclado
void
keyboard (unsigned char key, int x, int y){
switch (key){
case 27://se pressionar ESC
exit(0);//sai do programa
break;
case 'r'://Faz chamada ao algoritmo Cohen-Sutherland para recorte
CohenSutherlandLineClipAndDraw(vertexes[0][0], vertexes[0][1], vertexes[1][0], vertexes[1][1], X_MIN, X_MAX, Y_MIN, Y_MAX);
glutPostRedisplay();//faz redisplay
break;
case ' '://comando que apaga linhas e vertices
currentVertex = 0;//zera quantidade de vertices
glutPostRedisplay();//faz redisplay
break;
}
}
//funcao callback para mouse
void
mouse(int button, int state, int x, int y){
//caso botao do mouse seja pressionado
if (state == GLUT_DOWN){
//passando para coordenadas do mundo real
winX = (float)x; //passando o valor de x por cast, pois a variavel winX e' do tipo GLfloat
winY = (float)viewport[3] - (float)y; //viewport[3] e y sao inteiros, por isso sao passados por cast p/ winY que e' GLfloat
//funcao que pega as coordenadas de x, y
gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
//guardando a posicao de x quando pressiona o botao direito do mouse
vertexes[currentVertex][0] = posX;
//guardando a posicao de y quando pressiona o botao direito do mouse
vertexes[currentVertex][1] = posY;
//incrementa a quantidade de vertices para o desenho dos pontos do
//vertice e para o desenho da linha
if(currentVertex < N_VERTEX){
currentVertex++;//incrementando
}
//fazendo redisplay
glutPostRedisplay();
}
}
//Funcao principal
int
main(int argc, char *argv[]){
//inicializando glut
glutInit(&argc, argv);
//definindo tamanho da tela
glutInitWindowSize(800,600);
//definindo posicao inicial da janela
glutInitWindowPosition(100,15);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
//definindo nome da janela
glutCreateWindow("Algoritmo Cohen-Sutherland");
//rotina callback de display OpenGL
glutDisplayFunc(renderScene);
//Rotina callback para teclado
glutKeyboardFunc(keyboard);
//rotina callback para o mouse
glutMouseFunc(mouse);
//loop principal do glut
glutMainLoop();
return EXIT_SUCCESS;
}

Nenhum comentário:
Postar um comentário