#include <qcolordialog.h>

#include "Display3D.h"
#include <GL/glu.h>
//#include <GL/glut.h>
#include <map>


#include "Projection2DData.h"

#include "GraphicsDataFields.h"
#include "UniversalGraphicsSettings.h"

#include <iostream>

//void bitmap_output(int x, int y,int z, char*string,void*Font){
//  int len=(int)strlen(string),i;
//  glRasterPos3f(x,y,z);
//  for(i=0;i<len;i++)
//    glutBitmapCharacter(Font,string[i]);
//}


using namespace std;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Display3D::Display3D(QWidget *parent, const char *name)
    : QGLWidget(parent, name),GraphicsBase()
{
    drawingAllowed=false;
    setFormat(QGLFormat(DoubleBuffer | DepthBuffer));
    currentZoomFactor=1;
    enlargementFactor=1.5;
//     rotationX = 27;
//     rotationY = -11;
//     rotationZ = 0;
    legendOffset=0;
        


    faceColors[0] = red;
    faceColors[1] = green;
    faceColors[2] = blue;
    faceColors[3] = cyan;
    faceColors[4] = yellow;
    faceColors[5] = magenta;
    
    cubeCoords.assign(6,vector<vector<GLfloat> >(4,vector<GLfloat>(3,0.0)));
    cubeCoordsVec.assign(24,0.0);

       //vertex 0
   cubeCoordsVec[0]=0;
   cubeCoordsVec[1]=0;
   cubeCoordsVec[2]=0;
       
   //vertex 1
   cubeCoordsVec[3]=1;
   cubeCoordsVec[4]=0;
   cubeCoordsVec[5]=0;

   //vertex 2
   cubeCoordsVec[6]=1;
   cubeCoordsVec[7]=1;
   cubeCoordsVec[8]=0;


   //vertex 3
   cubeCoordsVec[9]=0;
   cubeCoordsVec[10]=1;
   cubeCoordsVec[11]=0;

      
   //vertex 4
   cubeCoordsVec[12]=0;
   cubeCoordsVec[13]=0;
   cubeCoordsVec[14]=1;

   //vertex 5
   cubeCoordsVec[15]=1;
   cubeCoordsVec[16]=0;
   cubeCoordsVec[17]=1;

   //vertex 6
   cubeCoordsVec[18]=1;
   cubeCoordsVec[19]=1;
   cubeCoordsVec[20]=1;
    
   //vertex 7
   cubeCoordsVec[21]=0;
   cubeCoordsVec[22]=1;
   cubeCoordsVec[23]=1;

        
    sizeX=100;
    sizeY=100;
    sizeZ=100;

   data3DConf.sizeX=10;
   data3DConf.sizeY=10;
   data3DConf.sizeZ=10;

   data3DConf.rotationX = 27;
   data3DConf.rotationY = -11;
   data3DConf.rotationZ = 0;
       
    
    sizeL=100;
    sizeM=100;
    sizeN=100;
    
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Display3D::produceImage(QImage & image){
   image=grabFrameBuffer();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Display3D::setSizeLMN(unsigned int _sizeL , unsigned int _sizeM ,unsigned int _sizeN){
   sizeL=_sizeL;
   sizeM=_sizeM;
   sizeN=_sizeN;

   maxDimension=sizeL;
   
   if(sizeM>maxDimension)
      maxDimension=sizeM;
   if(sizeN>maxDimension)
      maxDimension=sizeN;

   data3DConf.sizeX= sizeL;
   data3DConf.sizeY= sizeM;
   data3DConf.sizeZ= sizeN;

            
   
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::setInitialConfigure3DData(const Configure3DData & _data){

   sizeL=_data.sizeL;
   sizeM=_data.sizeM;
   sizeN=_data.sizeN;

   maxDimension=sizeL;
   if(sizeM>maxDimension)
      maxDimension=sizeM;
   if(sizeN>maxDimension)
      maxDimension=sizeN;

   data3DConf.sizeX= _data.sizeX;
   data3DConf.sizeY= _data.sizeY;
   data3DConf.sizeZ= _data.sizeZ;

   data3DConf.rotationX= _data.rotationX;
   data3DConf.rotationY= _data.rotationY;
   data3DConf.rotationZ= _data.rotationZ;

}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Display3D::initializeGL()
{
    if(!drawingAllowed)
    return;

    qglClearColor(black);
    glShadeModel(GL_FLAT);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
//     int argc=0;
//     char **argv=0;
//     glutInit(&argc,argv);
//     glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Display3D::setDimensions(GLfloat _sizeX,GLfloat _sizeY, GLfloat _sizeZ ){

//    data3DConf.sizeX=_sizeX;
//    data3DConf.sizeY=_sizeY;
//    data3DConf.sizeZ=_sizeZ;

/*   sizeX=data3DConf.sizeX*currentZoomFactor;
   sizeY=data3DConf.sizeY*currentZoomFactor;
   sizeZ=data3DConf.sizeZ*currentZoomFactor*3;*/

   sizeX=_sizeX;
   sizeY=_sizeY;
   sizeZ=_sizeZ;

//    cerr<<" set Dimension sizeX="<<sizeX<<" sizeY="<<sizeY<<" sizeZ="<<sizeZ<<endl;
   
   //glOrtho(0,sizeX*enlargementFactor,0,sizeY*enlargementFactor,0,sizeZ*enlargementFactor);
   
   //have to call these two functions to get QGLWidget beign refreshed and resized using glOrtho
   //without those calls you do widget will not change
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();

   glOrtho(
            0,data3DConf.sizeX*enlargementFactor*currentZoomFactor,
            0,data3DConf.sizeY*enlargementFactor*currentZoomFactor,
            0,data3DConf.sizeZ*enlargementFactor*currentZoomFactor
   );
   glMatrixMode(GL_MODELVIEW);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Display3D::resizeGL(int width, int height)
{
   //This function is responsible for view resizing. It is called every time something happens to QGLWidget
    if(!drawingAllowed)
    return;
    
    glViewport(0, 0, width, height);
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //glOrtho(0,sizeX*enlargementFactor,0,sizeY*enlargementFactor,0,sizeZ*enlargementFactor);
//     cerr<<"resizeGL sizeX="<<sizeX<<" sizeY="<<sizeY<<" sizeZ="<<sizeZ<<endl;
//     cerr<<"data3DConf.sizeX="<<data3DConf.sizeX<<" data3DConf.sizeY="<<data3DConf.sizeY<<" data3DConf.sizeZ="<<data3DConf.sizeZ<<endl;
    
    glOrtho(
            0,data3DConf.sizeX*enlargementFactor*currentZoomFactor,
            0,data3DConf.sizeY*enlargementFactor*currentZoomFactor,
            0,data3DConf.sizeZ*enlargementFactor*currentZoomFactor
   );
    glMatrixMode(GL_MODELVIEW);
    
    
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Display3D::paintGL()
{
    if(!drawingAllowed)
    return;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/*    cerr<<" sizeL="<<sizeL;
    cerr<<" sizeM="<<sizeM;
    cerr<<" sizeN="<<sizeN;
    cerr<<" sizeX="<<sizeX;
    cerr<<" sizeY="<<sizeY;
    cerr<<" sizeZ="<<sizeZ;
    cerr<<endl;*/
//     cerr<<"FCN ptr="<<drawFcnPtr<<endl;

    
    (this->*drawFcnPtr)();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Display3D::initDraw(){

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    
     glRotatef(data3DConf.rotationX, 1.0, 0.0, 0.0);
     glRotatef(data3DConf.rotationY, 0.0, 1.0, 0.0);
     glRotatef(data3DConf.rotationZ, 0.0, 0.0, 1.0);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Display3D::draw()
{
    

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glRotatef(data3DConf.rotationX, sizeX/2, 0.0, 0.0);
    glRotatef(data3DConf.rotationY, 0.0, sizeY/2, 0.0);
    glRotatef(data3DConf.rotationZ, 0.0, 0.0, sizeZ/2);

    
    
    qglColor(red);
    ///axes
    //x
    glBegin(GL_LINE);
      glVertex3f(10,10,10);
      glVertex3f(sizeX,10,10);
    glEnd();
    qglColor(green);
    //y
    glBegin(GL_LINE);
      glVertex3f(10,10,10);
      glVertex3f(10,sizeY,10);
    glEnd();

    qglColor(blue);
    //z
    glBegin(GL_LINE);
      glVertex3f(10,10,10);
      glVertex3f(10,10,sizeZ);
    glEnd();
    
    return;


}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Display3D::mousePressEvent(QMouseEvent *event)
{
    lastPos = event->pos();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::mouseMoveEvent(QMouseEvent *event)
{
    GLfloat dx = (GLfloat)(event->x() - lastPos.x()) / width();
    GLfloat dy = (GLfloat)(event->y() - lastPos.y()) / height();

    if (event->state() & LeftButton) {
        data3DConf.rotationX -= 180 * dy;

        updateGL();
    } else if (event->state() & RightButton) {
        data3DConf.rotationY -= 180 * dx;

        updateGL();
    }
    lastPos = event->pos();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::mouseDoubleClickEvent(QMouseEvent *event)
{
    int face = faceAtPosition(event->pos());
    if (face != -1) {
        QColor color = QColorDialog::getColor(faceColors[face],
                                              this);
        if (color.isValid()) {
            faceColors[face] = color;
            updateGL();
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int Display3D::faceAtPosition(const QPoint &pos)
{
    const int MaxSize = 512;
    GLuint buffer[MaxSize];
    GLint viewport[4];

    glGetIntegerv(GL_VIEWPORT, viewport);
    glSelectBuffer(MaxSize, buffer);
    glRenderMode(GL_SELECT);

    glInitNames();
    glPushName(0);

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluPickMatrix((GLdouble)pos.x(),
                  (GLdouble)(viewport[3] - pos.y()),
                  5.0, 5.0, viewport);
    draw();
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    if (!glRenderMode(GL_RENDER))
        return -1;
    return buffer[3];
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::drawCube(GLfloat x, GLfloat y , GLfloat z , GLfloat side){

   static GLubyte  cubeIndices[24]={4,5,6,7,1,2,6,5,0,1,5,4,0,3,2,1,0,4,7,3,2,3,7,6};
   static GLubyte  borderIndices[24]={0,1,1,2,2,3,3,0,4,5,5,6,6,7,7,4,0,4,1,5,2,6,3,7};
   

   glEnableClientState(GL_VERTEX_ARRAY);
   glVertexPointer(3,GL_FLOAT,0,&cubeCoordsVec[0]);
   qglColor(white);
   glPushMatrix();
   glScalef(sizeX,sizeY,10.0);
   glDrawElements(GL_QUADS,24,GL_UNSIGNED_BYTE,cubeIndices);

   
   glPopMatrix();
   qglColor(yellow);
   glPushMatrix();
   glTranslatef(x,y,z);
   glScalef(side,side,side);
   
   glDrawElements(GL_QUADS,24,GL_UNSIGNED_BYTE,cubeIndices);
   qglColor(magenta);
   glDrawElements(GL_LINES,24,GL_UNSIGNED_BYTE,borderIndices);
   glPopMatrix();
   glDisableClientState(GL_VERTEX_ARRAY);
      
                   


}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::drawCube(GLfloat x, GLfloat y , GLfloat z , GLfloat side, const QColor &color){


   static GLubyte  cubeIndices[24]={4,5,6,7,1,2,6,5,0,1,5,4,0,3,2,1,0,4,7,3,2,3,7,6};
   
   glEnableClientState(GL_VERTEX_ARRAY);
   glVertexPointer(3,GL_FLOAT,0,&cubeCoordsVec[0]);


   qglColor(color);
   glPushMatrix();
   glTranslatef(x,y,z);      
   glDrawElements(GL_QUADS,24,GL_UNSIGNED_BYTE,cubeIndices);

   glPopMatrix();
   glDisableClientState(GL_VERTEX_ARRAY);
      
                   


}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::drawSquare(GLfloat x, GLfloat y , GLfloat z , GLfloat side, const QColor &color){

   static GLubyte  squareIndices[4]={1,2,6,5};
   
   glEnableClientState(GL_VERTEX_ARRAY);
   glVertexPointer(3,GL_FLOAT,0,&cubeCoordsVec[0]);

   qglColor(color);
   glPushMatrix();
   glTranslatef(x,y,z);
   glScalef(side,side,side);
   glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,squareIndices);
   glPopMatrix();
   glDisableClientState(GL_VERTEX_ARRAY);
      
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Display3D::drawRectangle(GLfloat x, GLfloat y , GLfloat z , GLfloat width , GLfloat height, const QColor &color){

   static GLubyte  rectangleIndices[4]={1,2,6,5};
   
   glEnableClientState(GL_VERTEX_ARRAY);
   glVertexPointer(3,GL_FLOAT,0,&cubeCoordsVec[0]);

   qglColor(color);
   glPushMatrix();
   glTranslatef(x,y,z);
   glScalef(1,width,height);
   glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,rectangleIndices);
   glPopMatrix();
   glDisableClientState(GL_VERTEX_ARRAY);



}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::paintLattice(){

   if(!drawingAllowed)
   return;
          
   field3DGraphicsDataPtr = & graphFieldsPtr->field3DGraphicsData;
   drawFcnPtr=&Display3D::paint3DLattice;
   updateGL();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::paintConcentrationLattice(){

   if(!drawingAllowed)
   return;

   field3DGraphicsDataPtr = & graphFieldsPtr->field3DGraphicsData;
   drawFcnPtr=&Display3D::paint3DConcentrationLattice;
   updateGL();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::paintCellVectorFieldLattice(){
   if(!drawingAllowed)
   return;
   
   field3DGraphicsDataPtr = & graphFieldsPtr->field3DGraphicsData;
   drawFcnPtr=&Display3D::paint3DCellVectorFieldLattice;
   updateGL();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool Display3D::checkIfInside(unsigned int x, unsigned y, unsigned z){

   //this function checks if a given pixed is fully surrounded by other non-medium pixels
   
   static field3DGraphicsData_t & field3DGraphicsData = * field3DGraphicsDataPtr;
   static unsigned int maxX=sizeL-1;
   static unsigned int maxY=sizeM-1;
   static unsigned int maxZ=sizeN-1;
   
   field3DGraphicsData= *field3DGraphicsDataPtr;
   
   if(x==0 || y==0 || z==0 || x==maxX||y==maxY||z==maxZ){
      return false;
   }else{
      if(
            0 != field3DGraphicsData[x-1][y][z].type &&
            0 != field3DGraphicsData[x+1][y][z].type &&
            0 != field3DGraphicsData[x][y-1][z].type &&
            0 != field3DGraphicsData[x][y+1][z].type &&
            0 != field3DGraphicsData[x][y][z-1].type &&
            0 != field3DGraphicsData[x][y][z+1].type
         )
         //return false;
         return true;
      else
         //return true;
         return false;
   }
   
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::prepareScene(){
   

   if(currentZoomFactor!=univGraphSetPtr->zoomFactor){
      currentZoomFactor=univGraphSetPtr->zoomFactor;

      //IMPORTANT!
      //glOrtho (or setDimensions where glOrtho is actually called )must be called before setFixed Size to avoid problems when zoomingIN
//       setDimensions(currentZoomFactor*sizeL ,currentZoomFactor*sizeM,currentZoomFactor*sizeN );
//       setFixedSize(currentZoomFactor*maxDimension,currentZoomFactor*maxDimension);
      
   }
   setDimensions( currentZoomFactor*sizeL, currentZoomFactor*sizeM, currentZoomFactor*sizeN );
   //setDimensions( data3DConf.sizeX, data3DConf.sizeY, data3DConf.sizeZ );
   setFixedSize( currentZoomFactor*maxDimension, currentZoomFactor*maxDimension);
   
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    
    
   glRotatef(data3DConf.rotationX, 1.0, 0.0, 0.0);
   glRotatef(data3DConf.rotationY, 0.0, 1.0, 0.0);
   glRotatef(data3DConf.rotationZ, 0.0, 0.0, 1.0);

   glPushMatrix();
   glScalef(univGraphSetPtr->zoomFactor,univGraphSetPtr->zoomFactor,univGraphSetPtr->zoomFactor);

   glTranslatef(0,0,0);

   gluLookAt(sizeL*enlargementFactor,0,0,0,0,0,0,0,1);
//    cerr<<"prepare scene"<<endl;
    qglColor(red);
    ///axes
    //x
    glBegin(GL_LINE);
      glVertex3f(0,0,0);
      glVertex3f(sizeL,0,0);
    glEnd();
    qglColor(green);
    //y
    glBegin(GL_LINE);
      glVertex3f(0,0,0);
      glVertex3f(0,sizeM,0);
    glEnd();

    qglColor(blue);
    //z
    glBegin(GL_LINE);
      glVertex3f(0,0,0);
      glVertex3f(0,0,sizeN);
    glEnd();

    ///markers of eol
    glBegin(GL_LINE);
      glVertex3f(0,0,sizeN);
      glVertex3f(0,10,sizeN);
      glVertex3f(0,sizeM,0);
      glVertex3f(0,sizeM,10);
      glVertex3f(sizeL,0,0);
      glVertex3f(sizeL,10,0);
    glEnd();

    

   

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
unsigned int Display3D::legendDimension(std::string location, unsigned int &rectWidth,unsigned int & rectHeight,std::string type){
   unsigned int minRectWidth=8;
   unsigned int minNumberOfRect=5;
   unsigned int numberOfRect;
   
   if(location=="d"){///down
      numberOfRect=maxDimension/minRectWidth;
   }
   else{
      return 0;
   }

   if(type=="colormap"){
      numberOfRect=numberOfLegendBoxes;
   }
   if(type=="vector"){
      numberOfRect=numberOfLegendBoxesVector;
   }

   //numberOfRect=numberOfLegendBoxes;
   
//    if(numberOfRect<minNumberOfRect)
//       return 0;


   if(location=="d"){///right
      rectWidth=maxDimension*enlargementFactor/numberOfRect;
      rectHeight=(legendWidth/2);
      return numberOfRect;
   }

   return 0;  
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::paintLegend( float minConcentration, float maxConcentration,std::string location,std::string type){


   unsigned int rectWidth;
   unsigned int rectHeight;
   
   float _min=minConcentration;
   float _max=maxConcentration;
   QColor c(0,0,0);

   
   unsigned int numberOfRectangles = legendDimension( location , rectWidth, rectHeight,type);
   

   
   if(!numberOfRectangles){
      return;
   }

   unsigned int numAcc;
   if(type=="colormap"){
      numAcc=numberAccuracy;
   }
   
   if(type=="vector"){
      numAcc=numberAccuracyVector;
   }

   ///drawing legend - colormap

   
   //unsigned int maxNumberOfExtraPixels=maxDimension*univGraphSetPtr->zoomFactor-numberOfRectangles*rectWidth;
   unsigned int maxNumberOfExtraPixels=enlargementFactor*maxDimension-numberOfRectangles*rectWidth;
   unsigned int extraPixelCounter=0;
   unsigned int extraWidth=0;
//    cerr<<"maxNumberOfExtraPixels="<<maxNumberOfExtraPixels<<endl;
//    cerr<<"numberOfRectangles="<<numberOfRectangles<<endl;
   float percentage;

   if(maxNumberOfExtraPixels){
        extraWidth=1; 
   }
   
   glPushMatrix();
   //Had to do this to get legend display properly when changing 3D display sizes
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();

   glOrtho(
            0,sizeL*enlargementFactor*currentZoomFactor,
            0,sizeM*enlargementFactor*currentZoomFactor,
            0,sizeN*enlargementFactor*currentZoomFactor
   );
   glMatrixMode(GL_MODELVIEW);
   //Had to do this to get legend display properly when changing 3D display sizes - end
   
   glScalef(univGraphSetPtr->zoomFactor,univGraphSetPtr->zoomFactor,univGraphSetPtr->zoomFactor);
   
   gluLookAt(sizeL*enlargementFactor,0,0,0,0,0,0,0,1);

   
   for(unsigned int i = 0 ; i < numberOfRectangles ; ++i){
       percentage = percentageQuantity((i*(_max-_min))/(numberOfRectangles-1)+_min,_min,_max);
       c.setHsv( (int)((1.0-percentage)*255), 255,255 );
//        cerr<<"i*rectWidth+extraPixelCounter="<<i*rectWidth+extraPixelCounter<<" rectWidth+extraWidth="<<rectWidth+extraWidth<<
//        " rectHeight="<<rectHeight<<" rectWidth="<<rectWidth<<" maxDiim="<<maxDimension<<endl;

//       drawRectangle(maxDimension , i*rectWidth+extraPixelCounter , 0 , rectWidth+extraPixelCounter,rectHeight-i, c);
         drawRectangle(
                        maxDimension , (i*rectWidth+extraPixelCounter)/**data3DConf.sizeY/(float)sizeM*/ ,
                        0 , (rectWidth+extraWidth)/**data3DConf.sizeY/(float)sizeM*/ ,rectHeight, c
                        );
         
         qglColor(QColor(white));
         //notice rectWidth/enlargementFactor - this due to the fact that renderText uses "widget Coordinates"
         //whereas QGLWidget uses openGL scaled coordinates - and those where prescaled with elargementFactor
         
         renderText (
                     ((i+0.0)*rectWidth/enlargementFactor +extraPixelCounter)*univGraphSetPtr->zoomFactor,
                     currentZoomFactor*(maxDimension+legendWidth/2-0.2),
                     QString().setNum(_min+i*(_max-_min)/(numberOfRectangles-1),'g',numberAccuracy)
                     );
         
       if(extraPixelCounter<maxNumberOfExtraPixels){
          ++extraPixelCounter;
       }else{
         extraWidth=0;
       }

   }
   glPopMatrix();
   
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Display3D::prepareSceneColorMap(){

   legendOffset=0;

   if(currentZoomFactor!=univGraphSetPtr->zoomFactor){
      currentZoomFactor=univGraphSetPtr->zoomFactor;

      //IMPORTANT!
      //glOrtho (or setDimensions where glOrtho is actually called )must be called before setFixed Size to avoid problems when zoomingIN
//       setDimensions(currentZoomFactor*sizeL ,currentZoomFactor*sizeM,currentZoomFactor*(sizeN) );
//       if(legendEnable){
//          cerr<<"setFixedSize 3D colormap legendEnable ON"<<endl;
//          setFixedSize(currentZoomFactor*maxDimension,currentZoomFactor*(maxDimension+legendWidth));
//       }else{
//          cerr<<"setFixedSize 3D colormap legendEnable OFF"<<endl;
//          setFixedSize(currentZoomFactor*maxDimension,currentZoomFactor*(maxDimension));
//       }
      
   }

      setDimensions(currentZoomFactor*sizeL ,currentZoomFactor*sizeM,currentZoomFactor*(sizeN) );
      //setDimensions( data3DConf.sizeX, data3DConf.sizeY, data3DConf.sizeZ );
      if(legendEnable){
//          cerr<<"setFixedSize 3D colormap legendEnable ON"<<endl;
         setFixedSize(currentZoomFactor*maxDimension,currentZoomFactor*(maxDimension+legendWidth));
      }else{
//          cerr<<"setFixedSize 3D colormap legendEnable OFF"<<endl;
         setFixedSize(currentZoomFactor*maxDimension,currentZoomFactor*(maxDimension));
      }
   
   
/*   cerr<<"sizeX="<<sizeX<<" sizeY="<<sizeY<<" sizeZ="<<sizeZ<<endl;
   cerr<<"sizeL="<<sizeL<<" sizeM="<<sizeM<<" sizeN="<<sizeN<<endl;*/
   
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
   
//     paintLegend(0,1,"d");
    
//        //glColor3f(0,0,1);
//     qglColor(yellow);
//     cerr<<"printing 3D text"<<endl;
//     //bitmap_output(sizeX,10,10,"Y=sin(3*X*PIE)",GLUT_BITMAP_TIMES_ROMAN_10);
//     bitmap_output(0,0,0,"Y=sin(3*X*PIE)",GLUT_BITMAP_HELVETICA_12);
//     //bitmap_output(0,0,0,"Y=sin(3*X*PIE)",GLUT_BITMAP_9_BY_15);
//     //bitmap_output(0,0,0, "TEXT TO DISPLAY", GLUT_BITMAP_9_BY_15);
    
    
     glRotatef(data3DConf.rotationX, 1.0, 0.0, 0.0);
     glRotatef(data3DConf.rotationY, 0.0, 1.0, 0.0);
     glRotatef(data3DConf.rotationZ, 0.0, 0.0, 1.0);

   glPushMatrix();
   glScalef(univGraphSetPtr->zoomFactor,univGraphSetPtr->zoomFactor,univGraphSetPtr->zoomFactor);

   

   //gluLookAt(sizeL*1.2,0,0+legendOffset,0,0,0+legendOffset,0,0,1);
   gluLookAt(sizeL*enlargementFactor,0,0,0,0,0,0,0,1);

    qglColor(red);
    ///axes
    //x
    glBegin(GL_LINE);
      glVertex3f(0,0,legendOffset);
      glVertex3f(sizeL,0,legendOffset);
    glEnd();
    qglColor(green);
    //y
    glBegin(GL_LINE);
      glVertex3f(0,0,legendOffset);
      glVertex3f(0,sizeM,legendOffset);
    glEnd();

    qglColor(blue);
    //z
    glBegin(GL_LINE);
      glVertex3f(0,0,legendOffset);
      glVertex3f(0,0,sizeN+legendOffset);
    glEnd();

    ///markers of eol
    glBegin(GL_LINE);
      glVertex3f(0,0,sizeN+legendOffset);
      glVertex3f(0,10,sizeN+legendOffset);
      glVertex3f(0,sizeM,0+legendOffset);
      glVertex3f(0,sizeM,10+legendOffset);
      glVertex3f(sizeL,0,0+legendOffset);
      glVertex3f(sizeL,10,0+legendOffset);
    glEnd();

   

}


void Display3D::paint3DLattice(){

   //cerr<<"P3DL begin"<<endl;
   field3DGraphicsData_t & field3DGraphicsData = * field3DGraphicsDataPtr;
   prepareScene();
   //cerr<<"after prepare scene"<<endl;   
//    return;

// cerr<<" RotationX="<<rotationX<<" RotationY="<<rotationY<<" RotationZ="<<rotationZ<<endl;
      
      UniversalGraphicsSettings::colorMapItr pos;
      QColor *colorPtr;
      
/*    cerr<<"univGraphSetPtr="<<univGraphSetPtr<<endl;

   
    cerr<<" sizeL="<<sizeL;
    cerr<<" sizeM="<<sizeM;
    cerr<<" sizeN="<<sizeN;
    cerr<<" sizeX="<<sizeX;
    cerr<<" sizeY="<<sizeY;
    cerr<<" sizeZ="<<sizeZ;
    cerr<<endl;*/

      for(unsigned int x = 0 ; x < sizeL  ; ++x)
         for(unsigned int y = 0 ; y < sizeM ; ++y)
            for(unsigned int z = 0 ; z < sizeN ; ++z){

             pos=univGraphSetPtr->typeColorMap.find(field3DGraphicsData[x][y][z].type);

             if(checkIfInside(x,y,z)) continue;
             if( univGraphSetPtr->avoidType(field3DGraphicsData[x][y][z].type) ) continue;
             
             if(pos!=univGraphSetPtr->typeColorMap.end()){
                colorPtr=&(pos->second);
             }else{
                colorPtr=&univGraphSetPtr->defaultColor;
             }

            drawCube(x,  y , z , 1, *colorPtr );
            if(univGraphSetPtr->bordersOn)
               doBorders(x, y, z );

      }
   glPopMatrix();

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::doBorders(unsigned int x,unsigned int y,unsigned int z ){

   using namespace CompuCell3D;

   
   //offsets to neighboring wals of a given pixel
   static CompuCell3D::Point3D wallOffsets[6]={Point3D(-1,0,0),Point3D(1,0,0),Point3D(0,-1,0),Point3D(0,1,0),Point3D(0,0,-1),Point3D(0,0,1)};
   //pair of wals will make a visible edge if each of the walls of the pair touches different cell
   // I list all twelve combinations of indices of wallOffsets that could give rise to a visible edge
   static short edgePair[12][2]=
   {
      {0,4},
      {1,4},
      {2,4},
      {3,4},
      {0,5},
      {1,5},
      {2,5},
      {3,5},
      {0,2},
      {0,3},
      {1,2},
      {1,3}
   };

   //this is the list of pairs vertices- i.e. 6 numbers tot. in the order that corresponds to edgePair
   static GLfloat vertices[12][6]={
      {0,0,0,0,1,0},
      {1,0,0,1,1,0},
      {0,0,0,1,0,0},
      {0,1,0,1,1,0},
      {0,0,1,0,1,1},
      {1,0,1,1,1,1},
      {0,0,1,1,0,1},
      {0,1,1,1,1,1},
      {0,0,0,0,0,1},
      {0,1,0,0,1,1},
      {1,0,0,1,0,1},
      {1,1,0,1,1,1}
      

   };

   static GLubyte lineIndices[2]={0,1};
   
   static Point3D pt1,pt2,pt;
   static vector<short> vertexPairIndexVec(12,0);
   static short edgeCounter=0;
   
   edgeCounter=0;
   vertexPairIndexVec.assign(12,-1);//init the vector everytime you enter the function
   

   field3DGraphicsData_t & field3DGraphicsData = * field3DGraphicsDataPtr;
   
   pt.x=x;
   pt.y=y;
   pt.z=z;

   for(short i = 0 ; i < 12 ; ++i){
         
         pt1=pt+wallOffsets[ edgePair[i][0] ];
         pt2=pt+wallOffsets[ edgePair[i][1] ];
         if( belongsToField(pt1) && belongsToField(pt2) ){
             
                        
            //test if these walls make an edge
            if (
                  field3DGraphicsData[pt.x][pt.y][pt.z].id != field3DGraphicsData[pt1.x][pt1.y][pt1.z].id &&
                  field3DGraphicsData[pt.x][pt.y][pt.z].id != field3DGraphicsData[pt2.x][pt2.y][pt2.z].id 
               )
            {
               vertexPairIndexVec[edgeCounter]=i;
               ++edgeCounter;
               
            }
         }else{
            vertexPairIndexVec[edgeCounter]=i;
            ++edgeCounter;                     
         }
         
         
   }
   
   if(edgeCounter<=0){

      return;
   }

   
   //draw actual borders
   qglColor(univGraphSetPtr->borderColor);
   glEnableClientState(GL_VERTEX_ARRAY);
   for (short i = 0; i < edgeCounter; ++i ){
      
      glVertexPointer(3,GL_FLOAT,0,&(vertices[vertexPairIndexVec[i]][0]));
      glPushMatrix();
      
      

      glTranslatef(x,y,z);

      
      glDrawElements(GL_LINES,2,GL_UNSIGNED_BYTE,lineIndices);

      glPopMatrix();
      
      
   }
   glDisableClientState(GL_VERTEX_ARRAY);   
   
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::paint3DConcentrationLattice(){

   
   static QColor c;
   static float percentage;
   
   floatField3D_t & concentrationField=*currentConcentrationFieldPtr;
   field3DGraphicsData_t & field3DGraphicsData = * field3DGraphicsDataPtr;

   
   
   

   maxConcentrationTrue=numeric_limits<float>::min();

   for(unsigned int x = 0 ; x < sizeL  ; ++x)
      for(unsigned int y = 0 ; y < sizeM ; ++y)
         for(unsigned int z = 0 ; z < sizeN ; ++z){


            if(concentrationField[x][y][z]>maxConcentrationTrue){
               maxConcentrationTrue=concentrationField[x][y][z];
            }

            if(concentrationField[x][y][z]<minConcentrationTrue){
               minConcentrationTrue=concentrationField[x][y][z];
            }

         }

//    cerr<<"minConcentration="<<minConcentrationTrue<<" maxConcentration="<<maxConcentrationTrue<<endl;

   ///setting up % threshold for concentration

   if(!maxConcentrationFixed){
      maxConcentration = maxConcentrationTrue;
   }
   if(!minConcentrationFixed){
      minConcentration = minConcentrationTrue;
   }

   prepareSceneColorMap();
//return;   
        glTranslatef(0,0,legendOffset); 
      
      for(unsigned int x = 0 ; x < sizeL  ; ++x)
         for(unsigned int y = 0 ; y < sizeM ; ++y)
            for(unsigned int z = 0 ; z < sizeN ; ++z){

             if( univGraphSetPtr->avoidType(field3DGraphicsData[x][y][z].type) ) continue;            

             if(checkIfInside(x,y,z)) continue;
            
            if(concentrationField[x][y][z]<=0){
               c.setHsv( 255, 255,0);
            }else{
               percentage=percentageQuantity(concentrationField[x][y][z],minConcentration,maxConcentration);
               if(percentage<0.0)
                  percentage=0.0;
                if(percentage>1.0)
                  percentage=1.0;

                  c.setHsv( (int)((1.0-percentage)*255), 255,255 );
               if(percentage==0.0)
                  c.setHsv( -1, 0,0 );
           }
            
            drawCube(x,  y , z , 1, c );
            if(univGraphSetPtr->bordersOn)
               doBorders(x, y, z );

      }
   glPopMatrix();
   glLoadIdentity();
   
   if(legendEnable){
      paintLegend(minConcentration,maxConcentration,"d","colormap");
   }

      
    



}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Display3D::paint3DCellVectorFieldLattice(){
   cerr<<"this is paint3DCellvectorFieldLattice"<<endl;


}
