MaskImageCtrl.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00013 /*  This program is free software; you can redistribute it and/or
00014  *  modify it under the terms of the GNU General Public
00015  *  License as published by the Free Software Foundation; either
00016  *  version 2 of the License, or (at your option) any later version.
00017  *
00018  *  This software is distributed in the hope that it will be useful,
00019  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021  *  General Public License for more details.
00022  *
00023  *  You should have received a copy of the GNU General Public
00024  *  License along with this software. If not, see
00025  *  <http://www.gnu.org/licenses/>.
00026  *
00027  */
00028 
00029 #include "panoinc_WX.h"
00030 #include "panoinc.h"
00031 #include "base_wx/platform.h"
00032 #include "base_wx/wxcms.h"
00033 #include "hugin/MainFrame.h"
00034 #include "hugin/huginApp.h"
00035 #include "hugin/config_defaults.h"
00036 #include "hugin/MaskImageCtrl.h"
00037 #include "hugin/MaskEditorPanel.h"
00038 #include "base_wx/wxImageCache.h"
00039 #ifndef SUPPORTS_WXINVERT
00040 #include <vigra/inspectimage.hxx>
00041 #endif
00042 
00044 const int polygonPointSize=3;
00046 const int maxSelectionDistance=20;
00047 
00048 // our image control
00049 
00050 BEGIN_EVENT_TABLE(MaskImageCtrl, wxScrolledWindow)
00051     EVT_SIZE(MaskImageCtrl::OnSize)
00052     EVT_MOTION(MaskImageCtrl::OnMouseMove)
00053     EVT_LEFT_DOWN(MaskImageCtrl::OnLeftMouseDown)
00054     EVT_LEFT_UP(MaskImageCtrl::OnLeftMouseUp)
00055     EVT_LEFT_DCLICK(MaskImageCtrl::OnLeftMouseDblClick)
00056     EVT_RIGHT_DOWN(MaskImageCtrl::OnRightMouseDown)
00057     EVT_RIGHT_UP(MaskImageCtrl::OnRightMouseUp)
00058     EVT_KEY_UP(MaskImageCtrl::OnKeyUp)
00059     EVT_MOUSE_CAPTURE_LOST(MaskImageCtrl::OnCaptureLost)
00060     EVT_KILL_FOCUS(MaskImageCtrl::OnKillFocus)
00061     EVT_SCROLLWIN(MaskImageCtrl::OnScroll)
00062 END_EVENT_TABLE()
00063 
00064 bool MaskImageCtrl::Create(wxWindow * parent, wxWindowID id,
00065                          const wxPoint& pos,
00066                          const wxSize& size,
00067                          long style,
00068                          const wxString& name)
00069 {
00070     wxScrolledWindow::Create(parent, id, pos, size, style, name);
00071     m_maskEditState = NO_IMAGE;
00072     m_imgRotation = ROT0;
00073     m_scaleFactor = 1;
00074     m_fitToWindow = false;
00075     m_previewOnly = false;
00076     m_activeMask = UINT_MAX;
00077     m_showActiveMasks = false;
00078     m_maskMode = true;
00079     m_oldScrollPosX = -1;
00080     m_oldScrollPosY = -1;
00081 
00082     return true;
00083 }
00084 
00085 void MaskImageCtrl::Init(MaskEditorPanel * parent)
00086 {
00087     m_editPanel = parent;
00088 }
00089 
00090 void MaskImageCtrl::SetMaskMode(bool newMaskMode)
00091 {
00092     m_maskMode=newMaskMode;
00093     if(m_maskMode)
00094     {
00095         SetCursor(wxNullCursor);
00096         if(m_maskEditState!=NO_IMAGE)
00097         {
00098             m_maskEditState=NO_SELECTION;
00099             setActiveMask(UINT_MAX,false);
00100         };
00101     }
00102     else
00103     {
00104         if(m_maskEditState!=NO_IMAGE)
00105         {
00106             m_maskEditState=CROP_SHOWING;
00107         };
00108     };
00109 };
00110 
00111 void MaskImageCtrl::setImage(const std::string & file, HuginBase::MaskPolygonVector newMask, HuginBase::MaskPolygonVector masksToDraw, ImageRotation rot)
00112 {
00113     DEBUG_TRACE("setting Image " << file);
00114     if(!file.empty())
00115     {
00116         try
00117         {
00118             m_img = ImageCache::getInstance().getImage(file);
00119         }
00120         catch (...)
00121         {
00122             // loading of image failed, set all to empty values
00123             m_imageFilename = "";
00124             m_maskEditState = NO_IMAGE;
00125             m_bitmap = wxBitmap();
00126             // delete the image (release shared_ptr)
00127             // create an empty image.
00128             m_img = ImageCache::EntryPtr(new ImageCache::Entry);
00129             HuginBase::MaskPolygonVector mask;
00130             m_imageMask = mask;
00131             m_masksToDraw = mask;
00132             m_imgRotation = ROT0;
00133             setActiveMask(UINT_MAX, false);
00134             SetVirtualSize(100, 100);
00135             Refresh(true);
00136             // now notify main frame to remove the image from project
00137             wxCommandEvent e(EVT_LOADING_FAILED);
00138             e.SetString(wxString(file.c_str(), HUGIN_CONV_FILENAME));
00139             MainFrame::Get()->GetEventHandler()->AddPendingEvent(e);
00140             return;
00141         }
00142         m_imageFilename = file;
00143         if(m_maskMode)
00144         {
00145             m_maskEditState = NO_MASK;
00146         }
00147         else
00148         {
00149             m_maskEditState = CROP_SHOWING;
00150         };
00151         m_imageMask=newMask;
00152         m_masksToDraw=masksToDraw;
00153         m_imgRotation=rot;
00154         setActiveMask(UINT_MAX,false);
00155         rescaleImage();
00156         Scroll(m_oldScrollPosX, m_oldScrollPosY);
00157     }
00158     else
00159     {
00160         m_maskEditState = NO_IMAGE;
00161         m_bitmap = wxBitmap();
00162         // delete the image (release shared_ptr)
00163         // create an empty image.
00164         m_img = ImageCache::EntryPtr(new ImageCache::Entry);
00165         HuginBase::MaskPolygonVector mask;
00166         m_imageMask=mask;
00167         m_masksToDraw=mask;
00168         m_imgRotation=ROT0;
00169         setActiveMask(UINT_MAX,false);
00170         SetVirtualSize(100,100);
00171         Refresh(true);
00172     }
00173 }
00174 
00175 void MaskImageCtrl::setNewMasks(HuginBase::MaskPolygonVector newMasks, HuginBase::MaskPolygonVector masksToDraw)
00176 {
00177     m_imageMask=newMasks;
00178     m_masksToDraw=masksToDraw;
00179     if (m_activeMask >= m_imageMask.size())
00180     {
00181         setActiveMask(UINT_MAX);
00182     }
00183     else
00184     {
00185         setActiveMask(m_activeMask);
00186     };
00187     Refresh(false);
00188 };
00189 
00190 void MaskImageCtrl::setCrop(HuginBase::SrcPanoImage::CropMode newCropMode, vigra::Rect2D newCropRect, bool isCentered, hugin_utils::FDiff2D center, bool isCircleCrop)
00191 {
00192     m_cropMode=newCropMode;
00193     m_cropRect=newCropRect;
00194     m_cropCentered=isCentered;
00195     m_cropCenter=center;
00196     m_cropCircle=isCircleCrop;
00197 };
00198 
00199 void MaskImageCtrl::setActiveMask(unsigned int newMask, bool doUpdate)
00200 {
00201     if(m_activeMask!=newMask)
00202     {
00203         m_activeMask=newMask;
00204         m_selectedPoints.clear();
00205     };
00206     if(newMask<UINT_MAX)
00207     {
00208         if(m_maskMode)
00209         {
00210             if(m_selectedPoints.empty())
00211             {
00212                 m_maskEditState=NO_SELECTION;
00213             }
00214             else
00215             {
00216                 m_maskEditState=POINTS_SELECTED;
00217             };
00218         }
00219         else
00220         {
00221             m_selectedPoints.clear();
00222             m_maskEditState=CROP_SHOWING;
00223         };
00224         m_editingMask=m_imageMask[m_activeMask];
00225     }
00226     else
00227     {
00228         if(!m_imageFilename.empty())
00229         {
00230             if(m_maskMode)
00231             {
00232                 m_maskEditState=NO_MASK;
00233             }
00234             else
00235             {
00236                 m_maskEditState=CROP_SHOWING;
00237             };
00238         };
00239         HuginBase::MaskPolygon mask;
00240         m_editingMask=mask;
00241     };
00242     if(doUpdate)
00243         Refresh(true);
00244 };
00245 
00246 void MaskImageCtrl::selectAllMarkers()
00247 {
00248     m_selectedPoints.clear();
00249     if(m_activeMask<UINT_MAX)
00250         fill_set(m_selectedPoints,0,m_imageMask[m_activeMask].getMaskPolygon().size()-1);
00251 };
00252 
00253 // returns where the user clicked
00254 MaskImageCtrl::ClickPos MaskImageCtrl::GetClickPos(vigra::Point2D pos)
00255 {
00256     vigra::Rect2D testRect(pos.x-maxSelectionDistance, pos.y-maxSelectionDistance, pos.x+maxSelectionDistance, pos.y+maxSelectionDistance);
00257     if (m_cropMode == HuginBase::SrcPanoImage::CROP_CIRCLE)
00258     {
00259         double radius=std::min<int>(m_cropRect.width(), m_cropRect.height())/2.0;
00260         vigra::Point2D pos_center((m_cropRect.left()+m_cropRect.right())/2, (m_cropRect.top()+m_cropRect.bottom())/2);
00261         double dist=sqrt(double((pos-pos_center).squaredMagnitude()));
00262         if(dist-maxSelectionDistance<radius && radius<dist+maxSelectionDistance)
00263         {
00264             return CLICK_CIRCLE;
00265         };
00266     };
00267     if(m_cropRect.intersects(testRect))
00268     {
00269         if(abs(pos.x-m_cropRect.left())<maxSelectionDistance)
00270         {
00271             return CLICK_LEFT;
00272         };
00273         if(abs(pos.x-m_cropRect.right())<maxSelectionDistance)
00274         {
00275             return CLICK_RIGHT;
00276         };
00277         if(abs(pos.y-m_cropRect.top())<maxSelectionDistance)
00278         {
00279             return CLICK_TOP;
00280         };
00281         if(abs(pos.y-m_cropRect.bottom())<maxSelectionDistance)
00282         {
00283             return CLICK_BOTTOM;
00284         };
00285     };
00286     if(m_cropRect.contains(pos))
00287     {
00288         return CLICK_INSIDE;
00289     };
00290     return CLICK_OUTSIDE;
00291 };
00292 
00293 void MaskImageCtrl::UpdateCrop(hugin_utils::FDiff2D pos)
00294 {
00295     hugin_utils::FDiff2D delta=pos-applyRotInv(invtransform(m_currentPos));
00296     int newLeft, newRight, newTop, newBottom;
00297     bool needsUpdate=false;
00298     switch (m_maskEditState)
00299     {
00300         case CROP_MOVING:
00301             m_cropRect.moveBy(delta.x,delta.y);
00302             break;
00303         case CROP_LEFT_MOVING:
00304             if(m_cropCentered)
00305             {
00306                 double newHalfWidth=m_cropRect.width()/2.0-delta.x;
00307                 newLeft=hugin_utils::roundi(m_cropCenter.x-newHalfWidth);
00308                 newRight=hugin_utils::roundi(m_cropCenter.x+newHalfWidth);
00309             }
00310             else
00311             {
00312                 newLeft=m_cropRect.left()+delta.x;
00313                 newRight=m_cropRect.right();
00314             };
00315             newTop=m_cropRect.top();
00316             newBottom=m_cropRect.bottom();
00317             needsUpdate=true;
00318             break;
00319         case CROP_RIGHT_MOVING:
00320             if(m_cropCentered)
00321             {
00322                 double newHalfWidth=m_cropRect.width()/2.0+delta.x;
00323                 newLeft=hugin_utils::roundi(m_cropCenter.x-newHalfWidth);
00324                 newRight=hugin_utils::roundi(m_cropCenter.x+newHalfWidth);
00325             }
00326             else
00327             {
00328                 newLeft=m_cropRect.left();
00329                 newRight=m_cropRect.right()+delta.x;
00330             };
00331             newTop=m_cropRect.top();
00332             newBottom=m_cropRect.bottom();
00333             needsUpdate=true;
00334             break;
00335         case CROP_TOP_MOVING:
00336             if(m_cropCentered)
00337             {
00338                 double newHalfHeight=m_cropRect.height()/2.0-delta.y;
00339                 newTop=hugin_utils::roundi(m_cropCenter.y-newHalfHeight);
00340                 newBottom=hugin_utils::roundi(m_cropCenter.y+newHalfHeight);
00341             }
00342             else
00343             {
00344                 newTop=m_cropRect.top()+delta.y;
00345                 newBottom=m_cropRect.bottom();
00346             };
00347             newLeft=m_cropRect.left();
00348             newRight=m_cropRect.right();
00349             needsUpdate=true;
00350             break;
00351         case CROP_BOTTOM_MOVING:
00352             if(m_cropCentered)
00353             {
00354                 double newHalfHeight=m_cropRect.height()/2.0+delta.y;
00355                 newTop=hugin_utils::roundi(m_cropCenter.y-newHalfHeight);
00356                 newBottom=hugin_utils::roundi(m_cropCenter.y+newHalfHeight);
00357             }
00358             else
00359             {
00360                 newTop=m_cropRect.top();
00361                 newBottom=m_cropRect.bottom()+delta.y;
00362             };
00363             newLeft=m_cropRect.left();
00364             newRight=m_cropRect.right();
00365             needsUpdate=true;
00366             break;
00367         case CROP_CIRCLE_SCALING:
00368             {
00369                 double radius=sqrt(hugin_utils::sqr(pos.x-m_dragStartPos.x)+hugin_utils::sqr(pos.y-m_dragStartPos.y));
00370                 newLeft=m_dragStartPos.x-radius;
00371                 newRight=m_dragStartPos.x+radius;
00372                 newTop=m_dragStartPos.y-radius;
00373                 newBottom=m_dragStartPos.y+radius;
00374                 needsUpdate=true;
00375             };
00376             break;
00377         default:
00378             // in all other cases the crop is not changed
00379             // this should not happen
00380             break;
00381     };
00382     if(needsUpdate)
00383     {
00384         // switch left/right or top/bottom if necessary
00385         if(newLeft>newRight)
00386         {
00387             int temp=newLeft;
00388             newLeft=newRight;
00389             newRight=temp;
00390         };
00391         if(newTop>newBottom)
00392         {
00393             int temp=newTop;
00394             newTop=newBottom;
00395             newBottom=temp;
00396         };
00397         m_cropRect.setUpperLeft(vigra::Point2D(newLeft, newTop));
00398         m_cropRect.setLowerRight(vigra::Point2D(newRight, newBottom));
00399     };
00400 };
00401 
00402 void MaskImageCtrl::OnMouseMove(wxMouseEvent& mouse)
00403 {
00404     if(m_previewOnly)
00405         return;
00406     wxPoint mpos;
00407     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00408                            &mpos.x, & mpos.y);
00409     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(mpos));
00410     bool doUpdate = false;
00411     switch(m_maskEditState)
00412     {
00413         case NEW_POLYGON_CREATING:
00414             doUpdate=true;
00415             m_editingMask.movePointTo(m_editingMask.getMaskPolygon().size()-1,currentPos);
00416             break;
00417         case POLYGON_SELECTING:
00418         case REGION_SELECTING:
00419         case POINTS_DELETING:
00420 #if defined SUPPORTS_WXINVERT
00421             DrawSelectionRectangle();
00422 #endif
00423             m_currentPos=mpos;
00424             DrawSelectionRectangle();
00425             break;
00426         case POINTS_MOVING:
00427             doUpdate=true;
00428             m_editingMask=m_imageMask[m_activeMask];
00429             {
00430                 hugin_utils::FDiff2D delta=currentPos-applyRotInv(invtransform(m_dragStartPos));
00431                 for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00432                     m_editingMask.movePointBy(*it,delta);
00433             };
00434             break;
00435         case POINTS_ADDING:
00436             doUpdate=true;
00437             for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00438                 m_editingMask.movePointTo(*it,currentPos);
00439             break;
00440         case CROP_SHOWING:
00441             switch(GetClickPos(vigra::Point2D(currentPos.x, currentPos.y)))
00442             {
00443                 case CLICK_INSIDE:
00444                     if(!m_cropCentered)
00445                     {
00446                         SetCursor(wxCURSOR_HAND);
00447                     }
00448                     else
00449                     {
00450                         SetCursor(wxNullCursor);
00451                     };
00452                     break;
00453                 case CLICK_LEFT:
00454                 case CLICK_RIGHT:
00455                     switch (m_imgRotation)
00456                     {
00457                         case ROT90:
00458                         case ROT270:
00459                             SetCursor(wxCURSOR_SIZENS);
00460                             break;
00461                         default:
00462                             SetCursor(wxCURSOR_SIZEWE);
00463                     };
00464                     break;
00465                 case CLICK_TOP:
00466                 case CLICK_BOTTOM:
00467                     switch (m_imgRotation)
00468                     {
00469                         case ROT90:
00470                         case ROT270:
00471                             SetCursor(wxCURSOR_SIZEWE);
00472                             break;
00473                         default:
00474                             SetCursor(wxCURSOR_SIZENS);
00475                     };
00476                     break;
00477                 case CLICK_CIRCLE:
00478                     SetCursor(wxCURSOR_SIZING);
00479                     break;
00480                 default:
00481                     SetCursor(wxNullCursor);
00482             };
00483             break;
00484         case CROP_MOVING:
00485         case CROP_LEFT_MOVING:
00486         case CROP_RIGHT_MOVING:
00487         case CROP_TOP_MOVING:
00488         case CROP_BOTTOM_MOVING:
00489         case CROP_CIRCLE_SCALING:
00490 #if defined SUPPORTS_WXINVERT
00491             DrawCrop();
00492 #else
00493             doUpdate=true;
00494 #endif
00495             UpdateCrop(currentPos);
00496             m_currentPos=mpos;
00497 #if defined SUPPORTS_WXINVERT
00498             DrawCrop();
00499 #endif
00500             m_editPanel->UpdateCropFromImage();
00501             break;
00502         case NO_IMAGE:
00503         case NO_MASK:
00504         case NO_SELECTION:
00505         case POINTS_SELECTED:
00506         case NEW_POLYGON_STARTED:
00507             // in all other cases do nothing
00508             break;
00509     };
00510     if(doUpdate)
00511         update();
00512 }
00513 
00514 void MaskImageCtrl::OnLeftMouseDown(wxMouseEvent& mouse)
00515 {
00516     if(m_previewOnly)
00517         return;
00518     DEBUG_DEBUG("LEFT MOUSE DOWN");
00519     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00520                            &m_dragStartPos.x, & m_dragStartPos.y);
00521     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(m_dragStartPos));
00522     m_currentPos=m_dragStartPos;
00523     if(!HasCapture())
00524         CaptureMouse();
00525     SetFocus();
00526     switch(m_maskEditState)
00527     {
00528         case NEW_POLYGON_STARTED:
00529             //starting polygon creating
00530             m_editingMask.addPoint(currentPos);
00531             m_selectedPoints.insert(m_editingMask.getMaskPolygon().size()-1);
00532             break;
00533         case NO_MASK:
00534             if(m_maskMode)
00535             {
00536                 m_maskEditState=POLYGON_SELECTING;
00537                 DrawSelectionRectangle();
00538             };
00539             break;
00540         case NO_SELECTION:
00541             if(mouse.CmdDown())
00542             {
00543                 // check if mouse clicks happens near one line of active polygon
00544                 unsigned int index=m_editingMask.FindPointNearPos(currentPos,5*maxSelectionDistance);
00545                 if(index<UINT_MAX)
00546                 {
00547                     m_selectedPoints.clear();
00548                     m_editingMask.insertPoint(index,currentPos);
00549                     m_selectedPoints.insert(index);
00550                     m_maskEditState=POINTS_ADDING;
00551                 };
00552             }
00553             else
00554             {
00555                 HuginBase::UIntSet points;
00556                 if(SelectPointsInsideMouseRect(points,false))
00557                 {
00558                     for(HuginBase::UIntSet::const_iterator it=points.begin();it!=points.end();++it)
00559                         m_selectedPoints.insert(*it);
00560                     m_maskEditState=POINTS_MOVING;
00561                 }
00562                 else
00563                 {
00564                     m_maskEditState=REGION_SELECTING;
00565                     DrawSelectionRectangle();
00566                 }
00567             };
00568             break;
00569         case POINTS_SELECTED:
00570             if(mouse.CmdDown())
00571             {
00572                 // check if mouse clicks happens near one line of active polygon
00573                 unsigned int index=m_editingMask.FindPointNearPos(currentPos, 5*maxSelectionDistance);
00574                 if(index<UINT_MAX)
00575                 {
00576                     m_selectedPoints.clear();
00577                     m_editingMask.insertPoint(index,currentPos);
00578                     m_selectedPoints.insert(index);
00579                     m_maskEditState=POINTS_ADDING;
00580                 };
00581             }
00582             else
00583             {
00584                 HuginBase::UIntSet points;
00585                 if(SelectPointsInsideMouseRect(points,true))
00586                 {
00587                     //selected point clicked, starting moving
00588                     m_maskEditState=POINTS_MOVING;
00589                 }
00590                 else
00591                 {
00592                     //unselected point clicked
00593                     if(SelectPointsInsideMouseRect(points,false))
00594                     {
00595                         //clicked near other point
00596                         if(!mouse.ShiftDown())
00597                             m_selectedPoints.clear();
00598                         for(HuginBase::UIntSet::const_iterator it=points.begin();it!=points.end();++it)
00599                             m_selectedPoints.insert(*it);
00600                         m_maskEditState=POINTS_MOVING;
00601                     }
00602                     else
00603                     {
00604                         m_maskEditState=REGION_SELECTING;
00605                         DrawSelectionRectangle();
00606                     };
00607                 }
00608             };
00609             break;
00610         case CROP_SHOWING:
00611             switch(GetClickPos(vigra::Point2D(currentPos.x,currentPos.y)))
00612             {
00613                 case CLICK_OUTSIDE:
00614                     // clicked outside, do nothing
00615                     break;
00616                 case CLICK_INSIDE:
00617                     if(!m_cropCentered)
00618                     {
00619                         m_maskEditState=CROP_MOVING;
00620                     };
00621                     break;
00622                 case CLICK_LEFT:
00623                     m_maskEditState=CROP_LEFT_MOVING;
00624                     break;
00625                 case CLICK_RIGHT:
00626                     m_maskEditState=CROP_RIGHT_MOVING;
00627                     break;
00628                 case CLICK_TOP:
00629                     m_maskEditState=CROP_TOP_MOVING;
00630                     break;
00631                 case CLICK_BOTTOM:
00632                     m_maskEditState=CROP_BOTTOM_MOVING;
00633                     break;
00634                 case CLICK_CIRCLE:
00635                     m_dragStartPos.x=(m_cropRect.left()+m_cropRect.right())/2;
00636                     m_dragStartPos.y=(m_cropRect.top()+m_cropRect.bottom())/2;
00637                     m_maskEditState=CROP_CIRCLE_SCALING;
00638                     break;
00639             };
00640             if(m_maskEditState!=CROP_SHOWING)
00641             {
00642                 if (m_cropMode == HuginBase::SrcPanoImage::NO_CROP && m_cropCircle)
00643                 {
00644 #if defined SUPPORTS_WXINVERT
00645                     DrawCrop();
00646                     m_cropMode = HuginBase::SrcPanoImage::CROP_CIRCLE;
00647                     DrawCrop();
00648 #else
00649                     m_cropMode=HuginBase::SrcPanoImage::CROP_CIRCLE;
00650                     update();
00651 #endif
00652                 };
00653             };
00654             break;
00655         default:
00656             // otherwise do nothing
00657             break;
00658     };
00659 };
00660 
00661 void MaskImageCtrl::OnLeftMouseUp(wxMouseEvent& mouse)
00662 {
00663     if(m_previewOnly)
00664         return;
00665     DEBUG_DEBUG("LEFT MOUSE UP");
00666     wxPoint mpos;
00667     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00668                            &mpos.x, & mpos.y);
00669     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(mpos));
00670     bool doUpdate=false;
00671     switch(m_maskEditState)
00672     {
00673         case NEW_POLYGON_STARTED:
00674             doUpdate=true;
00675             m_editingMask.addPoint(currentPos);
00676             m_selectedPoints.insert(m_editingMask.getMaskPolygon().size()-1);
00677             m_maskEditState=NEW_POLYGON_CREATING;
00678             break;
00679         case NEW_POLYGON_CREATING:
00680             //next point of polygen selected
00681             doUpdate=true;
00682             m_editingMask.addPoint(currentPos);
00683             m_selectedPoints.insert(m_editingMask.getMaskPolygon().size()-1);
00684             break;
00685         case POINTS_MOVING:
00686             if(HasCapture())
00687                 ReleaseMouse();
00688             {
00689                 hugin_utils::FDiff2D delta=currentPos-applyRotInv(invtransform(m_dragStartPos));
00690                 if(hugin_utils::sqr(delta.x)+hugin_utils::sqr(delta.y)>hugin_utils::sqr(maxSelectionDistance))
00691                 {
00692                     for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00693                         m_imageMask[m_activeMask].movePointBy(*it,delta);
00694                     m_maskEditState=POINTS_SELECTED;
00695                     m_editPanel->UpdateMask();
00696                 }
00697                 else
00698                 {
00699                     m_editingMask=m_imageMask[m_activeMask];
00700                     m_maskEditState=POINTS_SELECTED;
00701                     doUpdate=true;
00702                 };
00703             };
00704             break;
00705         case POLYGON_SELECTING:
00706             if(HasCapture())
00707                 ReleaseMouse();
00708 #if defined SUPPORTS_WXINVERT
00709             DrawSelectionRectangle();
00710 #else
00711             doUpdate=true;
00712 #endif
00713             m_currentPos=mpos;
00714             m_maskEditState=NO_SELECTION;
00715             {
00716                 hugin_utils::FDiff2D p;
00717                 p.x=invtransform(m_dragStartPos.x+(m_currentPos.x-m_dragStartPos.x)/2);
00718                 p.y=invtransform(m_dragStartPos.y+(m_currentPos.y-m_dragStartPos.y)/2);
00719                 p=applyRotInv(p);
00720                 FindPolygon(p);
00721             };
00722             break;
00723         case REGION_SELECTING:
00724             {
00725                 if(HasCapture())
00726                     ReleaseMouse();
00727                 DrawSelectionRectangle();
00728                 m_currentPos=mpos;
00729                 bool selectedPoints=!m_selectedPoints.empty();
00730                 if(!mouse.ShiftDown())
00731                     m_selectedPoints.clear();
00732                 if(SelectPointsInsideMouseRect(m_selectedPoints,false))
00733                 {
00734                     //new points selected
00735                     if(m_selectedPoints.empty())
00736                         m_maskEditState=NO_SELECTION;
00737                     else
00738                         m_maskEditState=POINTS_SELECTED;
00739                 }
00740                 else
00741                 {
00742                     //there were no points selected
00743                     if(!selectedPoints)
00744                     {
00745                         //if there where no points selected before, we searching for an other polygon
00746                         hugin_utils::FDiff2D p;
00747                         p.x=invtransform(m_dragStartPos.x+(m_currentPos.x-m_dragStartPos.x)/2);
00748                         p.y=invtransform(m_dragStartPos.y+(m_currentPos.y-m_dragStartPos.y)/2);
00749                         p=applyRotInv(p);
00750                         FindPolygon(p);
00751                     };
00752                     m_maskEditState=NO_SELECTION;
00753                 };
00754                 doUpdate=true;
00755                 break;
00756             };
00757         case POINTS_ADDING:
00758             if(HasCapture())
00759                 ReleaseMouse();
00760             for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00761                 m_editingMask.movePointTo(*it,currentPos);
00762             m_imageMask[m_activeMask]=m_editingMask;
00763             m_editPanel->UpdateMask();
00764             m_maskEditState=POINTS_SELECTED;
00765             break;
00766         case CROP_MOVING:
00767         case CROP_LEFT_MOVING:
00768         case CROP_RIGHT_MOVING:
00769         case CROP_TOP_MOVING:
00770         case CROP_BOTTOM_MOVING:
00771         case CROP_CIRCLE_SCALING:
00772             if(HasCapture())
00773                 ReleaseMouse();
00774 #if defined SUPPORTS_WXINVERT
00775             DrawCrop();
00776 #else
00777             doUpdate=true;
00778 #endif
00779             UpdateCrop(currentPos);
00780 #if defined SUPPORTS_WXINVERT
00781             DrawCrop();
00782 #endif
00783             m_maskEditState=CROP_SHOWING;
00784             SetCursor(wxNullCursor);
00785             m_editPanel->UpdateCrop(true);
00786             break;
00787         default:
00788             if(HasCapture())
00789                 ReleaseMouse();
00790     };
00791     if(doUpdate)
00792         update();
00793 }
00794 
00795 void MaskImageCtrl::OnLeftMouseDblClick(wxMouseEvent &mouse)
00796 {
00797     if(m_previewOnly)
00798         return;
00799     switch(m_maskEditState)
00800     {
00801         case NEW_POLYGON_STARTED:
00802             {
00803                 m_maskEditState=NO_SELECTION;
00804                 HuginBase::MaskPolygon mask;
00805                 m_editingMask=mask;
00806                 m_selectedPoints.clear();
00807                 MainFrame::Get()->SetStatusText(wxT(""),0);
00808                 break;
00809             };
00810         case NEW_POLYGON_CREATING:
00811             {
00812                 //close newly generated polygon
00813                 m_maskEditState=NO_SELECTION;
00814                 //delete last point otherwise it would be added twice, because we added it
00815                 //already in release left mouse button
00816                 m_editingMask.removePoint(m_editingMask.getMaskPolygon().size()-1);
00817                 if(m_editingMask.getMaskPolygon().size()>2)
00818                 {
00819                     m_imageMask.push_back(m_editingMask);
00820                     m_activeMask=m_imageMask.size()-1;
00821                     m_editPanel->AddMask();
00822                 }
00823                 else
00824                 {
00825                     HuginBase::MaskPolygon mask;
00826                     m_editingMask=mask;
00827                     m_selectedPoints.clear();
00828                     update();
00829                 };
00830                 MainFrame::Get()->SetStatusText(wxT(""),0);
00831                 break;
00832             };
00833         default:
00834             // the other case do nothing here
00835             break;
00836     };
00837 };
00838 
00839 void MaskImageCtrl::OnRightMouseDown(wxMouseEvent& mouse)
00840 {
00841     if(m_previewOnly)
00842         return;
00843     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00844                            &m_dragStartPos.x, & m_dragStartPos.y);
00845     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(m_dragStartPos));
00846     m_currentPos=m_dragStartPos;
00847     if(!HasCapture())
00848         CaptureMouse();
00849     SetFocus();
00850     if(m_maskEditState==NO_SELECTION || m_maskEditState==POINTS_SELECTED)
00851     {
00852         if(mouse.CmdDown())
00853         {
00854             m_maskEditState=POINTS_DELETING;
00855             DrawSelectionRectangle();
00856         }
00857         else
00858         {
00859             if (m_editingMask.isInside(currentPos))
00860             {
00861                 fill_set(m_selectedPoints,0,m_editingMask.getMaskPolygon().size()-1);
00862                 m_maskEditState=POINTS_MOVING;
00863                 update();
00864             };
00865         };
00866     };
00867 };
00868 
00869 void MaskImageCtrl::OnRightMouseUp(wxMouseEvent& mouse)
00870 {
00871     if(m_previewOnly)
00872         return;
00873     wxPoint mpos;
00874     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00875                            &mpos.x, & mpos.y);
00876     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(mpos));
00877     if(HasCapture())
00878         ReleaseMouse();
00879     switch(m_maskEditState)
00880     {
00881         case NEW_POLYGON_STARTED:
00882             {
00883                 m_maskEditState=NO_SELECTION;
00884                 HuginBase::MaskPolygon mask;
00885                 m_editingMask=mask;
00886                 m_selectedPoints.clear();
00887                 MainFrame::Get()->SetStatusText(wxT(""),0);
00888                 break;
00889             };
00890         case NEW_POLYGON_CREATING:
00891             {
00892                 //close newly generated polygon
00893                 m_maskEditState=NO_SELECTION;
00894                 m_editingMask.movePointTo(m_editingMask.getMaskPolygon().size()-1,currentPos);
00895                 if(m_editingMask.getMaskPolygon().size()>2)
00896                 {
00897                     m_imageMask.push_back(m_editingMask);
00898                     m_activeMask=m_imageMask.size()-1;
00899                     m_editPanel->AddMask();
00900                 }
00901                 else
00902                 {
00903                     HuginBase::MaskPolygon mask;
00904                     m_editingMask=mask;
00905                     m_selectedPoints.clear();
00906                     update();
00907                 };
00908                 MainFrame::Get()->SetStatusText(wxT(""),0);
00909                 break;
00910             };
00911         case POINTS_DELETING:
00912             {
00913                 DrawSelectionRectangle();
00914                 HuginBase::UIntSet points;
00915                 m_currentPos=mpos;
00916                 if(SelectPointsInsideMouseRect(points,false))
00917                 {
00918                     if(m_editingMask.getMaskPolygon().size()-points.size()>2)
00919                     {
00920                         // clear all selected points
00921                         for(HuginBase::UIntSet::const_reverse_iterator it=points.rbegin();it!=points.rend();++it)
00922                             m_editingMask.removePoint(*it);
00923                         // now update set of selected points
00924                         if(m_selectedPoints.size()>0)
00925                         {
00926                             std::vector<unsigned int> mappedSelectedPoints(m_imageMask[m_activeMask].getMaskPolygon().size());
00927                             for(unsigned int i=0;i<mappedSelectedPoints.size();i++)
00928                                 mappedSelectedPoints[i]=i;
00929                             HuginBase::UIntSet temp=m_selectedPoints;
00930                             m_selectedPoints.clear();
00931                             for(HuginBase::UIntSet::const_iterator it=points.begin();it!=points.end();++it)
00932                             {
00933                                 if((*it)<mappedSelectedPoints.size()-1)
00934                                     for(unsigned int i=(*it)+1;i<mappedSelectedPoints.size();i++)
00935                                         mappedSelectedPoints[i]--;
00936                             };
00937                             for(HuginBase::UIntSet::const_iterator it=temp.begin();it!=temp.end();++it)
00938                                 if(!set_contains(points,*it))
00939                                     m_selectedPoints.insert(mappedSelectedPoints[*it]);
00940                         };
00941                         //now update the saved mask
00942                         m_imageMask[m_activeMask]=m_editingMask;
00943                         m_editPanel->UpdateMask();
00944                     }
00945                     else
00946                         wxBell();
00947                 };
00948                 if(m_selectedPoints.size()==0)
00949                     m_maskEditState=NO_SELECTION;
00950                 else
00951                     m_maskEditState=POINTS_SELECTED;
00952                 break;
00953             };
00954         case POINTS_MOVING:
00955             {
00956                 hugin_utils::FDiff2D delta=currentPos-applyRotInv(invtransform(m_dragStartPos));
00957                 if(hugin_utils::sqr(delta.x)+hugin_utils::sqr(delta.y)>hugin_utils::sqr(maxSelectionDistance))
00958                 {
00959                     for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00960                         m_imageMask[m_activeMask].movePointBy(*it,delta);
00961                     m_maskEditState=POINTS_SELECTED;
00962                     m_editPanel->UpdateMask();
00963                 }
00964                 else
00965                 {
00966                     m_editingMask=m_imageMask[m_activeMask];
00967                     m_maskEditState=POINTS_SELECTED;
00968                 };
00969                 break;
00970             };
00971         default:
00972             break;
00973     };
00974 };
00975 
00976 void MaskImageCtrl::OnKeyUp(wxKeyEvent &e)
00977 {
00978     int key=e.GetKeyCode();
00979     bool processed=false;
00980     if((key==WXK_DELETE) || (key==WXK_NUMPAD_DELETE))
00981     {
00982         if(m_activeMask<UINT_MAX)
00983         {
00984             if (m_maskEditState == POINTS_SELECTED)
00985             {
00986                 if ((m_selectedPoints.size()>0) && (m_editingMask.getMaskPolygon().size() - m_selectedPoints.size() > 2))
00987                 {
00988                     for (HuginBase::UIntSet::const_reverse_iterator it = m_selectedPoints.rbegin(); it != m_selectedPoints.rend(); ++it)
00989                         m_editingMask.removePoint(*it);
00990                     m_imageMask[m_activeMask] = m_editingMask;
00991                     processed = true;
00992                     m_editPanel->UpdateMask();
00993                 }
00994                 else
00995                 {
00996                     if (m_editingMask.getMaskPolygon().size() == m_selectedPoints.size())
00997                     {
00998                         wxCommandEvent dummy;
00999                         processed = true;
01000                         m_editPanel->OnMaskDelete(dummy);
01001                     }
01002                     else
01003                         wxBell();
01004                 };
01005             }
01006             else
01007             {
01008                 if(m_maskEditState==NO_SELECTION)
01009                 {
01010                     wxCommandEvent dummy;
01011                     processed=true;
01012                     m_editPanel->OnMaskDelete(dummy);
01013                 };
01014             };
01015         };
01016     };
01017     if(!processed)
01018         e.Skip();
01019 };
01020 
01021 void MaskImageCtrl::OnCaptureLost(wxMouseCaptureLostEvent &e)
01022 {
01023     wxFocusEvent dummy;
01024     OnKillFocus(dummy);
01025 };
01026 
01027 void MaskImageCtrl::OnKillFocus(wxFocusEvent &e)
01028 {
01029     if(HasCapture())
01030         ReleaseMouse();
01031     if(m_maskEditState==NEW_POLYGON_CREATING || m_maskEditState==NEW_POLYGON_STARTED)
01032     {
01033         wxBell();
01034         m_maskEditState=NO_SELECTION;
01035         HuginBase::MaskPolygon mask;
01036         m_editingMask=mask;
01037         m_selectedPoints.clear();
01038         update();
01039     };
01040 };
01041 
01042 void MaskImageCtrl::startNewPolygon()
01043 {
01044     m_maskEditState=NEW_POLYGON_STARTED;
01045     HuginBase::MaskPolygon newMask;
01046     m_editingMask=newMask;
01047     m_selectedPoints.clear();
01048 };
01049 
01050 wxSize MaskImageCtrl::DoGetBestSize() const
01051 {
01052     return wxSize(m_imageSize.GetWidth(),m_imageSize.GetHeight());
01053 };
01054 
01055 void MaskImageCtrl::update()
01056 {
01057     wxClientDC dc(this);
01058     PrepareDC(dc);
01059     OnDraw(dc);
01060 };
01061 
01062 void MaskImageCtrl::DrawPolygon(wxDC &dc, HuginBase::MaskPolygon poly, bool isSelected, bool drawMarker)
01063 {
01064     unsigned int nrOfPoints=poly.getMaskPolygon().size();
01065     if (nrOfPoints<2)
01066         return;
01067     wxPoint *polygonPoints=new wxPoint[nrOfPoints];
01068     for(unsigned int j=0;j<nrOfPoints;j++)
01069     {
01070         polygonPoints[j]=transform(applyRot(poly.getMaskPolygon()[j]));
01071     };
01072     if(isSelected)
01073         dc.SetPen(wxPen(m_colour_point_unselected, 1, wxPENSTYLE_SOLID));
01074     else
01075         switch(poly.getMaskType())
01076         {
01077             case HuginBase::MaskPolygon::Mask_negative:
01078             case HuginBase::MaskPolygon::Mask_Stack_negative:
01079             case HuginBase::MaskPolygon::Mask_negative_lens:
01080                 dc.SetPen(wxPen(m_colour_polygon_negative, 1, wxPENSTYLE_SOLID));
01081                 break;
01082             case HuginBase::MaskPolygon::Mask_positive:
01083             case HuginBase::MaskPolygon::Mask_Stack_positive:
01084                 dc.SetPen(wxPen(m_colour_polygon_positive, 1, wxPENSTYLE_SOLID));
01085                  break;
01086         };
01087     dc.SetBrush(*wxTRANSPARENT_BRUSH);
01088     if(nrOfPoints>2)
01089         dc.DrawPolygon(nrOfPoints,polygonPoints);
01090     else
01091         dc.DrawLine(polygonPoints[0],polygonPoints[1]);
01092     if(drawMarker)
01093     {
01094         wxPen penSelected(m_colour_point_selected);
01095         wxPen penUnselected(m_colour_point_unselected);
01096         wxBrush brushSelected(m_colour_point_selected);
01097         wxBrush brushUnselected(m_colour_point_unselected);
01098         for(unsigned int j=0;j<nrOfPoints;j++)
01099         {
01100             if(set_contains(m_selectedPoints,j))
01101             {
01102                 dc.SetPen(penSelected);
01103                 dc.SetBrush(brushSelected);
01104             }
01105             else
01106             {
01107                 dc.SetPen(penUnselected);
01108                 dc.SetBrush(brushUnselected);
01109             };
01110             dc.DrawRectangle(polygonPoints[j].x-polygonPointSize,polygonPoints[j].y-polygonPointSize,
01111                             2*polygonPointSize,2*polygonPointSize);
01112         };
01113     };
01114     delete []polygonPoints;
01115 };
01116 
01117 void MaskImageCtrl::DrawCrop()
01118 {
01119     wxClientDC dc(this);
01120     PrepareDC(dc);
01121     DrawCrop(dc);
01122 };
01123 
01124 void MaskImageCtrl::DrawCrop(wxDC & dc)
01125 {
01126     // draw crop rectangle/circle
01127     if(!m_maskMode)
01128     {
01129         // draw all areas without fillings
01130         dc.SetBrush(*wxTRANSPARENT_BRUSH);
01131 #if defined SUPPORTS_WXINVERT
01132         dc.SetLogicalFunction (wxINVERT);
01133 #else
01134         dc.SetPen(wxPen(m_color_selection, 1, wxPENSTYLE_SOLID));
01135 #endif
01136         wxPoint middle=transform(applyRot((m_cropRect.lowerRight()+m_cropRect.upperLeft())/2));
01137 
01138         int c = 8; // size of midpoint cross
01139         dc.DrawLine( middle.x + c, middle.y + c, middle.x - c, middle.y - c);
01140         dc.DrawLine( middle.x - c, middle.y + c, middle.x + c, middle.y - c);
01141         dc.DrawRectangle(wxRect(transform(applyRot(hugin_utils::FDiff2D(m_cropRect.left(), m_cropRect.top()))),
01142                                 transform(applyRot(hugin_utils::FDiff2D(m_cropRect.right(), m_cropRect.bottom())))));
01143 
01144         // draw crop circle as well, if requested.
01145         if (m_cropMode==HuginBase::BaseSrcPanoImage::CROP_CIRCLE)
01146         {
01147             double radius=std::min<int>(m_cropRect.width(),m_cropRect.height())/2.0;
01148             dc.DrawCircle(middle.x, middle.y, scale(radius));
01149         }
01150     };
01151 };
01152 
01153 void MaskImageCtrl::OnDraw(wxDC & dc)
01154 {
01155     if(m_maskEditState!=NO_IMAGE && m_bitmap.IsOk())
01156     {
01157         int offset=scale(HuginBase::maskOffset);
01158         //draw border around image to allow drawing mask over boudaries of image
01159         //don't draw as one complete rectangle to prevent flickering
01160         dc.SetPen(wxPen(GetBackgroundColour(), 1, wxPENSTYLE_SOLID));
01161         dc.SetBrush(wxBrush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
01162         dc.DrawRectangle(0,0,offset,m_bitmap.GetHeight()+2*offset);
01163         dc.DrawRectangle(0,0,m_bitmap.GetWidth()+2*offset,offset);
01164         dc.DrawRectangle(m_bitmap.GetWidth()+offset,0,m_bitmap.GetWidth()+2*offset,m_bitmap.GetHeight()+2*offset);
01165         dc.DrawRectangle(0,m_bitmap.GetHeight()+offset,m_bitmap.GetWidth()+2*offset,m_bitmap.GetHeight()+2*offset);
01166         dc.DrawBitmap(m_bitmap,offset,offset);
01167         if(m_fitToWindow)
01168         {
01169             //draw border when image is fit to window, otherwise the border (without image) is not updated
01170             wxSize clientSize=GetClientSize();
01171             if(m_bitmap.GetWidth()+2*offset<clientSize.GetWidth())
01172             {
01173                 dc.DrawRectangle(m_bitmap.GetWidth()+2*offset,0,clientSize.GetWidth()-m_bitmap.GetWidth()+2*offset,clientSize.GetHeight());
01174             };
01175             if(m_bitmap.GetHeight()+2*offset<clientSize.GetHeight())
01176             {
01177                 dc.DrawRectangle(0,m_bitmap.GetHeight()+2*offset,clientSize.GetWidth(),clientSize.GetHeight()-m_bitmap.GetHeight()+2*offset);
01178             };
01179         };
01180         if (m_maskMode && m_showActiveMasks && (m_cropMode != HuginBase::SrcPanoImage::NO_CROP || m_masksToDraw.size()>0))
01181         {
01182             //whole image, we need it several times
01183             wxRegion wholeImage(transform(applyRot(hugin_utils::FDiff2D(0,0))),
01184                                 transform(applyRot(hugin_utils::FDiff2D(m_realSize.GetWidth(),m_realSize.GetHeight()))));
01185             wxRegion region;
01186             if (m_cropMode != HuginBase::SrcPanoImage::NO_CROP)
01187             {
01188                 region.Union(wholeImage);
01189                 //now the crop
01190                 switch(m_cropMode)
01191                 {
01192                     case HuginBase::SrcPanoImage::CROP_RECTANGLE:
01193                         region.Subtract(wxRegion(transform(applyRot(m_cropRect.upperLeft())),
01194                             transform(applyRot(m_cropRect.lowerRight()))));
01195                         break;
01196                     case HuginBase::SrcPanoImage::CROP_CIRCLE:
01197                         {
01198                             unsigned int nrOfPoints = dc.GetSize().GetWidth() * 2;
01199                             wxPoint* circlePoints = new wxPoint[nrOfPoints];
01200                             vigra::Point2D middle = (m_cropRect.lowerRight() + m_cropRect.upperLeft()) / 2;
01201                             double radius = std::min<int>(m_cropRect.width(), m_cropRect.height()) / 2;
01202                             double interval = 2 * PI / nrOfPoints;
01203                             for (unsigned int i = 0; i < nrOfPoints; i++)
01204                             {
01205                                 circlePoints[i] = transform(applyRot(hugin_utils::FDiff2D(middle.x + radius*cos(i*interval), middle.y + radius*sin(i*interval))));
01206                             };
01207                             region.Subtract(wxRegion(nrOfPoints, circlePoints));
01208                             delete[]circlePoints;
01209                         }
01210                         break;
01211                     case HuginBase::BaseSrcPanoImage::NO_CROP:
01212                         break;
01213                 };
01214             };
01215             if(m_masksToDraw.size()>0)
01216             {
01217                 for(unsigned int i=0;i<m_masksToDraw.size();i++)
01218                 {
01219                     HuginBase::VectorPolygon poly=m_masksToDraw[i].getMaskPolygon();
01220                     wxPoint *polygonPoints=new wxPoint[poly.size()];
01221                     for(unsigned int j=0;j<poly.size();j++)
01222                     {
01223                         polygonPoints[j]=transform(applyRot(poly[j]));
01224                     };
01225                     wxRegion singleRegion(poly.size(),polygonPoints,wxWINDING_RULE);
01226                     if(m_masksToDraw[i].isInverted())
01227                     {
01228                         wxRegion newRegion(wholeImage);
01229                         newRegion.Subtract(singleRegion);
01230                         region.Union(newRegion);
01231                     }
01232                     else
01233                     {
01234                         region.Union(singleRegion);
01235                     };
01236                     delete []polygonPoints;
01237                 };
01238             };
01239 #ifndef __WXMAC__
01240             // on Windows and GTK we need to compensate to clipping region
01241             // by the scroll offset
01242             // this seems not to be necessary for wxMac
01243             int x;
01244             int y;
01245             GetViewStart(&x,&y);
01246             region.Offset(-x,-y);
01247 #endif
01248             dc.SetDeviceClippingRegion(region);
01249             dc.DrawBitmap(m_disabledBitmap,offset,offset);
01250             dc.DestroyClippingRegion();
01251         };
01252         DrawCrop(dc);
01253         if(m_maskMode && m_imageMask.size()>0)
01254         {
01255             //now draw all polygons
01256             HuginBase::MaskPolygonVector maskList=m_imageMask;
01257             bool drawSelected=(m_maskEditState!=POINTS_ADDING && m_maskEditState!=POINTS_MOVING);
01258             for(unsigned int i=0;i<maskList.size();i++)
01259             {
01260                 if(i!=m_activeMask)
01261                     DrawPolygon(dc,maskList[i],false,false);
01262                 else
01263                     if(drawSelected)
01264                         DrawPolygon(dc,maskList[i],true,true);
01265             };
01266         };
01267         //and now the actual polygon
01268         if(m_maskEditState==POINTS_ADDING || m_maskEditState==POINTS_MOVING || m_maskEditState==NEW_POLYGON_CREATING)
01269             DrawPolygon(dc,m_editingMask,true,true);
01270     }
01271     else
01272     {
01273         // clear the rectangle and exit
01274         dc.SetPen(wxPen(GetBackgroundColour(), 1, wxPENSTYLE_SOLID));
01275         dc.SetBrush(wxBrush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
01276         dc.Clear();
01277         return;
01278     };
01279 }
01280 
01281 void MaskImageCtrl::OnSize(wxSizeEvent &e)
01282 {
01283     DEBUG_TRACE("size: " << e.GetSize().GetWidth() << "x" << e.GetSize().GetHeight());
01284     // rescale m_bitmap if needed.
01285     if (m_imageFilename != "") {
01286         if (m_fitToWindow) {
01287             setScale(0);
01288         }
01289     }
01290 };
01291 
01292 void MaskImageCtrl::OnScroll(wxScrollWinEvent &e)
01293 {
01294     m_oldScrollPosX = GetScrollPos(wxHORIZONTAL);
01295     m_oldScrollPosY = GetScrollPos(wxVERTICAL);
01296     e.Skip();
01297 }
01298 
01299 void MaskImageCtrl::rescaleImage()
01300 {
01301     if (m_maskEditState == NO_IMAGE)
01302     {
01303         return;
01304     }
01305 #ifndef SUPPORTS_WXINVERT
01306     //determine average colour and set selection colour corresponding
01307     vigra::FindAverage<vigra::RGBValue<vigra::UInt8> > average;
01308     vigra::inspectImage(vigra::srcImageRange(*(m_img->get8BitImage())), average);
01309     vigra::RGBValue<vigra::UInt8> RGBaverage=average.average();
01310     if(RGBaverage[0]<180 && RGBaverage[1]<180 && RGBaverage[2]<180)
01311     {
01312         m_color_selection=*wxWHITE;
01313     }
01314     else
01315     {
01316         m_color_selection=*wxBLACK;
01317     };
01318 #endif
01319     wxImage img = imageCacheEntry2wxImage(m_img);
01320     if (img.GetWidth() == 0)
01321     {
01322         return;
01323     }
01324     m_imageSize = wxSize(img.GetWidth(), img.GetHeight());
01325     m_realSize = m_imageSize;
01326     m_imageSize.IncBy(2*HuginBase::maskOffset);
01327     if (m_fitToWindow)
01328         m_scaleFactor = calcAutoScaleFactor(m_imageSize);
01329 
01330     //scaling image to screen size
01331     if (getScaleFactor()!=1.0)
01332     {
01333         m_imageSize.SetWidth(scale(m_imageSize.GetWidth()));
01334         m_imageSize.SetHeight(scale(m_imageSize.GetHeight()));
01335         img=img.Scale(scale(m_realSize.GetWidth()), scale(m_realSize.GetHeight()));
01336     }
01337     else
01338     {
01339         //the conversion to disabled m_bitmap would work on the original cached image file
01340         //therefore we need to create a copy to work on it
01341         img=img.Copy();
01342     };
01343     //and now rotating
01344     switch(m_imgRotation)
01345     {
01346         case ROT90:
01347             img = img.Rotate90(true);
01348             break;
01349         case ROT180:
01350                 // this is slower than it needs to be...
01351             img = img.Rotate90(true);
01352             img = img.Rotate90(true);
01353             break;
01354         case ROT270:
01355             img = img.Rotate90(false);
01356             break;
01357         default:
01358             break;
01359     }
01360     // do color correction only if input image has icc profile or if we found a monitor profile
01361     if (!m_img->iccProfile->empty() || huginApp::Get()->HasMonitorProfile())
01362     {
01363         HuginBase::Color::CorrectImage(img, *(m_img->iccProfile), huginApp::Get()->GetMonitorProfile());
01364     };
01365     m_bitmap=wxBitmap(img);
01366 
01367     //create disabled m_bitmap for drawing active masks
01368     img = img.ConvertToDisabled(192);
01369     m_disabledBitmap=wxBitmap(img);
01370     if (m_imgRotation == ROT90 || m_imgRotation == ROT270)
01371     {
01372         SetVirtualSize(m_imageSize.GetHeight(), m_imageSize.GetWidth());
01373     }
01374     else
01375     {
01376         SetVirtualSize(m_imageSize.GetWidth(), m_imageSize.GetHeight());
01377     };
01378     SetScrollRate(1,1);
01379     Refresh(true);
01380 };
01381 
01382 void MaskImageCtrl::DrawSelectionRectangle()
01383 {
01384     wxClientDC dc(this);
01385     PrepareDC(dc);
01386 #if defined SUPPORTS_WXINVERT
01387     dc.SetLogicalFunction(wxINVERT);
01388     dc.SetPen(wxPen(*wxWHITE, 1, wxPENSTYLE_DOT));
01389 #else
01390     OnDraw(dc);
01391     dc.SetPen(wxPen(m_color_selection, scale(1), wxPENSTYLE_DOT));
01392 #endif
01393     dc.SetBrush(*wxTRANSPARENT_BRUSH);
01394     dc.DrawRectangle(m_dragStartPos.x,m_dragStartPos.y,
01395         (m_currentPos.x-m_dragStartPos.x),(m_currentPos.y-m_dragStartPos.y));
01396 };
01397 
01398 void MaskImageCtrl::FindPolygon(hugin_utils::FDiff2D p)
01399 {
01400     unsigned int selectedPolygon=UINT_MAX;
01401     unsigned int i=0;
01402     while(selectedPolygon==UINT_MAX && i<m_imageMask.size())
01403     {
01404         if(m_imageMask[i].isInside(p))
01405             selectedPolygon=i;
01406         i++;
01407     };
01408     if(selectedPolygon<UINT_MAX)
01409         m_editPanel->SelectMask(selectedPolygon);
01410 };
01411 
01412 bool MaskImageCtrl::SelectPointsInsideMouseRect(HuginBase::UIntSet &points,const bool considerSelectedOnly)
01413 {
01414     bool found=false;
01415     hugin_utils::FDiff2D p1=applyRotInv(invtransform(m_dragStartPos));
01416     hugin_utils::FDiff2D p2=applyRotInv(invtransform(m_currentPos));
01417     double xmin=std::min(p1.x,p2.x)-maxSelectionDistance;
01418     double xmax=std::max(p1.x,p2.x)+maxSelectionDistance;
01419     double ymin=std::min(p1.y,p2.y)-maxSelectionDistance;
01420     double ymax=std::max(p1.y,p2.y)+maxSelectionDistance;
01421     const HuginBase::VectorPolygon poly=m_editingMask.getMaskPolygon();
01422     for(unsigned int i=0;i<poly.size();i++)
01423     {
01424         bool activePoints=true;
01425         if(considerSelectedOnly)
01426             activePoints=set_contains(m_selectedPoints,i);
01427         if(activePoints && xmin<=poly[i].x && poly[i].x<=xmax && ymin<=poly[i].y && poly[i].y<=ymax)
01428         {
01429             points.insert(i);
01430             found=true;
01431         };
01432     };
01433     return found;
01434 };
01435 
01436 void MaskImageCtrl::setScale(double factor)
01437 {
01438     if (factor == 0)
01439     {
01440         m_fitToWindow = true;
01441         factor = calcAutoScaleFactor(m_imageSize);
01442     }
01443     else
01444     {
01445         m_fitToWindow = false;
01446     }
01447     DEBUG_DEBUG("new scale factor:" << factor);
01448     // update if factor changed
01449     if (factor != m_scaleFactor)
01450     {
01451         m_scaleFactor = factor;
01452         // keep existing scale focussed.
01453         rescaleImage();
01454     }
01455 };
01456 
01457 double MaskImageCtrl::calcAutoScaleFactor(wxSize size)
01458 {
01459     int w = size.GetWidth();
01460     int h = size.GetHeight();
01461     if (m_imgRotation ==  ROT90 || m_imgRotation == ROT270)
01462     {
01463         int t = w;
01464         w = h;
01465         h = t;
01466     }
01467 
01468     wxSize csize = GetSize();
01469     DEBUG_DEBUG("csize: " << csize.GetWidth() << "x" << csize.GetHeight() << "image: " << w << "x" << h);
01470     double s1 = (double)csize.GetWidth()/w;
01471     double s2 = (double)csize.GetHeight()/h;
01472     DEBUG_DEBUG("s1: " << s1 << "  s2:" << s2);
01473     return s1 < s2 ? s1 : s2;
01474 };
01475 
01476 double MaskImageCtrl::getScaleFactor() const
01477 {
01478     return m_scaleFactor;
01479 };
01480 
01481 void MaskImageCtrl::setDrawingActiveMasks(bool newDrawActiveMasks)
01482 {
01483     m_showActiveMasks=newDrawActiveMasks;
01484     update();
01485 };
01486 
01487 IMPLEMENT_DYNAMIC_CLASS(MaskImageCtrl, wxScrolledWindow)
01488 
01489 MaskImageCtrlXmlHandler::MaskImageCtrlXmlHandler()
01490                 : wxXmlResourceHandler()
01491 {
01492     AddWindowStyles();
01493 };
01494 
01495 wxObject *MaskImageCtrlXmlHandler::DoCreateResource()
01496 {
01497     XRC_MAKE_INSTANCE(cp, MaskImageCtrl)
01498 
01499     cp->Create(m_parentAsWindow,
01500                    GetID(),
01501                    GetPosition(), GetSize(),
01502                    GetStyle(wxT("style")),
01503                    GetName());
01504 
01505     SetupWindow(cp);
01506 
01507     return cp;
01508 };
01509 
01510 bool MaskImageCtrlXmlHandler::CanHandle(wxXmlNode *node)
01511 {
01512     return IsOfClass(node, wxT("MaskImageCtrl"));
01513 };
01514 
01515 IMPLEMENT_DYNAMIC_CLASS(MaskImageCtrlXmlHandler, wxXmlResourceHandler)

Generated on 9 Dec 2016 for Hugintrunk by  doxygen 1.4.7