Index: /trunk/FACT++/gui/Q3DCameraWidget.cc
===================================================================
--- /trunk/FACT++/gui/Q3DCameraWidget.cc	(revision 12016)
+++ /trunk/FACT++/gui/Q3DCameraWidget.cc	(revision 12016)
@@ -0,0 +1,868 @@
+/*
+ * Q3DCameraWidget.cc
+ *
+ *  Created on: Aug 26, 2011
+ *      Author: lyard
+ */
+#include "Q3DCameraWidget.h"
+#include <math.h>
+#include <sstream>
+
+    Q3DCameraWidget::Q3DCameraWidget(QWidget* pparent) : BasicGlCamera(pparent),
+                                                         timer(),
+                                                         currentLoc(),
+                                                         steps(0),
+                                                         totalSteps(50),
+                                                         currentView(4),
+                                                         nextView(currentView),
+                                                         cameraViews(0),
+                                                         isPicking(false),
+                                                         initFinished(false)
+    {
+        setFormat(QGLFormat(QGL::DoubleBuffer | QGL::DepthBuffer));
+        rotX = rotY = 0;
+        timer.setInterval(40.0);//0.04 second interval
+        QObject::connect(&timer, SIGNAL(timeout()),
+                         this, SLOT(timedUpdate()));
+        QObject::connect(this, SIGNAL(dataHasChanged()),
+                         this, SLOT(timedUpdate()));
+        spheresColors.resize(28);
+        spheresRadius.resize(28);
+        spheresLocation.resize(28);
+        PixelMap mypMap;
+        if (!mypMap.Read("FACTmapV5.txt"))
+        {
+            cerr << "ERROR - Problems reading FACTmapV5.txt" << endl;
+            exit(-1);
+        }
+        ifstream fin1("Trigger-Patches.txt");
+        if (!fin1.is_open())
+        {
+            cout << "Error: file \"Trigger-Patches\" missing. aborting." << endl;
+            exit(-1);
+        }
+        string buf;
+        vector<int> patchHW(1440);
+        int l = 0;
+        while (getline(fin1, buf, '\n'))
+        {
+            buf = Tools::Trim(buf);
+            if (buf[0]=='#')
+                continue;
+
+            stringstream str(buf);
+            for (int i=0; i<9; i++)
+            {
+                unsigned int n;
+                str >> n;
+
+                if (n>=patchHW.size())
+                    continue;
+
+                patchHW[n] = l;
+            }
+            l++;
+        }
+        if (l!=160)
+            cerr << "WARNING - Problems reading Trigger-Patches.txt" << endl;
+
+        assignPixelMap(mypMap);
+        assignTriggerPatchesMap(patchHW);
+        setTitle("Temperatures");
+
+
+        for (auto it=spheresColors.begin(), jt = spheresRadius.begin(); it != spheresColors.end(); it++, jt++)
+        {
+            (*it)[0] = 0.5f;
+            (*it)[1] = 0.5f;
+            (*it)[2] = 0.5f;
+            (*jt) = 0.1f;
+        }
+        float xx = 0.5;
+        float yx = 0.5;
+        float z = 0.2;
+        float zplus = 0.25;
+        //crate
+        for (int i=0;i<28;i+=4)
+        {
+            xx = 0.5*cos((float)(i)*M_PI/4);
+            yx = 0.5*sin((float)(i)*M_PI/4);
+            spheresLocation[i][0] = xx;
+            spheresLocation[i][1] = yx;
+            spheresLocation[i][2] = z;
+
+            xx = 0.5*cos((float)(i+1)*M_PI/4);
+            yx = 0.5*sin((float)(i+1)*M_PI/4);
+            spheresLocation[i+1][0] = xx;
+            spheresLocation[i+1][1] = yx;
+            spheresLocation[i+1][2] = z + zplus/4;
+
+            xx = 0.5*cos((float)(i+2)*M_PI/4);
+            yx = 0.5*sin((float)(i+2)*M_PI/4);
+            spheresLocation[i+2][0] = xx;
+            spheresLocation[i+2][1] = yx;
+            spheresLocation[i+2][2] = z + 2*zplus/4;
+
+            xx = 0.5*cos((float)(i+3)*M_PI/4);
+            yx = 0.5*sin((float)(i+3)*M_PI/4);
+            spheresLocation[i+3][0] = xx;
+            spheresLocation[i+3][1] = yx;
+            spheresLocation[i+3][2] = z + 3*zplus/4;
+            z += zplus;
+        }
+
+
+        cameraViews.push_back(cameraLocation(45,45, 0.6,-0.3,0));//0
+        cameraViews.push_back(cameraLocation(75,0, 0,-0.65,0));//1
+        cameraViews.push_back(cameraLocation(45,-45, -0.6,-0.3,0));//2
+        cameraViews.push_back(cameraLocation(0,75, 0.8,0,0));//3
+        cameraViews.push_back(cameraLocation(0,0, 0,0,1));//4
+        cameraViews.push_back(cameraLocation(0,-75, -0.8,0,0));//5
+        cameraViews.push_back(cameraLocation(-45,45, 0.6,0.5,0));//6
+        cameraViews.push_back(cameraLocation(-75,0, 0,1,0.2));//7
+        cameraViews.push_back(cameraLocation(-45,-45, -0.6,0.5,0));//8
+
+        tempPatches.resize(31);
+        tempPatches[0].push_back(16);
+        tempPatches[0].push_back(24);
+        tempPatches[0].push_back(32);
+        tempPatches[0].push_back(36);
+
+        tempPatches[1].push_back(49);
+        tempPatches[1].push_back(48);
+        tempPatches[1].push_back(52);
+
+        tempPatches[2].push_back(4);
+        tempPatches[2].push_back(5);
+        tempPatches[2].push_back(8);
+        tempPatches[2].push_back(9);
+
+        tempPatches[3].push_back(17);
+        tempPatches[3].push_back(19);
+        tempPatches[3].push_back(18);
+        tempPatches[3].push_back(26);
+        tempPatches[3].push_back(25);
+
+        tempPatches[4].push_back(37);
+        tempPatches[4].push_back(38);
+        tempPatches[4].push_back(50);
+        tempPatches[4].push_back(51);
+        tempPatches[4].push_back(33);
+        tempPatches[4].push_back(34);
+
+        tempPatches[5].push_back(65);
+        tempPatches[5].push_back(62);
+        tempPatches[5].push_back(61);
+        tempPatches[5].push_back(54);
+        tempPatches[5].push_back(53);
+
+        tempPatches[6].push_back(69);
+        tempPatches[6].push_back(68);
+        tempPatches[6].push_back(64);
+        tempPatches[6].push_back(60);
+
+        tempPatches[7].push_back(2);
+        tempPatches[7].push_back(6);
+        tempPatches[7].push_back(7);
+        tempPatches[7].push_back(12);
+        tempPatches[7].push_back(13);
+        tempPatches[7].push_back(0);
+
+        tempPatches[8].push_back(10);
+        tempPatches[8].push_back(11);
+        tempPatches[8].push_back(20);
+        tempPatches[8].push_back(21);
+
+        tempPatches[9].push_back(30);
+        tempPatches[9].push_back(35);
+        tempPatches[9].push_back(39);
+        tempPatches[9].push_back(27);
+        tempPatches[9].push_back(28);
+
+        tempPatches[10].push_back(40);
+        tempPatches[10].push_back(44);
+        tempPatches[10].push_back(45);
+        tempPatches[10].push_back(55);
+        tempPatches[10].push_back(57);
+
+        tempPatches[11].push_back(56);
+        tempPatches[11].push_back(63);
+        tempPatches[11].push_back(66);
+        tempPatches[11].push_back(67);
+        tempPatches[11].push_back(71);
+
+        tempPatches[12].push_back(72);
+        tempPatches[12].push_back(78);
+        tempPatches[12].push_back(76);
+        tempPatches[12].push_back(70);
+        tempPatches[12].push_back(77);
+
+        tempPatches[13].push_back(159);
+        tempPatches[13].push_back(1);
+        tempPatches[13].push_back(155);
+        tempPatches[13].push_back(3);
+        tempPatches[13].push_back(153);
+        tempPatches[13].push_back(14);
+
+        tempPatches[14].push_back(23);
+        tempPatches[14].push_back(15);
+        tempPatches[14].push_back(139);
+        tempPatches[14].push_back(22);
+        tempPatches[14].push_back(127);
+        tempPatches[14].push_back(29);
+
+        tempPatches[15].push_back(111);
+        tempPatches[15].push_back(42);
+        tempPatches[15].push_back(123);
+        tempPatches[15].push_back(31);
+        tempPatches[15].push_back(43);
+        tempPatches[15].push_back(41);
+
+        tempPatches[16].push_back(103);
+        tempPatches[16].push_back(58);
+        tempPatches[16].push_back(102);
+        tempPatches[16].push_back(59);
+        tempPatches[16].push_back(47);
+        tempPatches[16].push_back(46);
+
+        tempPatches[17].push_back(95);
+        tempPatches[17].push_back(73);
+        tempPatches[17].push_back(75);
+        tempPatches[17].push_back(74);
+        tempPatches[17].push_back(81);
+        tempPatches[17].push_back(79);
+
+        tempPatches[18].push_back(93);
+        tempPatches[18].push_back(91);
+        tempPatches[18].push_back(94);
+        tempPatches[18].push_back(100);
+        tempPatches[18].push_back(101);
+
+        tempPatches[19].push_back(108);
+        tempPatches[19].push_back(109);
+        tempPatches[19].push_back(110);
+        tempPatches[19].push_back(115);
+        tempPatches[19].push_back(121);
+
+        tempPatches[20].push_back(124);
+        tempPatches[20].push_back(137);
+        tempPatches[20].push_back(126);
+        tempPatches[20].push_back(125);
+        tempPatches[20].push_back(122);
+
+        tempPatches[21].push_back(152);
+        tempPatches[21].push_back(147);
+        tempPatches[21].push_back(138);
+        tempPatches[21].push_back(143);
+        tempPatches[21].push_back(136);
+
+        tempPatches[22].push_back(156);
+        tempPatches[22].push_back(158);
+        tempPatches[22].push_back(154);
+        tempPatches[22].push_back(157);
+        tempPatches[22].push_back(151);
+
+        tempPatches[23].push_back(87);
+        tempPatches[23].push_back(80);
+        tempPatches[23].push_back(92);
+        tempPatches[23].push_back(82);
+        tempPatches[23].push_back(83);
+
+        tempPatches[24].push_back(144);
+        tempPatches[24].push_back(148);
+        tempPatches[24].push_back(150);
+        tempPatches[24].push_back(149);
+
+        tempPatches[25].push_back(145);
+        tempPatches[25].push_back(146);
+        tempPatches[25].push_back(141);
+        tempPatches[25].push_back(142);
+        tempPatches[25].push_back(134);
+        tempPatches[25].push_back(135);
+
+        tempPatches[26].push_back(113);
+        tempPatches[26].push_back(114);
+        tempPatches[26].push_back(119);
+        tempPatches[26].push_back(120);
+        tempPatches[26].push_back(130);
+        tempPatches[26].push_back(131);
+
+        tempPatches[27].push_back(88);
+        tempPatches[27].push_back(90);
+        tempPatches[27].push_back(98);
+        tempPatches[27].push_back(99);
+        tempPatches[27].push_back(106);
+        tempPatches[27].push_back(107);
+
+        tempPatches[28].push_back(89);
+        tempPatches[28].push_back(85);
+        tempPatches[28].push_back(86);
+        tempPatches[28].push_back(84);
+
+        tempPatches[29].push_back(140);
+        tempPatches[29].push_back(132);
+        tempPatches[29].push_back(133);
+        tempPatches[29].push_back(128);
+        tempPatches[29].push_back(129);
+        tempPatches[29].push_back(116);
+        tempPatches[29].push_back(118);
+
+        tempPatches[30].push_back(97);
+        tempPatches[30].push_back(96);
+        tempPatches[30].push_back(104);
+        tempPatches[30].push_back(105);
+        tempPatches[30].push_back(112);
+        tempPatches[30].push_back(117);
+
+
+
+        for (int i=0;i<NTMARK;i++)
+        {
+            float color[3];
+            if (i<NTMARK/3)
+            {
+                color[0] = (float)(i)/((float)(NTMARK)/3.f);
+                color[1] = 0;
+                color[2] = 0;
+            }
+            if (i >= NTMARK/3 && i<2*NTMARK/3)
+            {
+                color[0] = 1;
+                color[1] = (float)(i-NTMARK/3)/((float)(NTMARK)/3.f);
+                color[2] = 0;
+            }
+            if (i>=2*NTMARK/3)
+            {
+                color[0] = 0;
+                color[1] = 1;
+                color[2] = (float)(i-2*NTMARK/3)/((float)(NTMARK)/3.f);
+            }
+            color[0] /= 2;
+            color[1] /= 2;
+            color[2] /= 2;
+            setPatchColor(i, color);
+        }
+
+        currentView = 4;
+        nextView = currentView;
+        currentLoc = cameraViews[currentView];
+        steps = 0;
+        totalSteps = 50;
+
+        fMin = 0.f;
+        fMax = 50.f;
+    }
+    Q3DCameraWidget::~Q3DCameraWidget()
+    {
+
+    }
+    void Q3DCameraWidget::timedUpdate()
+    {
+        updateGL();
+    }
+    void Q3DCameraWidget::updateData(float* dataa)
+    {
+        memcpy(&fscTemps[0], dataa, 60*sizeof(float));
+
+        if (tempPatches.size() != 31 || !initFinished)
+            return;
+
+        for (int i=0;i<59;i++)
+        {
+//            cout << i << " " << fscTemps[i] << endl;
+            float ratio = (fscTemps[i+1] - fMin)/(fMax - fMin);
+ //           cout  << fscTemps[i+1] << " " << i << endl;
+            float color[3];
+            if (ratio > ss[4])
+            {
+                color[0] = tooHighValueCoulour[0];
+                color[1] = tooHighValueCoulour[1];
+                color[2] = tooHighValueCoulour[2];
+            }
+            else
+            {
+                if (ratio < ss[0])
+                {
+                    color[0] = tooLowValueCoulour[0];
+                    color[1] = tooLowValueCoulour[1];
+                    color[2] = tooLowValueCoulour[2];
+                }
+                else
+                {
+ //                   cout << "Calculating the actual value" << endl;
+                    int index = 0;
+                    while (index < 5 && ss[index] < ratio)
+                        index ++;
+                    index--;
+                    float ratio2 = (ratio - ss[index])/(ss[index+1] - ss[index]);
+                    float ratio3 = 1.f - ratio2;
+                    color[0] = rr[index]*ratio3 + rr[index+1]*ratio2;
+                    color[1] = gg[index]*ratio3 + gg[index+1]*ratio2;
+                    color[2] = bb[index]*ratio3 + bb[index+1]*ratio2;
+                }
+            }
+            if (i < 31)
+            for (unsigned int j=0;j<tempPatches[i].size(); j++)
+                setPatchColor(tempPatches[i][j], color);
+            else
+            {
+                int ii = i-31;
+                for (;ii<28;ii++)
+                {
+                    spheresRadius[ii] = 0.05*ratio + 0.01;
+                    spheresColors[ii][0] = color[0];
+                    spheresColors[ii][1] = color[1];
+                    spheresColors[ii][2] = color[2];
+                }
+
+            }
+        }
+
+
+        if (!initFinished)
+            return;
+        UpdateText();
+        emit dataHasChanged();
+  //      timer.start();
+ //       updateGL();
+
+    }
+    void Q3DCameraWidget::mousePressEvent(QMouseEvent* cEvent)
+    {
+        if (cEvent->pos().x() > width()-(width()/50.f))
+        {
+            toggleInterfaceDisplay();
+            return;
+        }
+        int face = PixelAtPosition(cEvent->pos());
+         if (face != -1) {
+             fWhite = face;
+             if (face < 1440)
+                 fWhitePatch = pixelsPatch[fWhite];
+             else
+                 fWhitePatch = -1;
+//             cout << "Patch Value: " << fWhitePatch << " fWhite: " << fWhite << endl;
+
+             emit signalCurrentPixel(face);
+             }
+         else
+         {
+             fWhite = -1;
+             fWhitePatch = -1;
+         }
+         UpdateText();
+         updateGL();
+    }
+    void Q3DCameraWidget::mouseDoubleClickEvent(QMouseEvent *cEvent)
+    {
+        int face = PixelAtPosition(cEvent->pos());
+         if (face != -1 && face < 1440) {
+             highlightPatches.push_back(pixelsPatch[face]);
+             updateGL();
+             return;
+//             fWhitePatch = pixelsPatch[fWhite];
+         }
+        int dir = 0;
+        int xx = cEvent->pos().x();
+        int yx = cEvent->pos().y();
+        if (xx > width()/3) dir++;
+        if (xx > 2*width()/3) dir++;
+        if (yx > height()/3) dir+=3;
+        if (yx > 2*height()/3) dir+=3;
+
+        if (steps)
+            return;
+
+        nextView = dir;
+
+        if (nextView == currentView)
+            return;
+        steps = totalSteps;
+        timer.start();
+    }
+    int Q3DCameraWidget::PixelAtPosition(const QPoint &cPos)
+    {
+        const int MaxSize = 512;
+        GLuint buffer[MaxSize];
+        GLint viewport[4];
+
+        makeCurrent();
+
+        glGetIntegerv(GL_VIEWPORT, viewport);
+        glSelectBuffer(MaxSize, buffer);
+        glRenderMode(GL_SELECT);
+
+        glInitNames();
+        glPushName(0);
+
+        glMatrixMode(GL_PROJECTION);
+        glPushMatrix();
+        glLoadIdentity();
+//cout << "Viewport: " << viewport[0] << " " << viewport[1] << " " << viewport[2] << " " << viewport[3] << endl;
+        gluPickMatrix(cPos.x(), viewport[3] - cPos.y(), 1, 1, viewport);
+
+        GLfloat windowRatio = (float)viewport[2]/(float)viewport[3];
+        gluPerspective(40.f, windowRatio, 1, 10);
+
+        glMatrixMode(GL_MODELVIEW);
+        isPicking = true;
+        paintGL();
+        isPicking = false;
+        glMatrixMode(GL_PROJECTION);
+        glPopMatrix();
+
+        //for some reason that I cannot understand, the push/pop matrix doesn't do the trick here... bizarre
+        //ok, so re-do the resizeGL thing.
+        resizeGL(width(), height());
+
+        int hits = glRenderMode(GL_RENDER);
+        if (!hits)
+            return -1;
+//        else
+ //           cout << "There are " << hits << " hits..." << endl;
+//        for (int i=0;i<MaxSize;i++)
+//            cout << buffer[i] << " ";
+ //       cout << endl;
+
+        if (buffer[3] < 1440+28)
+            return buffer[3];
+        else
+            return -1;
+    }
+    void Q3DCameraWidget::paintGL()
+    {
+        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+        glLoadIdentity();
+
+        glTranslatef(0,-0.315, -3);
+//        glScalef(1.5, 1.5, 1.5);
+
+        float speed = 0.5f + 0.5f*cos(M_PI*((float)steps/(float)(totalSteps)));
+
+
+        if (currentView != nextView)
+        {
+            float targetRotX = cameraViews[nextView].rotX;
+            float targetRotY = cameraViews[nextView].rotY;
+            if (fabs(targetRotX - 315) < 0.01f && cameraViews[currentView].rotX == 0)
+                targetRotX -= 360;
+            if (fabs(targetRotX) < 0.01f && cameraViews[currentView].rotX == 315)
+                targetRotX += 360;
+
+            if (fabs(targetRotY - 315) < 0.01f && cameraViews[currentView].rotY == 0)
+                targetRotY -= 360;
+            if (fabs(targetRotY) < 0.01f && cameraViews[currentView].rotY == 315)
+                targetRotY += 360;
+            currentLoc.rotX = cameraViews[currentView].rotX + speed*(targetRotX - cameraViews[currentView].rotX);
+            currentLoc.rotY = cameraViews[currentView].rotY + speed*(targetRotY - cameraViews[currentView].rotY);
+            for (int i=0;i<3;i++)
+                currentLoc.position[i] = cameraViews[currentView].position[i] + speed*(cameraViews[nextView].position[i] - cameraViews[currentView].position[i]);
+            steps--;
+            if (!steps)//fabs(currentLoc.rotX - cameraViews[nextView].rotX) <0.01)
+            {
+                currentLoc = cameraViews[nextView];
+ //               currentLoc.rotX = cameraViews[nextView].rotX;
+ //               currentLoc.rotY = cameraViews[nextView].rotY;
+ //               for (int i=0;i<3;i++)
+ //               currentLoc.position[i] = cameraViews[nextView].position[i];
+                currentView = nextView;
+                timer.stop();
+            }
+        }
+        else
+        {
+            timer.stop();
+        }
+        glTranslatef(currentLoc.position[0], currentLoc.position[1], currentLoc.position[2]);
+        glRotatef(currentLoc.rotX, 1,0,0);
+        glRotatef(currentLoc.rotY, 0,1,0);
+
+       glTranslatef(0,0.315,0);
+       glRotatef(cameraRotation, 0,0,1);
+       glTranslatef(0,-0.315,0);
+ //       rotY +=0.1;
+ //       glRotatef(rotY, 0,1,0);
+ //       glRotatef(rotX, 1,0,0);
+//        glRotatef(90, 1,0,0);
+        drawCamera(true);
+        glTranslatef(0,0,0.01);
+        drawPatches();
+        if (fWhite != -1 && fWhite < 1440)
+        {
+            glTranslatef(0,0,0.01);
+            glColor3f(1.f, 0.f, 0.f);
+            drawHexagon(fWhite, false);
+            glTranslatef(0,0,-0.01);
+       }
+        glTranslatef(0,0,0.01);
+        glColor3f(1.0f, 0.5f, 0.0f);
+        glBegin(GL_LINES);
+        for (auto it=highlightPatches.begin(); it!=highlightPatches.end(); it++)
+        {
+            for (unsigned int j=0;j<patchesIndices[*it].size();j++)
+            {
+                glVertex2fv(verticesList[patchesIndices[*it][j].first]);
+                glVertex2fv(verticesList[patchesIndices[*it][j].second]);
+            }
+        }
+        glEnd();
+
+        glEnable(GL_LIGHTING);
+        glEnable(GL_LIGHT0);
+        glTranslatef(0,0.315, 0);
+        glRotatef(180,1,0,0);
+        drawSpheres();
+        drawCameraBody();
+        if (fWhite < 1500 && fWhite >= 1440)
+        {
+ //           cout << "Drawing wireframe sphere " << fWhite << endl;
+            glPushMatrix();
+            GLfloat red[4] = {0, 0, 0, 1};
+            red[0] = 1.f - spheresColors[fWhite-1440][0];
+            red[1] = 1.f - spheresColors[fWhite-1440][1];
+            red[2] = 1.f - spheresColors[fWhite-1440][2];
+            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red);
+            glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+ //           glColor3fv(spheresColors[i].data);
+            glTranslatef(spheresLocation[fWhite-1440][0], spheresLocation[fWhite-1440][1], spheresLocation[fWhite-1440][2]);
+            gluSphere(gluNewQuadric(), 0.11f, 15, 15);
+            glPopMatrix();
+            glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+        }
+
+
+        glDisable(GL_LIGHTING);
+
+        if (isPicking)
+            return;
+
+        BasicGlCamera::resizeGL(width(), height());
+        glDisable(GL_DEPTH_TEST);
+        DrawCameraText();
+        DrawScale();
+        glEnable(GL_DEPTH_TEST);
+        resizeGL(width(), height());
+
+        initFinished = true;
+
+    }
+    void Q3DCameraWidget::UpdateText()
+    {
+        if (fWhitePatch != -1)
+        {
+            ostringstream str;
+            str << "Patch " << fWhitePatch << " Temperature: ";
+            int patchIndice = -1;
+            unsigned int i=0;
+            for (auto it = tempPatches.begin(); it != tempPatches.end(); it++)
+            {
+                for (auto jt = it->begin(); jt != it->end(); jt++)
+                    if (*jt == fWhitePatch)
+                    {
+                        patchIndice = i;
+                        break;
+                    }
+                if (patchIndice != -1)
+                    break;
+                i++;
+            }
+            if (i==tempPatches.size())
+            {
+                dataText = "Error, patch couldn't be found in patch list";
+            }
+            else
+            {
+                str << fscTemps[i+1] << " degrees";
+                dataText = str.str();
+            }
+            return;
+        }
+        if (fWhite >= 1440 && fWhite < 1500)
+        {
+            ostringstream str;
+            int whi = fWhite - 1440;
+            switch (whi)
+            {
+            case 0:
+            case 1:
+            case 2:
+            case 3:
+            case 4:
+            case 5:
+            case 6:
+            case 7:
+               str << "Crate sensor #" << whi;
+                break;
+            case 8:
+            case 9:
+            case 10:
+            case 11:
+            case 12:
+            case 13:
+            case 14:
+            case 15:
+                str << "Power supply (crate) #" << whi-8;
+                break;
+            case 16:
+            case 17:
+            case 18:
+            case 19:
+                str << "Power supply (Aux) #" << whi - 16;
+                break;
+            case 20:
+            case 21:
+            case 22:
+            case 23:
+                str << "Back panel #" << whi - 20;
+                break;
+            case 24:
+            case 25:
+            case 26:
+            case 27:
+                str << "Switch box #" << whi - 24;
+                break;
+            default:
+                str << "Something went wrong " << whi;
+            }
+            str << ": " << fscTemps[whi+32] << " degrees";
+            dataText = str.str();
+            return;
+        }
+
+        dataText = "";
+    }
+    void Q3DCameraWidget::drawSpheres()
+    {
+//        GLUquadric* quad = gluNewQuadric();
+        for (int i=0;i<28;i++)
+        {
+            glPushMatrix();
+            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, spheresColors[i].data);
+            glLoadName(i + 1440);
+ //           glColor3fv(spheresColors[i].data);
+            glTranslatef(spheresLocation[i][0], spheresLocation[i][1], spheresLocation[i][2]);
+            gluSphere(gluNewQuadric(), 0.1f, 10, 10);//spheresRadius[i], 10, 10);
+            glPopMatrix();
+        }
+        glLoadName(1500);
+        glPushAttrib(GL_LIGHTING_BIT);
+        glDisable(GL_LIGHTING);
+        glColor3f(0.6,0.6,0.6);
+        glBegin(GL_LINE_LOOP);
+        for (int i=0;i<4;i++)
+            glVertex3fv(spheresLocation[i].data);
+        glEnd();
+        glBegin(GL_LINE_LOOP);
+        for (int i=4;i<8;i++)
+            glVertex3fv(spheresLocation[i].data);
+        glEnd();
+        glBegin(GL_LINE_LOOP);
+        for (int i=8;i<12;i++)
+            glVertex3fv(spheresLocation[i].data);
+        glEnd();
+        glBegin(GL_LINE_LOOP);
+        for (int i=12;i<16;i++)
+            glVertex3fv(spheresLocation[i].data);
+        glEnd();
+        glBegin(GL_LINE_LOOP);
+        for (int i=16;i<18;i++)
+            glVertex3fv(spheresLocation[i].data);
+        glEnd();
+        glBegin(GL_LINE_LOOP);
+        for (int i=18;i<20;i++)
+            glVertex3fv(spheresLocation[i].data);
+        glEnd();
+        glBegin(GL_LINE_LOOP);
+        for (int i=20;i<24;i++)
+            glVertex3fv(spheresLocation[i].data);
+        glEnd();
+        glBegin(GL_LINE_LOOP);
+        for (int i=24;i<26;i++)
+            glVertex3fv(spheresLocation[i].data);
+        glEnd();
+        glBegin(GL_LINE_LOOP);
+        for (int i=26;i<28;i++)
+            glVertex3fv(spheresLocation[i].data);
+        glEnd();
+
+        glPopAttrib();
+    }
+
+    void Q3DCameraWidget::drawCameraBody()
+    {
+        glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+
+        GLfloat color[4] = {0.4f, 0.5f, 0.5f, 1.f};
+        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
+        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 1.0f);
+        gluCylinder( gluNewQuadric(),
+                        0.62,
+                        0.62,
+                        1.83,
+                        30,
+                        2 );
+        glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+
+
+
+    }
+    void Q3DCameraWidget::drawCamera(bool alsoWire)
+    {
+        glColor3f(0.5,0.5,0.5);
+        glLineWidth(1.0);
+        for (int i=0;i<ACTUAL_NUM_PIXELS;i++)
+        {
+            glColor3fv(pixelsColor[i]);
+            glLoadName(i);
+            drawHexagon(i,true);
+        }
+        if (!alsoWire)
+            return;
+        glTranslatef(0,0,0.01);
+        glColor3f(0.0f,0.0f,0.0f);
+        for (int i=0;i<ACTUAL_NUM_PIXELS;i++)
+        {
+            drawHexagon(i, false);
+        }
+//        glLoadName(1440);
+    }
+    void Q3DCameraWidget::initializeGL()
+    {
+        qglClearColor(QColor(25,25,38));
+
+        glShadeModel(GL_SMOOTH);
+        glEnable(GL_DEPTH_TEST);
+        glDepthFunc(GL_LESS);
+        glDisable(GL_CULL_FACE);
+//        glCullFace(GL_FRONT);
+
+        glEnable(GL_LINE_SMOOTH);
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+        glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
+    }
+    void Q3DCameraWidget::resizeGL(int cWidth, int cHeight)
+    {
+        glViewport(0,0,cWidth, cHeight);
+        glMatrixMode(GL_PROJECTION);
+        glLoadIdentity();
+        GLfloat windowRatio = (float)cWidth/(float)cHeight;
+        if (windowRatio < 1)
+        {
+//            windowRatio = 1.0f/windowRatio;
+            gluPerspective(40.f, windowRatio, 1, 10);
+//            gluOrtho2D(-viewSize, viewSize, -viewSize*windowRatio, viewSize*windowRatio);
+            pixelSize = 2*viewSize/(float)cWidth;
+            shownSizex = 2*viewSize;
+            shownSizey = 2*viewSize*windowRatio;
+        }
+        else
+        {
+            gluPerspective(40.f, windowRatio, 1, 10);
+//            gluOrtho2D(-viewSize*windowRatio, viewSize*windowRatio, -viewSize, viewSize);
+            pixelSize = 2*viewSize/(float)cHeight;
+            shownSizex = 2*viewSize*windowRatio;
+            shownSizey = 2*viewSize;
+        }
+        glMatrixMode(GL_MODELVIEW);
+    }
Index: /trunk/FACT++/gui/Q3DCameraWidget.h
===================================================================
--- /trunk/FACT++/gui/Q3DCameraWidget.h	(revision 12016)
+++ /trunk/FACT++/gui/Q3DCameraWidget.h	(revision 12016)
@@ -0,0 +1,89 @@
+/*
+ * Q3DCameraWidget.h
+ *
+ *  Created on: Aug 26, 2011
+ *      Author: lyard
+ */
+
+#ifndef Q3DCAMERAWIDGET_H_
+#define Q3DCAMERAWIDGET_H_
+
+#include "BasicGlCamera.h"
+#include <QtCore/QTimer>
+#include <iostream>
+
+
+using namespace std;
+
+struct cameraLocation
+{
+    float rotX;
+    float rotY;
+    float position[3];
+
+    cameraLocation() : rotX(0), rotY(0), position({0,0,0})
+    {}
+    cameraLocation(float rx, float ry, float x, float y, float z): rotX(rx), rotY(ry), position({x,y,z})
+    {}
+};
+
+struct float3
+{
+    float data[4];
+    float3()
+    {
+        data[0] = data[1] = data[2] = 0;
+        data[3] = 1.f;
+    }
+    float& operator [] (int index)
+    {
+        return data[index];
+    }
+};
+class Q3DCameraWidget : public BasicGlCamera
+{
+    Q_OBJECT
+
+public:
+    Q3DCameraWidget(QWidget* pparent = 0);
+    ~Q3DCameraWidget();
+    void updateData(float* data);
+
+public Q_SLOTS:
+    void timedUpdate();
+
+    Q_SIGNALS:
+    void dataHasChanged();
+
+protected:
+    void paintGL();
+    void initializeGL();
+    void resizeGL(int cWidth, int cHeight);
+    void drawCamera(bool alsoWire);
+    void drawCameraBody();
+    float rotX, rotY;
+    void mousePressEvent(QMouseEvent* event);
+    void mouseDoubleClickEvent(QMouseEvent *cEvent);
+    int PixelAtPosition(const QPoint &pos);
+    void drawSpheres();
+    void UpdateText();
+
+private:
+    QTimer timer;
+    cameraLocation currentLoc;
+    int steps;
+    int totalSteps;
+    int currentView;
+    int nextView;
+    vector<cameraLocation> cameraViews;
+    float fscTemps[60];
+    bool isPicking;
+    vector<int> highlightPatches;
+    vector<vector<int> > tempPatches;
+    bool initFinished;
+    vector<float3> spheresColors;
+    vector<float> spheresRadius;
+    vector<float3> spheresLocation;
+};
+
+#endif /* Q3DCAMERAWIDGET_H_ */
Index: /trunk/FACT++/gui/TempViewer.cc
===================================================================
--- /trunk/FACT++/gui/TempViewer.cc	(revision 12016)
+++ /trunk/FACT++/gui/TempViewer.cc	(revision 12016)
@@ -0,0 +1,69 @@
+/*
+ * TempViewer.cc
+ *
+ *  Created on: Aug 26, 2011
+ *      Author: lyard
+ */
+#include "Q3DCameraWidget.h"
+#include <qapplication.h>
+#include <qlayout.h>
+
+#include "dic.hxx"
+
+class TemperatureSub : public DimClient
+{
+    DimStampedInfo info;
+    Q3DCameraWidget* view;
+    int numC;
+
+public:
+    TemperatureSub() : info("FSC_CONTROL/TEMPERATURE", (void*)NULL, 0, this), view(NULL)
+    {numC = 0;}
+    void setViewer(Q3DCameraWidget* v) { view = v;}
+    void infoHandler()
+    {
+        DimInfo* I = getInfo();
+        if (!(I==&info))
+        {
+            cout << "Hum, I'm getting info from subsciptions to which I didn\'t subscribe... weird" << endl;
+            return;
+        }
+        float* values = (float*)(I->getData());
+        if (I->getSize() != 60*sizeof(float))
+        {
+            cout << "wrong size: " << I->getSize() << endl;
+            return;
+        }
+        if (view)// && numC > 2)
+            view->updateData(values);
+        numC++;
+    }
+};
+void do3DView(int argc, char** argv)
+{
+    QApplication a(argc, argv);
+
+    Q3DCameraWidget* view = new Q3DCameraWidget();
+    TemperatureSub sub;
+
+    QWidget window;
+    QHBoxLayout* layout = new QHBoxLayout(&window);
+    layout->setContentsMargins(0,0,0,0);
+    layout->addWidget(view);
+//    layout->setMouseTracking(true);
+//    window.setMouseTracking(true);
+//    view->setMouseTracking(true);
+    window.resize(600,600);
+    window.show();
+
+    sub.setViewer(view);
+
+    a.exec();
+
+}
+
+int main(int argc, char** argv)
+{
+    do3DView(argc, argv);
+
+}
