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

Generated on 5 Feb 2016 for Hugintrunk by  doxygen 1.4.7