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

Generated on 30 Jun 2016 for Hugintrunk by  doxygen 1.4.7