#include "stdafx.h"
# include <iostream>
# include <string >
using namespace std ;
#include <fstream>
#include <gl\glut.h>
#include <math.h>
typedef GLfloat T;
GLfloat PI = 3.1415;
GLdouble wx,wy,wz;
bool curve = true; //Zeichne Kurve
bool in = false; // Maus auf Punk
bool showkh = false; //Zeige Konvexe Hülle
bool showp = true; // Zeige Punkte
struct Node {
T x;
T y;
T ax;
T gew;
Node * next;
};
struct List{ //Speichern der Punkte in Liste
Node * front,*back;
int size;
};
Node * ind = NULL; //Zeiger auf den Knoten des ausgewählten Punktes
List q;
void initialize(List &);
void push (List &, T , T , T);
void initialize(List & q){
q.front = q.back = NULL;
}
void push(List & q, T x , T y , T ax){
if(!q.front) {
q.front = q.back = new Node;
q.back->x = x ;
q.back->y = y ;
q.back->ax = ax ;
q.back->next = NULL;
q.size = 1;
q.back->gew = 1;
}
else {
Node * temp = q.back;
q.back = q.back->next = new Node ;
q.back->x = x;
q.back->y = y;
q.back->ax = ax;
q.back->next = NULL;
q.back->gew = 1;
q.size = q.size +1;
}
}
void increase(){ //Gewicht der Kontrollpunkte erhöhen
if(in) ind->gew++;
}
void decrease(){ //Gewicht der Kontrollpunkte reduzieren
if(in && (ind->gew > 1)) ind->gew--;
}
void new_controll_points(GLfloat ** & a) //Berechnung der gewichteten Kontrollpunkte
{
Node *temp = q.front;
for (int i=0; i<q.size; i++){
a[i][0] = temp->x * temp->gew;
a[i][1] = temp->y * temp->gew;
a[i][2] = 1 * temp->gew;
a[i][3] = 1 ;
temp = temp->next;
}
}
void draw_curve(GLfloat **p) //Zeichnen der Kurve
{
glPushMatrix();
glColor3f(1.0, 0.0, 0.0);
Node *temp = q.front;
// for(int i = 0;i<q.size;i++){
// cout<<"X werte in curve = "<< i+1<<" : " <<p[i][0]<<endl;
// cout<<"Y werte in curve = "<< i+1<<" : " <<p[i][1]<<endl;
//cout<<"Gewicht = "<< i+1<<" : " <<p[i][3]<<endl;
// }
glMap1f(GL_MAP1_VERTEX_4, 0,1, 4, q.size, &p[0][0]);
glMapGrid1f(40,0.0, 1.0);
glEvalMesh1(GL_LINE, 0, 40); // Darstellung der Kurve
glPopMatrix();
}
void bezier(){ //Belegung des Array der Koordinaten/Gewichte über Liste
if(q.size > 1){
GLfloat **gewp = new GLfloat*[q.size];
Node * temp = q.front;
GLfloat * _gewicht = new GLfloat[q.size];
for(int i = 0;i<q.size;i++){
_gewicht[i] = temp->gew;
gewp[i] = new GLfloat[4];
temp = temp->next;
}
//int k=0;
//for(Node *temp = q.front;temp;temp=temp->next){
//
// cout<<"X werte = "<< k+1<<" : " <<temp->x<<endl;
// cout<<"Y werte = "<< k+1<<" : " <<temp->y<<endl;
// cout<<"Gewicht = "<< k+1<<" : "<<temp->gew<<endl;
// k++;
//}
new_controll_points(gewp);
// for(int i = 0;i<q.size;i++){
// cout<<"X werte nach gew= "<< i+1<<" : " <<gewp[i][0]<<endl;
// cout<<"Y werte nach gew= "<< i+1<<" : " <<gewp[i][1]<<endl;
//cout<<"Gewicht = "<< i+1<<" : " <<_gewicht[i]<<endl;
// }
draw_curve(gewp); //Zeichnen der Bezierkurve
delete [] *gewp ;
delete [] gewp;
delete temp;
delete [] _gewicht;
}
}
void sort(){ //Sortieren der Punkte CCW ("Bubblesort")
Node* tmp1 = q.front;
Node* tmp2 = q.front;
while(tmp1 != NULL){
while(tmp2 != NULL){
if(tmp2->ax >= tmp1->ax){ //vertausche
GLfloat tauschax = tmp2->ax;
GLfloat tauschx = tmp2->x;
GLfloat tauschy = tmp2->y;
tmp2->ax = tmp1->ax;
tmp1->ax = tauschax;
tmp2->x = tmp1->x;
tmp1->x = tauschx;
tmp2->y = tmp1->y;
tmp1->y = tauschy;
}
tmp2 = tmp2->next;
}
tmp2 = q.front; //Zaehler 2 wieder reseten
tmp1 = tmp1->next; //Zaehler 1 um 1 element weiterschalten
}
}
void liste (void) //Zeichen der Punkte bzw konvexe Hülle (wird noch ausgelagert)
{
Node *l = q.front ;
glPolygonMode(GL_FRONT,GL_LINE);
if(showp){
glPointSize(5);
glBegin(GL_POINTS);
while(l){
glVertex3f(l->x,l->y,0);
l=l->next;
}
glEnd();
}
if(showkh){
glPolygonMode(GL_BACK,GL_LINE);
l=q.front;
glBegin(GL_POLYGON);
while(l){
glVertex3f(l->x,l->y,0);
l=l->next;
}
glEnd();
}
}
//Einstellung einiger OpenGL-Zustaende
void init_opengl(void)
{
glClearColor(0,0,0,0);
glEnableClientState(GL_VERTEX_ARRAY);
glLineWidth(2);
glPointSize(4);
glEnable(GL_MAP1_VERTEX_4);
}
//Darstellung der Szene
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glColor3f(1.0, 0.0, 0.0);
liste();
glPolygonMode(GL_FRONT,GL_FILL);
if(curve) bezier();
glFinish();
glutSwapBuffers();
}
void reshape(int w, int h)
{
GLfloat aspect_1 = (GLfloat)h / (GLfloat)w;
GLfloat aspect_2 = (GLfloat)w / (GLfloat)h;
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-4.0, 4.0, -4.0 * aspect_1, 4.0 * aspect_1, -4.0, 4.0);
else
glOrtho(-4.0 * aspect_2, 4.0 * aspect_2, -4.0, 4.0, -4.0, 4.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// Tastaturabfragen
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
//glutmainloop() beenden
case 27: // Escape-Taste
exit(0);
break;
// case 'c' : bezier();break;
case 's' : curve = !curve;break;
case '+' : increase();break;
case '-' : decrease();break;
case 'k' : showkh = !showkh;break;
case 'p' : showp = !showp;break;
}
glutPostRedisplay();
}
bool punkt(GLfloat x, GLfloat y) //Zeigt die Maus auf einen Punkt ?
{
Node * tempo = q.front;
while(tempo)
{
if((x < (tempo->x + 0.07)) && (x > (tempo->x - 0.07)) && (y < (tempo->y + 0.07))
&& (y > (tempo->y - 0.07)))
{
ind = tempo;
return true;
}
tempo=tempo->next;
}
return false;
}
GLfloat arc(GLfloat x,GLfloat y){ //Berechnung der Winkel zum sortieren
GLfloat temp = atan(y/x);
if(((x <= 0) && (y>= 0)) || ((x<= 0) && (y < 0))) temp += PI;
else if((x > 0) && (y< 0)) temp +=2*PI;
return temp;
}
void maus(int button, int state, int x, int y) //Beim drücken der linken Maustaste wird ein neuer Punkt generiert
{
GLint viewport[4]; // Speicherplatz fuer akt. Viewport
GLdouble mvmatrix[16], projmatrix[16];// Speicherplatz fuer akt. Matrizen
GLint realy; // Korrigierte y Koordinate
//
switch (button) {
case GLUT_LEFT_BUTTON: // Linke Maustaste
if (state == GLUT_DOWN) { // Taste gedrueckt
glGetIntegerv (GL_VIEWPORT, viewport);
glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);
realy = viewport[3] - (GLint) y - 1;
gluUnProject ((GLdouble) x, (GLdouble) realy, 0.0,
mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
in = punkt(wx,wy);
if(!in ){
GLfloat arct = arc(wx,wy);
push(q,wx,wy,arct);
sort();
}
}
if(state == GLUT_UP) sort(); //Wird ein Punkt gezogen, werden beim loslassen der Maustaste die Punkte neu sortiert
break;
case GLUT_RIGHT_BUTTON: // Rechte Maustaste
if (state == GLUT_DOWN)
exit(0);
break;
}
glutPostRedisplay();
}
void mausbewegung(int x,int y){ //Mausbewegung bei gedrückter linker Maustaste
GLint viewport[4]; // Speicherplatz fuer akt. Viewport
GLdouble mvmatrix[16], projmatrix[16];// Speicherplatz fuer akt. Matrizen
GLint realy;
glGetIntegerv (GL_VIEWPORT, viewport);
glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);
realy = viewport[3] - (GLint) y - 1;
gluUnProject ((GLdouble) x, (GLdouble) realy, 0.0,
mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
if(GLUT_LEFT_BUTTON == GLUT_DOWN){
if(ind){
ind->x = wx;
ind->y = wy;
ind->ax = arc(wx,wy);
}
}
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv); // Initialisierung der GLUT
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (1000, 1000);
glutCreateWindow (argv[0]);
init_opengl();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(maus);
glutMotionFunc(mausbewegung);
glutKeyboardFunc (keyboard);
//Nun beginnt es;
glutMainLoop();
return 0;
}