PreviewIdentifyTool.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00022 #include "panoinc_WX.h"
00023 #include "panoinc.h"
00024 
00025 #include "PreviewIdentifyTool.h"
00026 #include <config.h>
00027 
00028 #include "base_wx/platform.h"
00029 #include "GLPreviewFrame.h"
00030 #include "MainFrame.h"
00031 
00032 #include <wx/platform.h>
00033 
00034 //multitexture feature requires glew on some systems
00035 #if !defined Hugin_shared || !defined _WINDOWS
00036 #define GLEW_STATIC
00037 #endif
00038 #include <GL/glew.h>
00039 
00040 #ifdef __WXMAC__
00041 #include <OpenGL/gl.h>
00042 #include <OpenGL/glu.h>
00043 #else
00044 #include <GL/gl.h>
00045 #include <GL/glu.h>
00046 #endif
00047 
00048 #include <algorithm>
00049 #include <vector>
00050 
00051 // the size of the rectangular texture. Must be a power of two, and at least 8.
00052 #define rect_ts 64
00053 // the number of times larger the circular texture is, must be a power of 2, and
00054 // at least 1. Making better improves the appearance of the circle.
00055 #define circle_ts_multiple 4
00056 #define circle_ts (rect_ts * circle_ts_multiple)
00057 #define circle_middle ((float) (circle_ts - 1) / 2.0)
00058 #define circle_border_outer (circle_middle - 0.5 * (float) circle_ts_multiple)
00059 #define circle_border_inner (circle_middle - 2.5 * (float) circle_ts_multiple)
00060 #define circle_border_peak (circle_middle - 1.5 * (float) circle_ts_multiple)
00061 
00062 bool PreviewIdentifyTool::texture_created = false;
00063 unsigned int PreviewIdentifyTool::circle_border_tex;
00064 unsigned int PreviewIdentifyTool::rectangle_border_tex;
00065 unsigned int PreviewIdentifyTool::font_tex;
00066 unsigned int PreviewIdentifyTool::font_list;
00067 std::vector<int> PreviewIdentifyTool::m_glyphWidth;
00068 
00069 #define FONT_TEXTURE_HEIGHT 75
00070 wxBitmap GenerateFontTexture(const int textureHeight, int& textureWidth, std::vector<int>& glyphWidth)
00071 {
00072     wxBitmap bitmap(10 * textureHeight, textureHeight);
00073     wxMemoryDC dc(bitmap);
00074     dc.SetBackground(*wxBLACK_BRUSH);
00075     dc.Clear();
00076 #if wxCHECK_VERSION(3,0,0)
00077     wxFont font(wxSize(0, textureHeight), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
00078     dc.SetFont(font);
00079 #else
00080     wxFont* font=wxFont::New(wxSize(0, textureHeight), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxT(""));
00081     dc.SetFont(*font);
00082 #endif    
00083     dc.SetTextForeground(*wxWHITE);
00084     dc.DrawText(wxT("0123456789"), 0, 0);
00085     textureWidth = 0;
00086     glyphWidth.resize(10, 0);
00087     for (int i = 0; i < 10; ++i)
00088     {
00089         wxString number;
00090         number << i;
00091         wxSize textSize = dc.GetTextExtent(number);
00092         textureWidth += textSize.GetWidth();
00093         glyphWidth[i] = textSize.GetWidth();
00094     };
00095 #if !wxCHECK_VERSION(3,0,0)
00096     delete font;
00097 #endif  
00098     dc.SelectObject(wxNullBitmap);
00099     return bitmap;
00100 }
00101 
00102 PreviewIdentifyTool::PreviewIdentifyTool(ToolHelper *helper,
00103                                          GLPreviewFrame *owner)
00104     : Tool(helper)
00105 {
00106     holdControl = false;
00107     constantOn = false;
00108     holdLeft = false;
00109     stopUpdating = true;
00110     preview_frame = owner;
00111     if (!texture_created) {
00112         // make the textures. We have a circle border and a square one.
00113         // the textures are white with a the alpha chanel forming a border.
00114         glGenTextures(1, (GLuint*) &rectangle_border_tex);
00115         glGenTextures(1, (GLuint*) &circle_border_tex);
00116         // we only want to specify alpha, but using just alpha in opengl attaches 0
00117         // for the luminosity. I tried biasing the red green and blue values to get
00118         // them to 1.0, but it didn't work under OS X for some reason. Instead we
00119         // use a luminance alpha pair, and use 1.0 for luminance all the time.
00120         {
00121             // In the rectangle texture, the middle is 1/4 opaque, the outer pixels
00122             // are completely transparent, and one pixel in from the edges is
00123             // a completly opaque line.
00124             unsigned char rect_tex_data[rect_ts][rect_ts][2];
00125             // make everything white
00126             for (unsigned int x = 0; x < rect_ts; x++)
00127             {
00128                 for (unsigned int y = 0; y < rect_ts; y++)
00129                 {
00130                     rect_tex_data[x][y][0] = 255;
00131                 }
00132             }
00133             // now set the middle of the mask semi transparent
00134             for (unsigned int x = 2; x < rect_ts - 2; x++)
00135             {
00136                 for (unsigned int y = 2; y < rect_ts - 2; y++)
00137                 {
00138                     rect_tex_data[x][y][1] = 63;
00139                 }
00140             }
00141             // make an opaque border
00142             for (unsigned int d = 1; d < rect_ts - 1; d++)
00143             {
00144                 rect_tex_data[d][1][1] = 255;
00145                 rect_tex_data[d][rect_ts - 2][1] = 255;
00146                 rect_tex_data[1][d][1] = 255;
00147                 rect_tex_data[rect_ts - 2][d][1] = 255;
00148             }
00149             // make a transparent border around that
00150             for (unsigned int d = 0; d < rect_ts; d++)
00151             {
00152                 rect_tex_data[d][0][1] = 0;
00153                 rect_tex_data[d][rect_ts - 1][1] = 0;
00154                 rect_tex_data[0][d][1] = 0;
00155                 rect_tex_data[rect_ts - 1][d][1] = 0;
00156             }
00157             glBindTexture(GL_TEXTURE_2D, rectangle_border_tex);
00158             gluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, rect_ts, rect_ts,
00159                               GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, rect_tex_data);
00160             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
00161                             GL_LINEAR_MIPMAP_LINEAR);
00162             // clamp texture so it won't wrap over the border.
00163             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00164             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00165         }
00166         {
00167             // the circular one should look similar to the rectangle one, but we
00168             // enlarge it so that the circle apears less blocky. We don't want to
00169             // make it equally sharper however, so we make it a bit fuzzier by
00170             // blending.
00171             unsigned char circle_tex_data[circle_ts][circle_ts][2];
00172             for (unsigned int x = 0; x < circle_ts; x++)
00173             {
00174                 for (unsigned int y = 0; y < circle_ts; y++)
00175                 {
00176                     float x_offs = (float) x - circle_middle,
00177                           y_offs = (float) y - circle_middle,
00178                           radius = sqrt(x_offs * x_offs + y_offs * y_offs),
00179                           intensity;
00180                     if (radius < circle_border_inner)
00181                     {
00182                         intensity = 63.0;
00183                     } else if (radius < circle_border_peak)
00184                     {
00185                         intensity = (radius - circle_border_inner) /
00186                               (float) circle_ts_multiple * 255.0 * 3.0 / 4.0 + 64.0;
00187                     } else if (radius < circle_border_outer)
00188                     {
00189                         intensity = (radius - circle_border_peak) /
00190                                         (float) circle_ts_multiple * -255.0 + 256.0;
00191                     } else
00192                     {
00193                         intensity = 0.0;
00194                     }
00195                     circle_tex_data[x][y][0] = 255;
00196                     circle_tex_data[x][y][1] = (unsigned char) intensity;
00197                 }
00198             }
00199             glBindTexture(GL_TEXTURE_2D, circle_border_tex);
00200             gluBuild2DMipmaps(GL_TEXTURE_2D,
00201                               GL_LUMINANCE_ALPHA, circle_ts, circle_ts,
00202                               GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, circle_tex_data);
00203             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
00204                             GL_LINEAR_MIPMAP_LINEAR);
00205             // clamp texture so it won't wrap over the border.
00206             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00207             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00208         }
00209         {
00210             int textureWidth;
00211             wxBitmap fontTexture(GenerateFontTexture(FONT_TEXTURE_HEIGHT, textureWidth, m_glyphWidth));
00212             wxImage image = fontTexture.ConvertToImage();
00213             glGenTextures(1, (GLuint*)&font_tex);
00214             glBindTexture(GL_TEXTURE_2D, font_tex);
00215             unsigned char* font_tex_data = new unsigned char[FONT_TEXTURE_HEIGHT * textureWidth * 2];
00216             for (size_t x = 0; x < textureWidth; ++x)
00217             {
00218                 for (size_t y = 0; y < FONT_TEXTURE_HEIGHT; ++y)
00219                 {
00220                     const unsigned char value = image.GetRed(x, y);
00221                     font_tex_data[2 * y * textureWidth + 2 * x] = value;
00222                     font_tex_data[2 * y * textureWidth + 2 * x + 1] = value;
00223                 };
00224             };
00225             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00226             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00227             gluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, textureWidth, FONT_TEXTURE_HEIGHT,
00228                 GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, font_tex_data);
00229             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
00230                 GL_LINEAR_MIPMAP_LINEAR);
00231             delete[] font_tex_data;
00232 
00233             font_list = glGenLists(10);
00234             float posX = 0;
00235             for (int loop = 0; loop<10; loop++)
00236             {
00237                 glNewList(font_list + loop, GL_COMPILE);
00238                 glBegin(GL_QUADS);
00239                 glTexCoord2f(posX, 0);
00240                 glVertex2i(0, 0);
00241                 glTexCoord2f(posX + m_glyphWidth[loop] / static_cast<float>(textureWidth), 0);
00242                 glVertex2i(m_glyphWidth[loop], 0);
00243                 glTexCoord2f(posX + m_glyphWidth[loop] / static_cast<float>(textureWidth), 1);
00244                 glVertex2i(m_glyphWidth[loop], FONT_TEXTURE_HEIGHT);
00245                 glTexCoord2f(posX, 1);
00246                 glVertex2i(0, FONT_TEXTURE_HEIGHT);
00247                 glEnd();
00248                 glTranslated(m_glyphWidth[loop], 0, 0);
00249                 glEndList();
00250                 posX += m_glyphWidth[loop] / static_cast<float>(textureWidth);
00251             }
00252         }
00253         texture_created = true;
00254     }
00255 }
00256 PreviewIdentifyTool::~PreviewIdentifyTool()
00257 {
00258     // free the textures
00259     glDeleteTextures(1, (GLuint*) &rectangle_border_tex);
00260     glDeleteTextures(1, (GLuint*) &circle_border_tex);
00261     glDeleteLists(font_list, 10);
00262     glDeleteTextures(1, (GLuint*) &font_tex);
00263 }
00264 
00265 void PreviewIdentifyTool::Activate()
00266 {
00267     // register notifications
00268     helper->NotifyMe(PreviewToolHelper::MOUSE_MOVE, this);
00269     helper->NotifyMe(PreviewToolHelper::DRAW_OVER_IMAGES, this);
00270     helper->NotifyMe(PreviewToolHelper::IMAGES_UNDER_MOUSE_CHANGE, this);
00271     helper->NotifyMe(PreviewToolHelper::MOUSE_PRESS, this);
00272     
00273     // clear up
00274     // Assume that there are no images under the mouse when the tool is
00275     // activated. This should be fine if the user clicks the button to activate
00276     // the tool.
00277     image_set.clear();
00278     mouse_is_over_button = false;
00279     /* TODO if it becomes possible to activate the tool by a keyboard shortcut
00280      * or something, call ImagesUnderMouseChangedEvent() to make sure we display
00281      * indicators for images currently under the cursor. */
00282     ImagesUnderMouseChangedEvent();
00283 
00284     helper->SetStatusMessage(_("Move the mouse over the images or image buttons to identify them."));
00285 }
00286 
00287 void PreviewIdentifyTool::StopUpdating() {
00288     if (!image_set.empty()) {
00289         std::set<unsigned int>::iterator iterator;
00290         for (iterator = image_set.begin(); iterator != image_set.end(); ++iterator)
00291         {
00292             DEBUG_ASSERT(*iterator < helper->GetPanoramaPtr()->getNrOfImages());
00293             // reset this button to its default system colour.
00294             preview_frame->SetImageButtonColour(*iterator, 0, 0, 0);
00295             // remove the notification
00296             helper->DoNotNotifyMeBeforeDrawing(*iterator, this);
00297         }
00298     }
00299     image_set.clear();
00300     preview_frame->UpdateIdentifyTools(image_set);
00301     stopUpdating = true;
00302     ForceRedraw();
00303 }
00304 
00305 void PreviewIdentifyTool::ContinueUpdating() {
00306     stopUpdating = false;
00307     ImagesUnderMouseChangedEvent();
00308 }
00309 
00310 void PreviewIdentifyTool::MouseMoveEvent(double x, double y, wxMouseEvent & e)
00311 {
00312 
00313     bool stop = false;
00314     bool start = false;
00315 
00316     if (constantOn) {
00317         if (e.Dragging() && !(holdLeft)) {
00318             stop = true;
00319             stopUpdating = true;
00320         }
00321 
00322         if (stopUpdating && !e.LeftIsDown() && !e.MiddleIsDown() && !e.RightIsDown()) {
00323             start = true;
00324         }
00325     }
00326 
00327     if (holdControl && !e.m_controlDown) {
00328         holdControl = false;
00329         if (!constantOn) {
00330             stop = true;
00331         }
00332     }
00333     
00334     if (!holdControl && e.m_controlDown) {
00335         holdControl = true;
00336         stop = false;
00337         if (stopUpdating) {
00338             start = true;
00339         }
00340     }
00341     
00342     if (stop) {
00343         this->StopUpdating();
00344     } else if(start) {
00345         this->ContinueUpdating();
00346     }
00347 
00348 
00349 }
00350 
00351 void PreviewIdentifyTool::KeypressEvent(int keycode, int modifierss, int pressed) {
00352 
00353     if (keycode == WXK_CONTROL) {
00354         if (pressed) {
00355             holdControl = true;
00356             ContinueUpdating();
00357         } else {
00358             if(holdControl) {
00359                 StopUpdating();
00360             }
00361             holdControl = false;
00362         }
00363     }
00364 }
00365 
00366 void PreviewIdentifyTool::setConstantOn(bool constant_on_in) {
00367     constantOn = constant_on_in;
00368     if (constant_on_in) {
00369         stopUpdating = false;
00370         ContinueUpdating();
00371     } else {
00372         stopUpdating = true;
00373         StopUpdating();
00374     }
00375 
00376 }
00377 
00378 
00379 void PreviewIdentifyTool::ImagesUnderMouseChangedEvent()
00380 {
00381     if (stopUpdating) {
00382         return;
00383     }
00384     
00385     std::set<unsigned int> new_image_set = helper->GetImageNumbersUnderMouse();
00386     
00387     //UpdateIdentifyTools() will unrequest notification for the old indicators,
00388     //reset the button colors, request notification for the new ones, swap in
00389     //image_set with new_image_set, and force a redraw for all three
00390     //PreviewIdentifyTool objects in GLPreviewFrame. This has the effect of 
00391     //displaying the indicators in both the preview and overview when you move
00392     //your mouse over either when the Identify button is toggled on. 
00393     preview_frame->UpdateIdentifyTools(new_image_set);
00394     
00395     // if there is exactly two images, tell the user they can click to edit CPs.
00396     if (image_set.size() == 2)
00397     {
00398          helper->SetStatusMessage(_("Click to create or edit control points here."));
00399     } else {
00400          helper->SetStatusMessage(_("Move the mouse over the images or image buttons to identify them."));
00401     }
00402 }
00403 
00404 void PreviewIdentifyTool::AfterDrawImagesEvent()
00405 {
00406     // we draw the partly transparent identification boxes over the top of the
00407     // entire stack of images in image_set so that the extents of images in the
00408     // background are clearly marked.
00409     unsigned int num_images = image_set.size();
00410     // draw the actual images
00411     // the preview draws them in reverse order, so the lowest numbered appears
00412     // on top. We will folow this convention to avoid confusion.
00413     glMatrixMode(GL_MODELVIEW);
00414     std::set<unsigned int>::reverse_iterator it;
00415     for (it = image_set.rbegin(); it != image_set.rend(); ++it)
00416     {
00417         DEBUG_ASSERT(*it < helper->GetPanoramaPtr()->getNrOfImages());
00418         helper->GetViewStatePtr()->GetTextureManager()->
00419                 DrawImage(*it,
00420                          helper->GetVisualizationStatePtr()->GetMeshDisplayList(*it));
00421     }
00422     glMatrixMode(GL_TEXTURE);
00423     
00424     // now draw the identification boxes
00425     glEnable(GL_BLEND);
00426     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00427     unsigned int image_counter = 0;
00428     const unsigned int canvasWidth = helper->GetViewStatePtr()->GetOptions()->getWidth();
00429     const unsigned int canvasHeight = helper->GetViewStatePtr()->GetOptions()->getHeight();
00430     for (it = image_set.rbegin(); it != image_set.rend(); ++it)
00431     {
00432         glMatrixMode(GL_TEXTURE);
00433         // Use the mask to alter the shape of the identification boxes, but
00434         // replace the normal image texture with the identification box itself.
00435         if (helper->GetViewStatePtr()->GetSupportMultiTexture())
00436         {
00437             helper->GetViewStatePtr()->GetTextureManager()->BindTexture(*it);
00438             glActiveTexture(GL_TEXTURE0);
00439         }
00440         // we want to shift the texture so it lines up with the cropped region.
00441         glPushMatrix();
00442         HuginBase::SrcPanoImage *src = helper->GetViewStatePtr()->
00443                                                                GetSrcImage(*it);
00444         int width = src->getSize().width(), height = src->getSize().height();
00445         vigra::Rect2D crop_region = src->getCropRect();
00446         // pick a texture depending on crop mode and move it to the cropped area
00447         switch (src->getCropMode())
00448         {
00449             case HuginBase::SrcPanoImage::CROP_CIRCLE:
00450                 glBindTexture(GL_TEXTURE_2D, circle_border_tex);
00451                 // change the crop region to a square around the circle.
00452                 if (crop_region.width() < crop_region.height())
00453                 {
00454                     // too tall, move top and bottom.
00455                     int diff = (crop_region.width() - crop_region.height()) / 2;
00456                     // diff is negative, so we will shrink the border in the y
00457                     // direction.
00458                     crop_region.addBorder(0, diff);
00459                 } else if (crop_region.width() > crop_region.height())
00460                 {
00461                     // too wide, move left and right
00462                     int diff = (crop_region.height() - crop_region.width()) / 2;
00463                     crop_region.addBorder(diff, 0);
00464                 }
00465                 {
00466                     float diameter = (float) crop_region.width();
00467                     glScalef((float) width / diameter,
00468                              (float) height / diameter, 1.0);
00469                     glTranslatef(-(float) crop_region.left() / (float) width,
00470                                  -(float) crop_region.top() / (float) height,
00471                                  0.0);
00472                 }
00473                 break;
00474             case HuginBase::SrcPanoImage::CROP_RECTANGLE:
00475                 // get the biggest rectangle contained by both the image 
00476                 // and the cropped area.
00477                 crop_region &= vigra::Rect2D(src->getSize());
00478                 glBindTexture(GL_TEXTURE_2D, rectangle_border_tex);
00479                 glScalef((float) width / (float) crop_region.width(),
00480                          (float) height / (float) crop_region.height(),
00481                          1.0);
00482                 glTranslatef(-(float) crop_region.left() / (float) width,
00483                              -(float) crop_region.top() / (float) height,
00484                              0.0);
00485                 break;
00486             case HuginBase::SrcPanoImage::NO_CROP:
00487                 glBindTexture(GL_TEXTURE_2D, rectangle_border_tex);
00488                 break;
00489         }
00490         // draw the image in this texture
00491         glMatrixMode(GL_MODELVIEW);
00492         unsigned char r,g,b;
00493         HighlightColour(image_counter, num_images, r, g, b);
00494         image_counter++;
00495         glColor3ub(r,g,b);
00496         glCallList(helper->GetVisualizationStatePtr()->GetMeshDisplayList(*it));
00497         glMatrixMode(GL_TEXTURE);
00498         glPopMatrix();
00499         // tell the preview frame to update the button to show the same colour.
00500         preview_frame->SetImageButtonColour(*it, r, g, b);
00501         // draw number
00502         HuginBase::PanoramaOptions* opts = helper->GetViewStatePtr()->GetOptions();
00503         HuginBase::SrcPanoImage* img = helper->GetViewStatePtr()->GetSrcImage(*it);
00504         HuginBase::PTools::Transform transform;
00505         transform.createInvTransform(*img, *opts);
00506         hugin_utils::FDiff2D imageCenter(crop_region.upperLeft() + crop_region.size() / 2);
00507         hugin_utils::FDiff2D imageCenterPano;
00508         if (transform.transformImgCoord(imageCenterPano, imageCenter) && !wxGetKeyState(WXK_ALT))
00509         {
00510             glBindTexture(GL_TEXTURE_2D, font_tex);
00511             if (helper->GetViewStatePtr()->GetSupportMultiTexture())
00512             {
00513                 glActiveTexture(GL_TEXTURE1);
00514                 glDisable(GL_TEXTURE_2D);
00515                 glActiveTexture(GL_TEXTURE0);
00516             };
00517             glMatrixMode(GL_MODELVIEW);
00518             glPushMatrix();
00519             wxString number;
00520             number << *it;
00521             int textWidth = 0;
00522             for (size_t i = 0; i < number.Length(); ++i)
00523             {
00524 #if wxCHECK_VERSION(3,0,0)
00525                 textWidth += m_glyphWidth[number[i].GetValue() - 48];
00526 #else
00527                 textWidth += m_glyphWidth[number[i] - 48];
00528 #endif
00529             }
00530             float scaleFactor = std::min(canvasWidth, canvasHeight) / static_cast<float>(FONT_TEXTURE_HEIGHT) / 10;
00531             imageCenterPano.x = std::min<double>(std::max<double>(imageCenterPano.x, textWidth*scaleFactor / 2.0), canvasWidth - textWidth * scaleFactor / 2.0);
00532             imageCenterPano.y = std::min<double>(std::max<double>(imageCenterPano.y, FONT_TEXTURE_HEIGHT*scaleFactor / 2.0), canvasHeight - FONT_TEXTURE_HEIGHT * scaleFactor / 2.0);
00533             glTranslatef(imageCenterPano.x, imageCenterPano.y, 0);
00534             glScalef(scaleFactor, scaleFactor, 1.0);
00535             glTranslatef(-textWidth / 2, -FONT_TEXTURE_HEIGHT / 2, 0);
00536             glListBase(font_list - 48);
00537             glCallLists(number.Length(), GL_UNSIGNED_BYTE, number.c_str());
00538             glMatrixMode(GL_MODELVIEW);
00539             glPopMatrix();
00540         };
00541     }
00542     // set stuff back how we found it.
00543     glMatrixMode(GL_MODELVIEW);
00544     glDisable(GL_BLEND);
00545     glColor3ub(255, 255, 255);
00546 }
00547 
00548 bool PreviewIdentifyTool::BeforeDrawImageEvent(unsigned int image)
00549 {
00550     // Delay drawing of images, so we can show them on top of the others.
00551     DEBUG_ASSERT(image < helper->GetPanoramaPtr()->getNrOfImages());
00552     if (image_set.count(image)) return false;
00553     return true;
00554 }
00555 
00556 void PreviewIdentifyTool::ShowImageNumber(unsigned int image)
00557 {
00558     DEBUG_ASSERT(image < helper->GetPanoramaPtr()->getNrOfImages());
00559     // Add this image to the set of images drawn.
00560     if (!image_set.count(image))
00561     {
00562         // it is not already in the set. Add it now
00563         image_set.insert(image);
00564         // we want notification of when it is drawn so we can delay drawing.
00565         helper->NotifyMeBeforeDrawing(image, this);
00566         //  now we want a redraw.
00567         ForceRedraw();
00568     }
00569     mouse_over_image = image;
00570     mouse_is_over_button = true;
00571 }
00572 
00573 void PreviewIdentifyTool::StopShowingImages()
00574 {
00575     if (mouse_is_over_button)
00576     {
00577         // set the colour to the image the user just moused off to the default.
00578         preview_frame->SetImageButtonColour(mouse_over_image, 0, 0, 0);
00579         helper->DoNotNotifyMeBeforeDrawing(mouse_over_image, this);
00580         image_set.erase(mouse_over_image);
00581         // now redraw without the indicator.
00582         ForceRedraw();
00583         mouse_is_over_button = false;
00584     }    
00585 }
00586 
00587 // generate a colour given how many colours we need and an index.
00588 void PreviewIdentifyTool::HighlightColour(unsigned int index,
00589                                           unsigned int count,
00590                                           unsigned char &red,
00591                                           unsigned char &green,
00592                                           unsigned char &blue)
00593 {
00594     DEBUG_ASSERT(index < count && index >= 0);
00595     // the first one is red, the rest are evenly spaced throughout the spectrum 
00596     float hue = ((float) index / (float) count) * 6.0;
00597     if (hue < 1.0)
00598     {
00599         // red to yellow
00600         red = 255;
00601         green = (unsigned char) (hue * 255.0);
00602         blue = 0;
00603     } else if (hue < 2.0) {
00604         // yellow to green
00605         red = (unsigned char) ((-hue + 2.0) * 255.0);
00606         green = 255;
00607         blue = 0;
00608     } else if (hue < 3.0) {
00609         // green to cyan
00610         red = 0;
00611         green = 255;
00612         blue = (unsigned char) ((hue - 2.0) * 255.0);
00613     } else if (hue < 4.0) {
00614         // cyan to blue
00615         red = 0;
00616         green = (unsigned char) ((-hue + 4.0) * 255.0);
00617         blue = 255;
00618     } else if (hue < 5.0) {
00619         // blue to magenta
00620         red = (unsigned char) ((hue - 4.0) * 255.0);
00621         green = 0;
00622         blue = 255;
00623     } else {
00624         // magenta to red
00625         red = 255;
00626         green = 0;
00627         blue = (unsigned char) ((-hue + 6.0) * 255.0);
00628     }
00629 }
00630 
00631 void PreviewIdentifyTool::MouseButtonEvent(wxMouseEvent & e)
00632 {
00633 
00634 
00635     if ( e.LeftDown() && helper->IsMouseOverPano())
00636     {   
00637         holdLeft = true;
00638     } 
00639 
00640     if (holdLeft && e.LeftUp() && (image_set.size()==1 || image_set.size() == 2)) 
00641     {
00642         holdLeft = false;
00643         if (constantOn || e.CmdDown())
00644         {
00645             // when there are only two images with indicators shown, show the
00646             // control point editor with those images when left clicked.
00647             if(image_set.size()==2)
00648             {
00649                 MainFrame::Get()->ShowCtrlPointEditor(*(image_set.begin()),
00650                                                         *(++image_set.begin()));
00651             }
00652             else
00653             {
00654                 MainFrame::Get()->ShowMaskEditor(*image_set.begin());
00655             };
00656             MainFrame::Get()->Raise();
00657         }
00658     }
00659 
00660     if (holdLeft && !(e.LeftIsDown())) {
00661         holdLeft = false;
00662     }
00663 
00664     if (constantOn) {
00665         if (e.ButtonUp() && !e.MiddleIsDown() && !e.RightIsDown()) {
00666             stopUpdating = false;
00667             ImagesUnderMouseChangedEvent();
00668         }
00669     }
00670 
00671 }
00672 
00673 void PreviewIdentifyTool::UpdateWithNewImageSet(std::set<unsigned int> new_image_set)
00674 {
00675     // If we are currently showing indicators for some of the images, we want
00676     // to work out which ones are not in the new set, so we can set their
00677     // buttons back to the system colour.
00678     if (!image_set.empty())
00679     {
00680         HuginBase::UIntSet difference;
00681         std::set_difference (image_set.begin(), image_set.end(),
00682                              new_image_set.begin(), new_image_set.end(),
00683                              std::inserter(difference,difference.end()));
00684         if (!difference.empty())
00685         {
00686             for (HuginBase::UIntSet::iterator iterator = difference.begin(); iterator != difference.end(); ++iterator)
00687             {
00688                 DEBUG_ASSERT(*iterator < helper->GetPanoramaPtr()->getNrOfImages());
00689                 // reset this button to its default system colour.
00690                 preview_frame->SetImageButtonColour(*iterator, 0, 0, 0);
00691                 // remove the notification
00692                 helper->DoNotNotifyMeBeforeDrawing(*iterator, this);
00693             }
00694         }
00695     }
00696 
00697     // now request to be notified when drawing the new ones.
00698     if (!new_image_set.empty())
00699     {
00700         HuginBase::UIntSet difference;
00701         std::set_difference(new_image_set.begin(), new_image_set.end(),
00702             image_set.begin(), image_set.end(),
00703             std::inserter(difference, difference.end()));
00704         if (!difference.empty())
00705         {
00706             for (HuginBase::UIntSet::iterator iterator = difference.begin(); iterator != difference.end(); ++iterator)
00707             {
00708                 DEBUG_ASSERT(*iterator < helper->GetPanoramaPtr()->getNrOfImages());
00709                 // get notification of when this is about to be drawn.
00710                 helper->NotifyMeBeforeDrawing(*iterator, this);
00711             }
00712         }
00713     };
00714     // remember the new set.
00715     image_set.swap(new_image_set);
00716 
00717     // Redraw with new indicators. Since the indicators aren't part of the
00718     // panorama and none of it is likely to change, we have to persuade the
00719     // viewstate that a redraw is required.
00720     ForceRedraw();
00721 }
00722 
00723 void PreviewIdentifyTool::ForceRedraw()
00724 {
00725     helper->GetVisualizationStatePtr()->ForceRequireRedraw();
00726     helper->GetVisualizationStatePtr()->Redraw();
00727 }

Generated on 3 Aug 2015 for Hugintrunk by  doxygen 1.4.7