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

Generated on Wed Jul 16 01:25:32 2014 for Hugintrunk by  doxygen 1.3.9.1