CPEditorPanel.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00027 #include <config.h>
00028 
00029 // often necessary before panoinc.h
00030 #ifdef __APPLE__
00031 #include "panoinc_WX.h"
00032 #endif
00033 // standard hugin include
00034 #include "panoinc.h"
00035 // both includes above need to come before other wx includes on OSX
00036 
00037 // hugin's
00038 #include "hugin/huginApp.h"
00039 #include "hugin/config_defaults.h"
00040 #include "base_wx/CommandHistory.h"
00041 #include "base_wx/wxImageCache.h"
00042 #include "hugin/CPImageCtrl.h"
00043 #include "hugin/TextKillFocusHandler.h"
00044 #include "hugin/CPEditorPanel.h"
00045 #include "base_wx/wxPanoCommand.h"
00046 #include "base_wx/MyProgressDialog.h"
00047 #include "algorithms/optimizer/PTOptimizer.h"
00048 #include "algorithms/basic/CalculateOptimalScale.h"
00049 #include "base_wx/PTWXDlg.h"
00050 #include "base_wx/wxPlatform.h"
00051 
00052 // more standard includes if needed
00053 #include <algorithm>
00054 #include <float.h>
00055 #include <vector>
00056 
00057 // more vigra include if needed
00058 #include "vigra/cornerdetection.hxx"
00059 #include "vigra/localminmax.hxx"
00060 #include "vigra_ext/openmp_vigra.h"
00061 #include "vigra_ext/Correlation.h"
00062 
00063 // Celeste header
00064 #include "Celeste.h"
00065 
00066 using namespace std;
00067 using namespace HuginBase;
00068 using namespace vigra;
00069 using namespace vigra_ext;
00070 using namespace vigra::functor;
00071 using namespace hugin_utils;
00072 
00073 BEGIN_EVENT_TABLE(CPEditorPanel, wxPanel)
00074     EVT_CPEVENT(CPEditorPanel::OnCPEvent)
00075     EVT_COMBOBOX(XRCID("cp_editor_left_choice"), CPEditorPanel::OnLeftChoiceChange )
00076     EVT_COMBOBOX(XRCID("cp_editor_right_choice"), CPEditorPanel::OnRightChoiceChange )
00077     EVT_LIST_ITEM_SELECTED(XRCID("cp_editor_cp_list"), CPEditorPanel::OnCPListSelect)
00078     EVT_LIST_ITEM_DESELECTED(XRCID("cp_editor_cp_list"), CPEditorPanel::OnCPListDeselect)
00079     EVT_LIST_COL_END_DRAG(XRCID("cp_editor_cp_list"), CPEditorPanel::OnColumnWidthChange)
00080     EVT_CHOICE(XRCID("cp_editor_choice_zoom"), CPEditorPanel::OnZoom)
00081     EVT_TEXT_ENTER(XRCID("cp_editor_x1"), CPEditorPanel::OnTextPointChange )
00082     EVT_TEXT_ENTER(XRCID("cp_editor_y1"), CPEditorPanel::OnTextPointChange )
00083     EVT_TEXT_ENTER(XRCID("cp_editor_x2"), CPEditorPanel::OnTextPointChange )
00084     EVT_TEXT_ENTER(XRCID("cp_editor_y2"), CPEditorPanel::OnTextPointChange )
00085     EVT_CHOICE(XRCID("cp_editor_mode"), CPEditorPanel::OnTextPointChange )
00086     EVT_CHAR(CPEditorPanel::OnKey)
00087     EVT_BUTTON(XRCID("cp_editor_delete"), CPEditorPanel::OnDeleteButton)
00088     EVT_BUTTON(XRCID("cp_editor_add"), CPEditorPanel::OnAddButton)
00089     EVT_BUTTON(XRCID("cp_editor_previous_img"), CPEditorPanel::OnPrevImg)
00090     EVT_BUTTON(XRCID("cp_editor_next_img"), CPEditorPanel::OnNextImg)
00091     EVT_BUTTON(XRCID("cp_editor_finetune_button"), CPEditorPanel::OnFineTuneButton)
00092     EVT_BUTTON(XRCID("cp_editor_action_button"), CPEditorPanel::OnActionButton)
00093     EVT_MENU(XRCID("cp_menu_create_cp"), CPEditorPanel::OnActionSelectCreate)
00094     EVT_MENU(XRCID("cp_menu_celeste"), CPEditorPanel::OnActionSelectCeleste)
00095     EVT_MENU(XRCID("cp_menu_clean_cp"), CPEditorPanel::OnActionSelectCleanCP)
00096 END_EVENT_TABLE()
00097 
00098 CPEditorPanel::CPEditorPanel()
00099 {
00100     DEBUG_TRACE("**********************");
00101     m_pano = 0;
00102     m_countCP = 0;
00103 }
00104 
00105 bool CPEditorPanel::Create(wxWindow* parent, wxWindowID id,
00106                     const wxPoint& pos,
00107                     const wxSize& size,
00108                     long style,
00109                     const wxString& name)
00110 {
00111     DEBUG_TRACE(" Create called *************");
00112     if (! wxPanel::Create(parent, id, pos, size, style, name) ) {
00113         return false;
00114     }
00115 
00116     cpCreationState = NO_POINT;
00117     m_leftImageNr=UINT_MAX;
00118     m_rightImageNr=UINT_MAX;
00119     m_listenToPageChange=true;
00120     m_detailZoomFactor=1;
00121     m_selectedPoint=UINT_MAX;
00122     m_leftRot=CPImageCtrl::ROT0;
00123     m_rightRot=CPImageCtrl::ROT0;
00124 
00125     DEBUG_TRACE("");
00126     wxXmlResource::Get()->LoadPanel(this, wxT("cp_editor_panel"));
00127     wxPanel * panel = XRCCTRL(*this, "cp_editor_panel", wxPanel);
00128 
00129     wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
00130     topsizer->Add(panel, 1, wxEXPAND, 0);
00131 
00132     m_leftChoice = XRCCTRL(*this, "cp_editor_left_choice", CPImagesComboBox); 
00133     m_leftImg = XRCCTRL(*this, "cp_editor_left_img", CPImageCtrl);
00134     assert(m_leftImg);
00135     m_leftImg->Init(this);
00136     m_leftImg->setTransforms(&m_leftTransform, &m_leftInvTransform, &m_rightInvTransform);
00137 
00138     // right image
00139     m_rightChoice = XRCCTRL(*this, "cp_editor_right_choice", CPImagesComboBox);
00140     m_rightImg = XRCCTRL(*this, "cp_editor_right_img", CPImageCtrl);
00141     assert(m_rightImg);
00142     m_rightImg->Init(this);
00143     m_rightImg->setTransforms(&m_rightTransform, &m_rightInvTransform, &m_leftInvTransform);
00144 
00145     // setup list view
00146     m_cpList = XRCCTRL(*this, "cp_editor_cp_list", wxListCtrl);
00147     m_cpList->Connect(wxEVT_CHAR,wxKeyEventHandler(CPEditorPanel::OnKey),NULL,this);
00148     m_cpList->InsertColumn( 0, _("#"), wxLIST_FORMAT_RIGHT, 35);
00149     m_cpList->InsertColumn( 1, _("left x"), wxLIST_FORMAT_RIGHT, 65);
00150     m_cpList->InsertColumn( 2, _("left y"), wxLIST_FORMAT_RIGHT, 65);
00151     m_cpList->InsertColumn( 3, _("right x"), wxLIST_FORMAT_RIGHT, 65);
00152     m_cpList->InsertColumn( 4, _("right y"), wxLIST_FORMAT_RIGHT, 65);
00153     m_cpList->InsertColumn( 5, _("Alignment"), wxLIST_FORMAT_LEFT,110 );
00154     m_cpList->InsertColumn( 6, _("Distance"), wxLIST_FORMAT_RIGHT, 110);
00155 
00156     //get saved width
00157     wxConfigBase* config = wxConfig::Get();
00158     for ( int j=0; j < m_cpList->GetColumnCount() ; j++ )
00159     {
00160         // -1 is auto
00161         int width = config->Read(wxString::Format( wxT("/CPEditorPanel/ColumnWidth%d"), j ), -1);
00162         if(width != -1)
00163             m_cpList->SetColumnWidth(j, width);
00164     }
00165 
00166     // other controls
00167     m_x1Text = XRCCTRL(*this,"cp_editor_x1", wxTextCtrl);
00168     m_x1Text->PushEventHandler(new TextKillFocusHandler(this));
00169     m_y1Text = XRCCTRL(*this,"cp_editor_y1", wxTextCtrl);
00170     m_y1Text->PushEventHandler(new TextKillFocusHandler(this));
00171     m_x2Text = XRCCTRL(*this,"cp_editor_x2", wxTextCtrl);
00172     m_x2Text->PushEventHandler(new TextKillFocusHandler(this));
00173     m_y2Text = XRCCTRL(*this,"cp_editor_y2", wxTextCtrl);
00174     m_y2Text->PushEventHandler(new TextKillFocusHandler(this));
00175 
00176     m_cpModeChoice = XRCCTRL(*this, "cp_editor_mode", wxChoice);
00177     m_addButton = XRCCTRL(*this, "cp_editor_add", wxButton);
00178     m_delButton = XRCCTRL(*this, "cp_editor_delete", wxButton);
00179 
00180     m_autoAddCB = XRCCTRL(*this,"cp_editor_auto_add", wxCheckBox);
00181     DEBUG_ASSERT(m_autoAddCB);
00182     m_fineTuneCB = XRCCTRL(*this,"cp_editor_fine_tune_check",wxCheckBox);
00183     DEBUG_ASSERT(m_fineTuneCB);
00184 
00185     m_estimateCB = XRCCTRL(*this,"cp_editor_auto_estimate", wxCheckBox);
00186     DEBUG_ASSERT(m_estimateCB);
00187 
00188     m_actionButton = XRCCTRL(*this, "cp_editor_action_button", wxButton);
00189     m_actionButton->Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(CPEditorPanel::OnActionContextMenu), NULL, this);
00190     m_cpActionContextMenu = wxXmlResource::Get()->LoadMenu(wxT("cp_menu_action"));
00191     // setup scroll window for the controls under the images
00192     m_cp_ctrls = XRCCTRL(*this, "cp_controls_panel", wxPanel);
00193     DEBUG_ASSERT(m_cp_ctrls);
00194 
00195     m_autoAddCB->SetValue(config->Read(wxT("/CPEditorPanel/autoAdd"),0l) != 0 );
00196     m_fineTuneCB->SetValue(config->Read(wxT("/CPEditorPanel/autoFineTune"),1l) != 0 );
00197     m_estimateCB->SetValue(config->Read(wxT("/CPEditorPanel/autoEstimate"),1l) != 0 );
00198 
00199     // disable controls by default
00200     m_cpModeChoice->Disable();
00201     m_addButton->Disable();
00202     m_delButton->Disable();
00203     m_autoAddCB->Disable();
00204     m_fineTuneCB->Disable();
00205     m_estimateCB->Disable();
00206     XRCCTRL(*this, "cp_editor_finetune_button", wxButton)->Disable();
00207     m_actionButton->Disable();
00208     XRCCTRL(*this, "cp_editor_choice_zoom", wxChoice)->Disable();
00209     XRCCTRL(*this, "cp_editor_previous_img", wxButton)->Disable();
00210     XRCCTRL(*this, "cp_editor_next_img", wxButton)->Disable();
00211     m_leftChoice->Disable();
00212     m_rightChoice->Disable();
00213 
00214     // apply zoom specified in xrc file
00215     wxCommandEvent dummy;
00216     dummy.SetInt(XRCCTRL(*this,"cp_editor_choice_zoom",wxChoice)->GetSelection());
00217     OnZoom(dummy);
00218 
00219     SetSizer( topsizer );
00220     // read last used action setting
00221     m_cpActionButtonMode = static_cast<CPTabActionButtonMode>(config->Read(wxT("/CPEditorPanel/ActionMode"), 1l));
00222     switch (m_cpActionButtonMode)
00223     {
00224         case CPTAB_ACTION_CREATE_CP:
00225             m_cpActionContextMenu->Check(XRCID("cp_menu_create_cp"), true);
00226             {
00227                 wxCommandEvent e;
00228                 OnActionSelectCreate(e);
00229             };
00230             break;
00231         case CPTAB_ACTION_CLEAN_CP:
00232             m_cpActionContextMenu->Check(XRCID("cp_menu_clean_cp"), true);
00233             {
00234                 wxCommandEvent e;
00235                 OnActionSelectCleanCP(e);
00236             };
00237             break;
00238         case CPTAB_ACTION_CELESTE:
00239         default:
00240             m_cpActionContextMenu->Check(XRCID("cp_menu_celeste"), true);
00241             {
00242                 wxCommandEvent e;
00243                 OnActionSelectCeleste(e);
00244             };
00245             break;
00246     };
00247 
00248     return true;
00249 }
00250 
00251 void CPEditorPanel::Init(HuginBase::Panorama * pano)
00252 {
00253     m_pano=pano;
00254     // observe the panorama
00255     m_pano->addObserver(this);
00256 }
00257 
00258 CPEditorPanel::~CPEditorPanel()
00259 {
00260     DEBUG_TRACE("dtor");
00261 
00262     m_x1Text->PopEventHandler(true);
00263     m_y1Text->PopEventHandler(true);
00264     m_x2Text->PopEventHandler(true);
00265     m_y2Text->PopEventHandler(true);
00266 
00267     wxConfigBase::Get()->Write(wxT("/CPEditorPanel/autoAdd"), m_autoAddCB->IsChecked() ? 1 : 0);
00268     wxConfigBase::Get()->Write(wxT("/CPEditorPanel/autoFineTune"), m_fineTuneCB->IsChecked() ? 1 : 0);
00269     wxConfigBase::Get()->Write(wxT("/CPEditorPanel/autoEstimate"), m_estimateCB->IsChecked() ? 1 : 0);
00270 
00271     m_pano->removeObserver(this);
00272     DEBUG_TRACE("dtor end");
00273 }
00274 
00275 void CPEditorPanel::setLeftImage(unsigned int imgNr)
00276 {
00277     DEBUG_TRACE("image " << imgNr);
00278     if (imgNr == UINT_MAX) {
00279         m_leftImg->setImage("", CPImageCtrl::ROT0);
00280         m_leftImageNr = imgNr;
00281         m_leftFile = "";
00282         changeState(NO_POINT);
00283         UpdateDisplay(true);
00284     } else if (m_leftImageNr != imgNr) {
00285         double yaw = const_map_get(m_pano->getImageVariables(imgNr),"y").getValue();
00286         double pitch = const_map_get(m_pano->getImageVariables(imgNr),"p").getValue();
00287         double roll = const_map_get(m_pano->getImageVariables(imgNr),"r").getValue();
00288         m_leftRot = GetRot(yaw, pitch, roll);
00289         m_leftImg->setImage(m_pano->getImage(imgNr).getFilename(), m_leftRot);
00290         m_leftImageNr = imgNr;
00291         if (m_leftChoice->GetSelection() != (int) imgNr) {
00292             m_leftChoice->SetSelection(imgNr);
00293         }
00294         m_rightChoice->SetRefImage(m_pano,m_leftImageNr);
00295         m_rightChoice->Refresh();
00296         m_leftFile = m_pano->getImage(imgNr).getFilename();
00297         changeState(NO_POINT);
00298         UpdateDisplay(true);
00299     }
00300     m_selectedPoint = UINT_MAX;
00301     // FIXME: lets hope that nobody holds references to these images..
00302     ImageCache::getInstance().softFlush();
00303     UpdateTransforms();
00304 }
00305 
00306 
00307 void CPEditorPanel::setRightImage(unsigned int imgNr)
00308 {
00309     DEBUG_TRACE("image " << imgNr);
00310     if (imgNr == UINT_MAX) {
00311         m_rightImg->setImage("", CPImageCtrl::ROT0);
00312         m_rightImageNr = imgNr;
00313         m_rightFile = "";
00314         m_rightRot = CPImageCtrl::ROT0;
00315         changeState(NO_POINT);
00316         UpdateDisplay(true);
00317     } else if (m_rightImageNr != imgNr) {
00318         // set the new image
00319         double yaw = const_map_get(m_pano->getImageVariables(imgNr),"y").getValue();
00320         double pitch = const_map_get(m_pano->getImageVariables(imgNr),"p").getValue();
00321         double roll = const_map_get(m_pano->getImageVariables(imgNr),"r").getValue();
00322         m_rightRot = GetRot(yaw, pitch, roll);
00323         m_rightImg->setImage(m_pano->getImage(imgNr).getFilename(), m_rightRot);
00324         // select tab
00325         m_rightImageNr = imgNr;
00326         if (m_rightChoice->GetSelection() != (int) imgNr) {
00327             m_rightChoice->SetSelection(imgNr);
00328         }
00329         m_leftChoice->SetRefImage(m_pano,m_rightImageNr);
00330         m_leftChoice->Refresh();
00331         m_rightFile = m_pano->getImage(imgNr).getFilename();
00332         // update the rest of the display (new control points etc)
00333         changeState(NO_POINT);
00334         UpdateDisplay(true);
00335     }
00336     m_selectedPoint = UINT_MAX;
00337 
00338     // FIXME: lets hope that nobody holds references to these images..
00339     ImageCache::getInstance().softFlush();
00340     UpdateTransforms();
00341 }
00342 
00343 void CPEditorPanel::UpdateTransforms()
00344 {
00345     if(m_leftImageNr<m_pano->getNrOfImages())
00346     {
00347         m_leftTransform.createTransform(m_pano->getImage(m_leftImageNr), m_pano->getOptions());
00348         m_leftInvTransform.createInvTransform(m_pano->getImage(m_leftImageNr), m_pano->getOptions());
00349     };
00350     if(m_rightImageNr<m_pano->getNrOfImages())
00351     {
00352         m_rightTransform.createTransform(m_pano->getImage(m_rightImageNr), m_pano->getOptions());
00353         m_rightInvTransform.createInvTransform(m_pano->getImage(m_rightImageNr), m_pano->getOptions());
00354     };
00355 };
00356 
00357 void CPEditorPanel::OnCPEvent( CPEvent&  ev)
00358 {
00359     DEBUG_TRACE("");
00360     wxString text;
00361     unsigned int nr = ev.getPointNr();
00362     FDiff2D point = ev.getPoint();
00363     bool left (TRUE);
00364     if (ev.GetEventObject() == m_leftImg) {
00365         left = true;
00366     } else  if (ev.GetEventObject() == m_rightImg){
00367         left = false;
00368     } else {
00369         DEBUG_FATAL("UNKNOWN SOURCE OF CPEvent");
00370     }
00371 
00372     switch (ev.getMode()) {
00373     case CPEvent::NONE:
00374         text = wxT("NONE");
00375         break;
00376     case CPEvent::NEW_POINT_CHANGED:
00377         NewPointChange(ev.getPoint(),left);
00378         break;
00379     case CPEvent::POINT_SELECTED:
00380         // need to reset cpEditState
00381         DEBUG_DEBUG("selected point " << nr);
00382         SelectLocalPoint(nr);
00383         changeState(NO_POINT);
00384         break;
00385     case CPEvent::NEW_LINE_ADDED:
00386         {
00387             float vertBias = getVerticalCPBias();
00388             HuginBase::ControlPoint cp = ev.getControlPoint();
00389             cp.image1Nr=m_leftImageNr;
00390             cp.image2Nr=m_rightImageNr;
00391             bool  hor = abs(cp.x1 - cp.x2) > (abs(cp.y1 - cp.y2) * vertBias);
00392             switch (m_leftRot)
00393             {
00394                 case CPImageCtrl::ROT0:
00395                 case CPImageCtrl::ROT180:
00396                     if (hor)
00397                         cp.mode = HuginBase::ControlPoint::Y;
00398                     else
00399                         cp.mode = HuginBase::ControlPoint::X;
00400                     break;
00401                 default:
00402                     if (hor)
00403                         cp.mode = HuginBase::ControlPoint::X;
00404                     else
00405                         cp.mode = HuginBase::ControlPoint::Y;
00406                     break;
00407             }
00408             changeState(NO_POINT);
00409             // create points
00410             PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::AddCtrlPointCmd(*m_pano, cp));
00411             // select new control Point
00412             unsigned int lPoint = m_pano->getNrOfCtrlPoints()-1;
00413             SelectGlobalPoint(lPoint);
00414             changeState(NO_POINT);
00415             MainFrame::Get()->SetStatusText(_("new control point added"));
00416             m_leftChoice->CalcCPDistance(m_pano);
00417             m_rightChoice->CalcCPDistance(m_pano);
00418             break;
00419         };
00420     case CPEvent::POINT_CHANGED:
00421         {
00422             DEBUG_DEBUG("move point("<< nr << ")");
00423             if (nr >= currentPoints.size()) {
00424                 DEBUG_ERROR("invalid point number while moving point")
00425                 return;
00426             }
00427             HuginBase::ControlPoint cp = ev.getControlPoint();
00428             changeState(NO_POINT);
00429             DEBUG_DEBUG("changing point to: " << cp.x1 << "," << cp.y1
00430                         << "  " << cp.x2 << "," << cp.y2);
00431 
00432             PanoCommand::GlobalCmdHist::getInstance().addCommand(
00433                 new PanoCommand::ChangeCtrlPointCmd(*m_pano, currentPoints[nr].first, cp)
00434                 );
00435 
00436             break;
00437         }
00438     case CPEvent::RIGHT_CLICK:
00439         {
00440             if (cpCreationState == BOTH_POINTS_SELECTED) {
00441                 DEBUG_DEBUG("right click -> adding point");
00442                 CreateNewPoint();
00443             } else {
00444                 DEBUG_DEBUG("right click without two points..");
00445                 changeState(NO_POINT);
00446             }
00447             break;
00448         }
00449     case CPEvent::SCROLLED:
00450         {
00451             wxPoint d(roundi(point.x), roundi(point.y));
00452             d = m_rightImg->MaxScrollDelta(d);
00453             d = m_leftImg->MaxScrollDelta(d);
00454             m_rightImg->ScrollDelta(d);
00455             m_leftImg->ScrollDelta(d);
00456         }
00457         break;
00458     case CPEvent::DELETE_REGION_SELECTED:
00459         {
00460             UIntSet cpToRemove;
00461             if(!currentPoints.empty())
00462             {
00463                 wxRect rect=ev.getRect();
00464                 for(unsigned int i=0;i<currentPoints.size();i++)
00465                 {
00466                     HuginBase::ControlPoint cp = currentPoints[i].second;
00467                     if (cp.mode == HuginBase::ControlPoint::X_Y)
00468                     {
00469                         //checking only normal control points
00470                         if(left)
00471                         {
00472                             if(rect.Contains(roundi(cp.x1),roundi(cp.y1)))
00473                             {
00474                                 cpToRemove.insert(localPNr2GlobalPNr(i));
00475                             };
00476                         }
00477                         else
00478                         {
00479                             if(rect.Contains(roundi(cp.x2),roundi(cp.y2)))
00480                             {
00481                                 cpToRemove.insert(localPNr2GlobalPNr(i));
00482                             };
00483                         };
00484                     };
00485                 };
00486             };
00487             changeState(NO_POINT);
00488             if(cpToRemove.size()>0)
00489             {
00490                 PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::RemoveCtrlPointsCmd(*m_pano, cpToRemove));
00491             };
00492             break;
00493         }
00494     } //end switch
00495     m_leftImg->update();
00496     m_rightImg->update();
00497 }
00498 
00499 
00500 void CPEditorPanel::CreateNewPoint()
00501 {
00502     DEBUG_TRACE("");
00503     FDiff2D p1 = m_leftImg->getNewPoint();
00504     FDiff2D p2 = m_rightImg->getNewPoint();
00505     HuginBase::ControlPoint point;
00506     point.image1Nr = m_leftImageNr;
00507     point.x1 = p1.x;
00508     point.y1 = p1.y;
00509     point.image2Nr = m_rightImageNr;
00510     point.x2 = p2.x;
00511     point.y2 = p2.y;
00512     if (point.image1Nr == point.image2Nr) {
00513         if (m_cpModeChoice->GetSelection()>=3) {
00514             // keep line until user chooses new mode
00515             point.mode = m_cpModeChoice->GetSelection();
00516         } else {
00517             // Most projections will have a bias to creating vertical
00518             // constraints.
00519             float vertBias = getVerticalCPBias();
00520             bool  hor = abs(p1.x - p2.x) > (abs(p1.y - p2.y) * vertBias);
00521             switch (m_leftRot) {
00522                 case CPImageCtrl::ROT0:
00523                 case CPImageCtrl::ROT180:
00524                     if (hor)
00525                         point.mode = HuginBase::ControlPoint::Y;
00526                     else
00527                         point.mode = HuginBase::ControlPoint::X;
00528                     break;
00529                 default:
00530                     if (hor)
00531                         point.mode = HuginBase::ControlPoint::X;
00532                     else
00533                         point.mode = HuginBase::ControlPoint::Y;
00534                     break;
00535             }
00536         }
00537     } else {
00538         point.mode = HuginBase::ControlPoint::X_Y;
00539     }
00540 
00541     changeState(NO_POINT);
00542 
00543     // create points
00544     PanoCommand::GlobalCmdHist::getInstance().addCommand(
00545         new PanoCommand::AddCtrlPointCmd(*m_pano, point)
00546         );
00547 
00548 
00549     // select new control Point
00550     unsigned int lPoint = m_pano->getNrOfCtrlPoints() -1;
00551     SelectGlobalPoint(lPoint);
00552     changeState(NO_POINT);
00553     MainFrame::Get()->SetStatusText(_("new control point added"));
00554     m_leftChoice->CalcCPDistance(m_pano);
00555     m_rightChoice->CalcCPDistance(m_pano);
00556 }
00557 
00558 
00559 const float CPEditorPanel::getVerticalCPBias()
00560 {
00561     HuginBase::PanoramaOptions opts = m_pano->getOptions();
00562     HuginBase::PanoramaOptions::ProjectionFormat projFormat = opts.getProjection();
00563     float bias;
00564     switch (projFormat)
00565     {
00566         case HuginBase::PanoramaOptions::RECTILINEAR:
00567             bias = 1.0;
00568             break;
00569         default:
00570             bias = 2.0;
00571             break;
00572     }
00573     return bias;
00574 }
00575 
00576 
00577 void CPEditorPanel::ClearSelection()
00578 {
00579     if (m_selectedPoint == UINT_MAX) {
00580         // no point selected, no need to select one.
00581         return;
00582     }
00583     m_cpList->SetItemState(m_selectedPoint, 0, wxLIST_STATE_SELECTED);
00584 
00585     m_selectedPoint=UINT_MAX;
00586     changeState(NO_POINT);
00587     m_leftImg->deselect();
00588     m_rightImg->deselect();
00589     UpdateDisplay(false);
00590 }
00591 
00592 void CPEditorPanel::SelectLocalPoint(unsigned int LVpointNr)
00593 {
00594     DEBUG_TRACE("selectLocalPoint(" << LVpointNr << ")");
00595 
00596     if ( m_selectedPoint == LVpointNr) {
00597         DEBUG_DEBUG("already selected");
00598         m_leftImg->selectPoint(LVpointNr);
00599         m_rightImg->selectPoint(LVpointNr);
00600         return;
00601     }
00602     m_selectedPoint = LVpointNr;
00603 
00604     const HuginBase::ControlPoint & p = currentPoints[LVpointNr].second;
00605     m_x1Text->SetValue(wxString::Format(wxT("%.2f"),p.x1));
00606     m_y1Text->SetValue(wxString::Format(wxT("%.2f"),p.y1));
00607     m_x2Text->SetValue(wxString::Format(wxT("%.2f"),p.x2));
00608     m_y2Text->SetValue(wxString::Format(wxT("%.2f"),p.y2));
00609     m_cpModeChoice->SetSelection(p.mode);
00610     m_leftImg->selectPoint(LVpointNr);
00611     m_rightImg->selectPoint(LVpointNr);
00612     m_cpList->SetItemState(LVpointNr, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
00613     m_cpList->EnsureVisible(LVpointNr);
00614 
00615     EnablePointEdit(true);
00616 }
00617 
00618 void CPEditorPanel::SelectGlobalPoint(unsigned int globalNr)
00619 {
00620     unsigned int localNr;
00621     if (globalPNr2LocalPNr(localNr,globalNr)) {
00622         DEBUG_DEBUG("CPEditor::setGlobalPoint(" << globalNr << ") found local point " << localNr);
00623         SelectLocalPoint(localNr);
00624     } else {
00625         DEBUG_ERROR("CPEditor::setGlobalPoint: point " << globalNr << " not found in currentPoints");
00626     }
00627 }
00628 
00629 bool CPEditorPanel::globalPNr2LocalPNr(unsigned int & localNr, unsigned int globalNr) const
00630 {
00631     HuginBase::CPointVector::const_iterator it = currentPoints.begin();
00632 
00633     while(it != currentPoints.end() && (*it).first != globalNr) {
00634         ++it;
00635     }
00636 
00637     if (it != currentPoints.end()) {
00638         localNr = it - currentPoints.begin();
00639         return true;
00640     } else {
00641         return false;
00642     }
00643 }
00644 
00645 unsigned int CPEditorPanel::localPNr2GlobalPNr(unsigned int localNr) const
00646 {
00647     assert(localNr < currentPoints.size());
00648     return currentPoints[localNr].first;
00649 }
00650 
00651 
00652 void CPEditorPanel::estimateAndAddOtherPoint(const FDiff2D & p,
00653                                              bool left,
00654                                              CPImageCtrl * thisImg,
00655                                              unsigned int thisImgNr,
00656                                              CPCreationState THIS_POINT,
00657                                              CPCreationState THIS_POINT_RETRY,
00658                                              CPImageCtrl * otherImg,
00659                                              unsigned int otherImgNr,
00660                                              CPCreationState OTHER_POINT,
00661                                              CPCreationState OTHER_POINT_RETRY)
00662 {
00663     FDiff2D op;
00664     op = EstimatePoint(FDiff2D(p.x, p.y), left);
00665     // check if point is in image.
00666     const SrcPanoImage & pImg = m_pano->getImage(otherImgNr);
00667     if (op.x < (int) pImg.getSize().width() && op.x >= 0
00668         && op.y < (int) pImg.getSize().height() && op.y >= 0)
00669     {
00670         otherImg->setNewPoint(op);
00671         // if fine-tune is checked, run a fine-tune session as well.
00672         // hmm probably there should be another separate function for this..
00673         if (m_fineTuneCB->IsChecked()) {
00674             MainFrame::Get()->SetStatusText(_("searching similar points..."),0);
00675             FDiff2D newPoint = otherImg->getNewPoint();
00676 
00677             long templWidth = wxConfigBase::Get()->Read(wxT("/Finetune/TemplateSize"), HUGIN_FT_TEMPLATE_SIZE);
00678             const SrcPanoImage & img = m_pano->getImage(thisImgNr);
00679             double sAreaPercent = wxConfigBase::Get()->Read(wxT("/Finetune/SearchAreaPercent"),HUGIN_FT_SEARCH_AREA_PERCENT);
00680             int sWidth = std::min((int)(img.getWidth() * sAreaPercent / 100.0), 500);
00681             CorrelationResult corrPoint;
00682             bool corrOk=false;
00683             Diff2D roundp(p.toDiff2D());
00684             try {
00685                 corrOk = PointFineTune(thisImgNr,
00686                                       roundp,
00687                                       templWidth,
00688                                       otherImgNr,
00689                                       newPoint,
00690                                       sWidth,
00691                                       corrPoint);
00692             } catch (std::exception & e) {
00693                 wxMessageBox(wxString (e.what(), wxConvLocal), _("Error during Fine-tune"));
00694             }
00695             if (! corrOk) {
00696                 // just set point, PointFineTune already complained
00697                 if (corrPoint.corrPos.x >= 0 && corrPoint.corrPos.y >= 0 && corrPoint.maxpos.x > 0 && corrPoint.maxpos.y > 0)
00698                 {
00699                     otherImg->setScale(m_detailZoomFactor);
00700                     otherImg->setNewPoint(corrPoint.maxpos);
00701                     thisImg->setNewPoint(corrPoint.corrPos);
00702                     changeState(BOTH_POINTS_SELECTED);
00703                 };
00704             } else {
00705                 // show point & zoom in if auto add is not set
00706                 if (!m_autoAddCB->IsChecked()) {
00707                     otherImg->setScale(m_detailZoomFactor);
00708                     otherImg->setNewPoint(corrPoint.maxpos);
00709                     thisImg->setNewPoint(corrPoint.corrPos);
00710                     changeState(BOTH_POINTS_SELECTED);
00711                     wxString s1;
00712                     s1.Printf(_("Point fine-tuned, angle: %.0f deg, correlation coefficient: %0.3f, curvature: %0.3f %0.3f "),
00713                               corrPoint.maxAngle, corrPoint.maxi, corrPoint.curv.x, corrPoint.curv.y );
00714                     
00715                     wxString s2 = s1 + wxT(" -- ") + wxString(_("change points, or press right mouse button to add the pair"));
00716                     MainFrame::Get()->SetStatusText(s2,0);
00717                 } else {
00718                     // add point
00719                     otherImg->setNewPoint(corrPoint.maxpos);
00720                     thisImg->setNewPoint(corrPoint.corrPos);
00721                     changeState(BOTH_POINTS_SELECTED);
00722                     CreateNewPoint();
00723                 }
00724             }
00725         } else {
00726             // no fine-tune, set 100% scale and set both points to selected
00727             otherImg->setScale(m_detailZoomFactor);
00728             otherImg->showPosition(op);
00729             changeState(BOTH_POINTS_SELECTED);
00730         }
00731 
00732     } else {
00733         // estimate was outside of image
00734         // do nothing special
00735         wxBell();
00736         MainFrame::Get()->SetStatusText(_("Estimated point outside image"),0);
00737     }
00738 }
00739 
00740 void CPEditorPanel::NewPointChange(FDiff2D p, bool left)
00741 {
00742     DEBUG_TRACE("");
00743 
00744     wxString corrMsg;
00745 
00746     CPImageCtrl * thisImg = m_leftImg;
00747     unsigned int thisImgNr = m_leftImageNr;
00748     CPImageCtrl * otherImg = m_rightImg;
00749     unsigned int otherImgNr = m_rightImageNr;
00750     CPCreationState THIS_POINT = LEFT_POINT;
00751     CPCreationState THIS_POINT_RETRY = LEFT_POINT_RETRY;
00752     CPCreationState OTHER_POINT = RIGHT_POINT;
00753     CPCreationState OTHER_POINT_RETRY = RIGHT_POINT_RETRY;
00754 
00755     bool estimate = m_estimateCB->IsChecked();
00756 
00757     if (!left) {
00758         thisImg = m_rightImg;
00759         thisImgNr = m_rightImageNr;
00760         otherImg = m_leftImg;
00761         otherImgNr = m_leftImageNr;
00762         THIS_POINT = RIGHT_POINT;
00763         THIS_POINT_RETRY = RIGHT_POINT_RETRY;
00764         OTHER_POINT = LEFT_POINT;
00765         OTHER_POINT_RETRY = LEFT_POINT_RETRY;
00766     }
00767 
00768 
00769     if (cpCreationState == NO_POINT) {
00770         //case NO_POINT
00771         changeState(THIS_POINT);
00772         // zoom into our window
00773         if (thisImg->getScale() < 1) {
00774             thisImg->setScale(m_detailZoomFactor);
00775             thisImg->showPosition(p);
00776         } else {
00777             // run auto-estimate procedure?
00778             bool hasNormalCP = false;
00779             for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end() && !hasNormalCP; ++it)
00780             {
00781                 hasNormalCP = (it->second.mode == HuginBase::ControlPoint::X_Y);
00782             };
00783             if (estimate && (thisImgNr != otherImgNr) && hasNormalCP) {
00784                 estimateAndAddOtherPoint(p, left,
00785                                          thisImg, thisImgNr, THIS_POINT, THIS_POINT_RETRY,
00786                                          otherImg, otherImgNr, OTHER_POINT, OTHER_POINT_RETRY);
00787             };
00788         }
00789 
00790     } else if (cpCreationState == OTHER_POINT_RETRY) {
00791         thisImg->showPosition(p);
00792     } else if (cpCreationState == THIS_POINT) {
00793         thisImg->showPosition(p);
00794 
00795         bool hasNormalCP = false;
00796         for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end() && !hasNormalCP; ++it)
00797         {
00798             hasNormalCP = (it->second.mode == HuginBase::ControlPoint::X_Y);
00799         };
00800         if (estimate && (thisImgNr != otherImgNr) && hasNormalCP) {
00801             estimateAndAddOtherPoint(p, left,
00802                                      thisImg, thisImgNr, THIS_POINT, THIS_POINT_RETRY,
00803                                      otherImg, otherImgNr, OTHER_POINT, OTHER_POINT_RETRY);
00804         }
00805     } else if (cpCreationState == OTHER_POINT || cpCreationState == THIS_POINT_RETRY) {
00806         // the try for the second point.
00807         if (cpCreationState == OTHER_POINT) {
00808             // other point already selected, finalize point.
00809 
00810             // TODO: option to ignore the auto fine tune button when multiple images are selected.
00811             if (m_fineTuneCB->IsChecked() ) {
00812                 CorrelationResult corrRes;
00813 
00814                 FDiff2D newPoint = otherImg->getNewPoint();
00815 
00816                 long templWidth = wxConfigBase::Get()->Read(wxT("/Finetune/TemplateSize"),HUGIN_FT_TEMPLATE_SIZE);
00817                 const SrcPanoImage & img = m_pano->getImage(thisImgNr);
00818                 double sAreaPercent = wxConfigBase::Get()->Read(wxT("/Finetune/SearchAreaPercent"),
00819                                                                 HUGIN_FT_SEARCH_AREA_PERCENT);
00820                 int sWidth = std::min((int) (img.getWidth() * sAreaPercent / 100.0), 500);
00821                 bool corrOk = false;
00822                 // corr point
00823                 Diff2D newPoint_round = newPoint.toDiff2D();
00824                 try {
00825                     corrOk = PointFineTune(otherImgNr,
00826                                            newPoint_round,
00827                                            templWidth,
00828                                            thisImgNr,
00829                                            p,
00830                                            sWidth,
00831                                            corrRes);
00832                 } catch (std::exception & e) {
00833                     wxMessageBox(wxString (e.what(), wxConvLocal), _("Error during Fine-tune"));
00834                 }
00835 
00836                 if (! corrOk) {
00837                     // low xcorr
00838                     // zoom to 100 percent. & set second stage
00839                     // to abandon finetune this time.
00840                     if (corrRes.corrPos.x >= 0 && corrRes.corrPos.y >= 0 && corrRes.maxpos.x >= 0 && corrRes.maxpos.y >= 0)
00841                     {
00842                         thisImg->setScale(m_detailZoomFactor);
00843                         thisImg->setNewPoint(corrRes.maxpos);
00844                         thisImg->update();
00845                         otherImg->setNewPoint(corrRes.corrPos);
00846                         changeState(BOTH_POINTS_SELECTED);
00847                     };
00848                 } else {
00849                     // show point & zoom in if auto add is not set
00850                     changeState(BOTH_POINTS_SELECTED);
00851                     if (!m_autoAddCB->IsChecked()) {
00852                         thisImg->setScale(m_detailZoomFactor);
00853                     }
00854                     thisImg->setNewPoint(corrRes.maxpos);
00855                     otherImg->setNewPoint(corrRes.corrPos);
00856                     wxString s1;
00857                     s1.Printf(_("Point fine-tuned, angle: %.0f deg, correlation coefficient: %0.3f, curvature: %0.3f %0.3f "),
00858                               corrRes.maxAngle, corrRes.maxi, corrRes.curv.x, corrRes.curv.y );
00859                     
00860                     corrMsg = s1 + wxT(" -- ") +  wxString(_("change points, or press right mouse button to add the pair"));
00861                     MainFrame::Get()->SetStatusText(corrMsg,0);
00862                     
00863                 }
00864             } else {
00865                 // no finetune. but zoom into picture, when we where zoomed out
00866                 if (thisImg->getScale() < 1) {
00867                     // zoom to 100 percent. & set second stage
00868                     // to abandon finetune this time.
00869                     thisImg->setScale(m_detailZoomFactor);
00870                     thisImg->clearNewPoint();
00871                     thisImg->showPosition(p);
00872                     //thisImg->setNewPoint(p.x, p.y);
00873                     changeState(THIS_POINT_RETRY);
00874                     return;
00875                 } else {
00876                     // point is already set. no need to move.
00877                     // setNewPoint(p);
00878                     changeState(BOTH_POINTS_SELECTED);
00879                 }
00880             }
00881         } else {
00882             // selection retry
00883             // nothing special, no second stage fine-tune yet.
00884         }
00885 
00886         // ok, we have determined the other point.. apply if auto add is on
00887         if (m_autoAddCB->IsChecked()) {
00888             CreateNewPoint();
00889         } else {
00890             // keep both point floating around, until they are
00891             // added with a right mouse click or the add button
00892             changeState(BOTH_POINTS_SELECTED);
00893             if (corrMsg != wxT("")) {
00894                 MainFrame::Get()->SetStatusText(corrMsg,0);
00895             }
00896         }
00897 
00898     } else if (cpCreationState == BOTH_POINTS_SELECTED) {
00899         // nothing to do.. maybe a special fine-tune with
00900         // a small search region
00901 
00902     } else {
00903         // should never reach this, else state machine is broken.
00904         DEBUG_ASSERT(0);
00905     }
00906 }
00907 
00908 // return a SrcPanoImage so that the given point is in the center
00909 SrcPanoImage GetImageRotatedTo(const SrcPanoImage& img, const vigra::Diff2D& point, int testWidth, double& neededHFOV)
00910 {
00911     // copy only necessary information into temporary SrcPanoImage
00912     SrcPanoImage imgMod;
00913     imgMod.setSize(img.getSize());
00914     imgMod.setProjection(img.getProjection());
00915     imgMod.setHFOV(img.getHFOV());
00916     // calculate, where the interest point lies
00917     HuginBase::PanoramaOptions opt;
00918     opt.setProjection(HuginBase::PanoramaOptions::EQUIRECTANGULAR);
00919     opt.setHFOV(360);
00920     opt.setWidth(360);
00921     opt.setHeight(180);
00922 
00923     HuginBase::PTools::Transform transform;
00924     transform.createInvTransform(imgMod, opt);
00925     double x1, y1;
00926     if (!transform.transformImgCoord(x1, y1, point.x, point.y))
00927     {
00928         neededHFOV = -1;
00929         return imgMod;
00930     }
00931     // equirect image coordinates -> equirectangular coordinates
00932     // transformImgCoord places the origin at the upper left corner and negate
00933     Matrix3 rotY;
00934     rotY.SetRotationPT(DEG_TO_RAD(180 - (x1 + 0.5)), 0, 0);
00935     Matrix3 rotP;
00936     rotP.SetRotationPT(0, DEG_TO_RAD((y1 + 0.5) - 90), 0);
00937     double y, p, r;
00938     // calculate the necessary rotation angles and remember
00939     Matrix3 rot = rotP * rotY;
00940     rot.GetRotationPT(y, p, r);
00941     imgMod.setYaw(RAD_TO_DEG(y));
00942     imgMod.setPitch(RAD_TO_DEG(p));
00943     imgMod.setRoll(RAD_TO_DEG(r));
00944 
00945     // new we calculate the needed HFOV for template/search area width
00946     double x2, y2;
00947     // check a point left from our interest point
00948     if (transform.transformImgCoord(x2, y2, point.x - testWidth / 2.0, point.y))
00949     {
00950         if (x2 < x1)
00951         {
00952             neededHFOV = 2.0 * (x1 - x2);
00953         }
00954         else
00955         {
00956             // we crossed the 360 deg border
00957             neededHFOV = 2.0 * (360 - x2 + x1);
00958         };
00959         // limit maximum HFOV for remapping to stereographic projection done as next step
00960         if (neededHFOV > 90)
00961         {
00962             neededHFOV = 90;
00963         };
00964         return imgMod;
00965     };
00966     // this goes wrong, maybe the tested point is outside the image area of a fisheye image
00967     // now test the right point
00968     if (transform.transformImgCoord(x2, y2, point.x + testWidth / 2.0, point.y))
00969     {
00970         if (x1 < x2)
00971         {
00972             neededHFOV = 2.0 * (x2 - x1);
00973         }
00974         else
00975         {
00976             // we crossed the 360 deg border
00977             neededHFOV = 2.0 * (360 + x2 - x1);
00978         };
00979         // limit maximum HFOV for remapping to stereographic projection done as next step
00980         if (neededHFOV > 90)
00981         {
00982             neededHFOV = 90;
00983         };
00984         return imgMod;
00985     };
00986     // we can't calculate the needed HFOV, return -1
00987     neededHFOV = -1;
00988     return imgMod;
00989 };
00990 
00991 CorrelationResult PointFineTuneProjectionAware(const SrcPanoImage& templ, const vigra::UInt8RGBImage& templImg,
00992     vigra::Diff2D templPos, int templSize,
00993     const SrcPanoImage& search, const vigra::UInt8RGBImage& searchImg,
00994     vigra::Diff2D searchPos, int sWidth)
00995 {
00996     wxBusyCursor busy;
00997     // read settings
00998     wxConfigBase *cfg = wxConfigBase::Get();
00999     bool rotatingFinetune = cfg->Read(wxT("/Finetune/RotationSearch"), HUGIN_FT_ROTATION_SEARCH) == 1;
01000     double startAngle = HUGIN_FT_ROTATION_START_ANGLE;
01001     cfg->Read(wxT("/Finetune/RotationStartAngle"), &startAngle, HUGIN_FT_ROTATION_START_ANGLE);
01002     startAngle = DEG_TO_RAD(startAngle);
01003     double stopAngle = HUGIN_FT_ROTATION_STOP_ANGLE;
01004     cfg->Read(wxT("/Finetune/RotationStopAngle"), &stopAngle, HUGIN_FT_ROTATION_STOP_ANGLE);
01005     stopAngle = DEG_TO_RAD(stopAngle);
01006     int nSteps = cfg->Read(wxT("/Finetune/RotationSteps"), HUGIN_FT_ROTATION_STEPS);
01007     // if both images have the same projection and the angle does not differ to much use normal point fine-tune
01008     if (templ.getProjection() == search.getProjection()
01009         && templ.getHFOV() < 65 && search.getHFOV() < 65
01010         && fabs(templ.getHFOV() - search.getHFOV()) < 5)
01011     {
01012         CorrelationResult res;
01013         if (rotatingFinetune)
01014         {
01015             res = vigra_ext::PointFineTuneRotSearch(templImg, templPos, templSize,
01016                 searchImg, searchPos, sWidth, startAngle, stopAngle, nSteps);
01017         }
01018         else
01019         {
01020             res = vigra_ext::PointFineTune(templImg, vigra::RGBToGrayAccessor<RGBValue<UInt8> >(), templPos, templSize,
01021                 searchImg, vigra::RGBToGrayAccessor<RGBValue<UInt8> >(), searchPos, sWidth);
01022         };
01023         res.corrPos = templPos;
01024         return res;
01025     };
01026     // images have different projections or the HFOV is different
01027     // so we reproject the image to stereographic projection and fine tune point there
01028     // rotate image so that interest point is in the center
01029     double templHFOV = 0;
01030     double searchHFOV = 0;
01031     SrcPanoImage templMod = GetImageRotatedTo(templ, templPos, templSize, templHFOV);
01032     SrcPanoImage searchMod = GetImageRotatedTo(search, searchPos, sWidth + templSize + 5, searchHFOV);
01033     CorrelationResult res;
01034     res.maxpos = FDiff2D(-1, -1);
01035     res.corrPos = FDiff2D(-1, -1);
01036     if (templHFOV < 0 || searchHFOV < 0)
01037     {
01038         //something went wrong, e.g. image outside of projection circle for fisheye lenses
01039         return res;
01040     }
01041     // populate PanoramaOptions
01042     HuginBase::PanoramaOptions opts;
01043     opts.setProjection(HuginBase::PanoramaOptions::STEREOGRAPHIC);
01044     opts.setHFOV(std::max(templHFOV, searchHFOV));
01045     // calculate a sensible scale factor
01046     double scaleTempl = HuginBase::CalculateOptimalScale::calcOptimalPanoScale(templMod, opts);
01047     double scaleSearch = HuginBase::CalculateOptimalScale::calcOptimalPanoScale(searchMod, opts);
01048     opts.setWidth(std::max<unsigned int>(opts.getWidth()*std::min(scaleTempl, scaleSearch), 3 * templSize));
01049     opts.setHeight(opts.getWidth());
01050     // transform coordinates to transform system
01051     HuginBase::PTools::Transform transform;
01052     transform.createInvTransform(templMod, opts);
01053     double templX, templY, searchX, searchY;
01054     transform.transformImgCoord(templX, templY, templPos.x, templPos.y);
01055     transform.createInvTransform(searchMod, opts);
01056     transform.transformImgCoord(searchX, searchY, searchPos.x, searchPos.y);
01057     // now transform the images
01058     vigra_ext::PassThroughFunctor<vigra::UInt8> ptf;
01059     AppBase::DummyProgressDisplay dummy;
01060     transform.createTransform(searchMod, opts);
01061     vigra::UInt8RGBImage searchImgMod(opts.getSize());
01062     vigra::BImage alpha(opts.getSize());
01063     vigra_ext::transformImage(srcImageRange(searchImg), destImageRange(searchImgMod), destImage(alpha),
01064         vigra::Diff2D(0, 0), transform, ptf, false, vigra_ext::INTERP_CUBIC, &dummy);
01065     // now remap template, we need to remap a little bigger area to have enough information when the template
01066     // is rotated in PointFineTuneRotSearch
01067     Diff2D templPointInt(hugin_utils::roundi(templX), hugin_utils::roundi(templY));
01068     vigra::Rect2D rect(templPointInt.x - templSize - 2, templPointInt.y - templSize - 2,
01069         templPointInt.x + templSize + 2, templPointInt.y + templSize + 2);
01070     rect &= vigra::Rect2D(opts.getSize());
01071     transform.createTransform(templMod, opts);
01072     vigra::UInt8RGBImage templImgMod(opts.getSize());
01073     vigra_ext::transformImage(srcImageRange(templImg), destImageRange(templImgMod, rect), destImage(alpha),
01074         vigra::Diff2D(rect.left(), rect.top()), transform, ptf, false, vigra_ext::INTERP_CUBIC, &dummy);
01075 #if defined DEBUG_EXPORT_FINE_TUNE_REMAPPING
01076     {
01077         vigra::ImageExportInfo templExport("template_remapped.tif");
01078         vigra::exportImage(srcImageRange(templImgMod), templExport.setPixelType("UINT8"));
01079         vigra::ImageExportInfo searchExport("search_remapped.tif");
01080         vigra::exportImage(srcImageRange(searchImgMod), searchExport.setPixelType("UINT8"));
01081     }
01082 #endif
01083     // now we can finetune the point in stereographic projection
01084     // we are always using the rotate fine-tune algorithm, because for this case
01085     // often a rotation is involved
01086     res = vigra_ext::PointFineTuneRotSearch(templImgMod, templPointInt, templSize,
01087         searchImgMod, Diff2D(hugin_utils::roundi(searchX), hugin_utils::roundi(searchY)), sWidth, startAngle, stopAngle, nSteps);
01088     // we transfer also the new found template position back to the original image
01089     transform.createTransform(templMod, opts);
01090     transform.transformImgCoord(res.corrPos.x, res.corrPos.y, templPointInt.x + 0.00001, templPointInt.y + 0.00001);
01091     // we need to move the finetune point back to position in original image
01092     transform.createTransform(searchMod, opts);
01093     transform.transformImgCoord(res.maxpos.x, res.maxpos.y, res.maxpos.x, res.maxpos.y);
01094     return res;
01095 };
01096 
01097 bool CPEditorPanel::PointFineTune(unsigned int tmplImgNr,
01098                                   const Diff2D & tmplPoint,
01099                                   int templSize,
01100                                   unsigned int subjImgNr,
01101                                   const FDiff2D & o_subjPoint,
01102                                   int sWidth,
01103                                   CorrelationResult & res)
01104 {
01105     DEBUG_TRACE("tmpl img nr: " << tmplImgNr << " corr src: "
01106                 << subjImgNr);
01107 
01108     MainFrame::Get()->SetStatusText(_("searching similar points..."),0);
01109 
01110     double corrThresh=HUGIN_FT_CORR_THRESHOLD;
01111     wxConfigBase::Get()->Read(wxT("/Finetune/CorrThreshold"),&corrThresh,
01112                               HUGIN_FT_CORR_THRESHOLD);
01113 
01114     double curvThresh = HUGIN_FT_CURV_THRESHOLD;
01115     wxConfigBase::Get()->Read(wxT("/Finetune/CurvThreshold"),&curvThresh,
01116                               HUGIN_FT_CURV_THRESHOLD);
01117 
01118     // fixme: just cutout suitable gray 
01119     ImageCache::ImageCacheRGB8Ptr subjImg = ImageCache::getInstance().getImage(m_pano->getImage(subjImgNr).getFilename())->get8BitImage();
01120     ImageCache::ImageCacheRGB8Ptr tmplImg = ImageCache::getInstance().getImage(m_pano->getImage(tmplImgNr).getFilename())->get8BitImage();
01121 
01122     res = PointFineTuneProjectionAware(m_pano->getImage(tmplImgNr), *(tmplImg), tmplPoint, templSize,
01123         m_pano->getImage(subjImgNr), *(subjImg), o_subjPoint.toDiff2D(), sWidth);
01124 
01125     // invert curvature. we always assume its a maxima, the curvature there is negative
01126     // however, we allow the user to specify a positive threshold, so we need to
01127     // invert it
01128     res.curv.x = - res.curv.x;
01129     res.curv.y = - res.curv.y;
01130 
01131     MainFrame::Get()->SetStatusText(wxString::Format(_("Point fine-tuned, angle: %.0f deg, correlation coefficient: %0.3f, curvature: %0.3f %0.3f "),
01132                                     res.maxAngle, res.maxi, res.curv.x, res.curv.y ),0);
01133     if (res.corrPos.x < 0 || res.corrPos.y < 0 || res.maxpos.x < 0 || res.maxpos.y < 0)
01134     {
01135         // invalid transformation in fine tune
01136 #if wxCHECK_VERSION(2, 9, 0)
01137         wxMessageDialog dlg(this,
01138             _("No similar point found."),
01139 #ifdef _WINDOWS
01140             _("Hugin"),
01141 #else
01142             wxT(""),
01143 #endif
01144             wxICON_ERROR | wxOK);
01145         dlg.SetExtendedMessage(_("An internal transformation went wrong.\nCheck that the point is inside the image."));
01146         dlg.ShowModal();
01147 #else
01148         wxMessageBox(_("An internal transformation went wrong.\nCheck that the point is inside the image."),
01149 #ifdef _WINDOWS
01150             _("Hugin"),
01151 #else
01152             wxT(""),
01153 #endif
01154             wxICON_ERROR | wxOK, this);
01155 #endif
01156         return false;
01157     }
01158     if (res.maxi < corrThresh || res.curv.x < curvThresh || res.curv.y < curvThresh )
01159     {
01160         // Bad correlation result.
01161 #if wxCHECK_VERSION(2, 9, 0)
01162         wxMessageDialog dlg(this,
01163             _("No similar point found."),
01164 #ifdef _WINDOWS
01165             _("Hugin"),
01166 #else
01167             wxT(""),
01168 #endif
01169             wxICON_ERROR | wxOK);
01170         dlg.SetExtendedMessage(wxString::Format(_("Check the similarity visually.\nCorrelation coefficient (%.3f) is lower than the threshold set in the preferences."),
01171                              res.maxi));
01172         dlg.ShowModal();
01173 #else
01174         wxMessageBox(
01175             wxString::Format(_("No similar point found. Check the similarity visually.\nCorrelation coefficient (%.3f) is lower than the threshold set in the preferences."),
01176                              res.maxi),
01177 #ifdef _WINDOWS
01178             _("Hugin"),
01179 #else
01180             wxT(""),
01181 #endif
01182             wxICON_ERROR | wxOK, this);
01183 #endif
01184         return false;
01185     }
01186 
01187     return true;
01188 }
01189 
01190 void CPEditorPanel::panoramaChanged(Panorama &pano)
01191 {
01192     int nGui = m_cpModeChoice->GetCount();
01193     int nPano = pano.getNextCPTypeLineNumber()+1;
01194     DEBUG_DEBUG("mode choice: " << nGui << " entries, required: " << nPano);
01195 
01196     if (nGui > nPano)
01197     {
01198         m_cpModeChoice->Freeze();
01199         // remove some items.
01200         for (int i = nGui-1; i >=nPano-1; --i) {
01201             m_cpModeChoice->Delete(i);
01202         }
01203         if (nPano > 3) {
01204             m_cpModeChoice->SetString(nPano-1, _("Add new Line"));
01205         }
01206         m_cpModeChoice->Thaw();
01207     } else if (nGui < nPano) {
01208         m_cpModeChoice->Freeze();
01209         if (nGui > 3) {
01210             m_cpModeChoice->SetString(nGui-1, wxString::Format(_("Line %d"), nGui-1));
01211         }
01212         for (int i = nGui; i < nPano-1; i++) {
01213             m_cpModeChoice->Append(wxString::Format(_("Line %d"), i));
01214         }
01215         m_cpModeChoice->Append(_("Add new Line"));
01216         m_cpModeChoice->Thaw();
01217     }
01218     UpdateTransforms();
01219     // check if number of control points has changed, if so we need to update our variables
01220     if (pano.getNrOfCtrlPoints() != m_countCP)
01221     {
01222         m_countCP = pano.getNrOfCtrlPoints();
01223         UpdateDisplay(false);
01224     };
01225     DEBUG_TRACE("");
01226 }
01227 
01228 void CPEditorPanel::panoramaImagesChanged(Panorama &pano, const UIntSet &changed)
01229 {
01230     unsigned int nrImages = pano.getNrOfImages();
01231     unsigned int nrTabs = m_leftChoice->GetCount();
01232     DEBUG_TRACE("nrImages:" << nrImages << " nrTabs:" << nrTabs);
01233 
01234 #ifdef __WXMSW__
01235     int oldLeftSelection = m_leftChoice->GetSelection();
01236     int oldRightSelection = m_rightChoice->GetSelection();
01237 #endif
01238 
01239     if (nrImages == 0)
01240     {
01241         // disable controls
01242         m_cpModeChoice->Disable();
01243         m_addButton->Disable();
01244         m_delButton->Disable();
01245         m_autoAddCB->Disable();
01246         m_fineTuneCB->Disable();
01247         m_estimateCB->Disable();
01248         XRCCTRL(*this, "cp_editor_finetune_button", wxButton)->Disable();
01249         m_actionButton->Disable();
01250         XRCCTRL(*this, "cp_editor_choice_zoom", wxChoice)->Disable();
01251         XRCCTRL(*this, "cp_editor_previous_img", wxButton)->Disable();
01252         XRCCTRL(*this, "cp_editor_next_img", wxButton)->Disable();
01253         m_leftChoice->Disable();
01254         m_rightChoice->Disable();
01255     }
01256     else
01257     {
01258         // enable controls
01259         m_cpModeChoice->Enable();
01260         m_autoAddCB->Enable();
01261         m_fineTuneCB->Enable();
01262         m_estimateCB->Enable();
01263         XRCCTRL(*this, "cp_editor_finetune_button", wxButton)->Enable();
01264         m_actionButton->Enable();
01265         XRCCTRL(*this, "cp_editor_choice_zoom", wxChoice)->Enable();
01266         XRCCTRL(*this, "cp_editor_previous_img", wxButton)->Enable();
01267         XRCCTRL(*this, "cp_editor_next_img", wxButton)->Enable();
01268         m_leftChoice->Enable();
01269         m_rightChoice->Enable();
01270 
01271         ImageCache::getInstance().softFlush();
01272 
01273         for (unsigned int i=0; i < ((nrTabs < nrImages)? nrTabs: nrImages); i++) {
01274             wxFileName fileName(wxString (pano.getImage(i).getFilename().c_str(), HUGIN_CONV_FILENAME));
01275             m_leftChoice->SetString(i, wxString::Format(wxT("%d"), i) + wxT(". - ") + fileName.GetFullName());
01276             m_rightChoice->SetString(i, wxString::Format(wxT("%d"), i) + wxT(". - ") + fileName.GetFullName());
01277         }
01278         // wxChoice on windows looses the selection when setting new labels. Restore selection
01279 #ifdef __WXMSW__
01280         m_leftChoice->SetSelection(oldLeftSelection);
01281         m_rightChoice->SetSelection(oldRightSelection);
01282 #endif
01283         // add tab bar entries, if needed
01284         if (nrTabs < nrImages)
01285         {
01286             for (unsigned int i=nrTabs; i < nrImages; i++)
01287             {
01288                 wxFileName fileName(wxString (pano.getImage(i).getFilename().c_str(), HUGIN_CONV_FILENAME));
01289                 m_leftChoice->Append(wxString::Format(wxT("%d"), i) + wxT(". - ") + fileName.GetFullName());
01290                 m_rightChoice->Append(wxString::Format(wxT("%d"), i) + wxT(". - ") + fileName.GetFullName());
01291             }
01292         }
01293     }
01294     if (nrTabs > nrImages)
01295     {
01296         // remove tab bar entries if needed
01297         // we have to disable listening to notebook selection events,
01298         // else we might update to a noexisting image
01299         m_listenToPageChange = false;
01300         for (int i=nrTabs-1; i >= (int)nrImages; i--) {
01301             m_leftChoice->Delete(i);
01302             m_rightChoice->Delete(i);
01303         }
01304         m_listenToPageChange = true;
01305         if (nrImages > 0) {
01306             // select some other image if we deleted the current image
01307             if (m_leftImageNr >= nrImages) {
01308                 setLeftImage(nrImages -1);
01309             }
01310             if (m_rightImageNr >= nrImages) {
01311                 setRightImage(nrImages -1);
01312             }
01313         } else {
01314             DEBUG_DEBUG("setting no images");
01315             m_leftImageNr = UINT_MAX;
01316             m_leftFile = "";
01317             m_rightImageNr = UINT_MAX;
01318             m_rightFile = "";
01319             // no image anymore..
01320             m_leftImg->setImage(m_leftFile, CPImageCtrl::ROT0);
01321             m_rightImg->setImage(m_rightFile, CPImageCtrl::ROT0);
01322         }
01323     }
01324 
01325     // update changed images
01326     bool update(false);
01327     for(UIntSet::const_iterator it = changed.begin(); it != changed.end(); ++it) {
01328         unsigned int imgNr = *it;
01329         // we only need to update the view if the currently
01330         // selected images were changed.
01331         // changing the images via the tabbar will always
01332         // take the current state directly from the pano
01333         // object
01334         DEBUG_DEBUG("image changed "<< imgNr);
01335         double yaw = const_map_get(m_pano->getImageVariables(imgNr), "y").getValue();
01336         double pitch = const_map_get(m_pano->getImageVariables(imgNr), "p").getValue();
01337         double roll = const_map_get(m_pano->getImageVariables(imgNr), "r").getValue();
01338         CPImageCtrl::ImageRotation rot = GetRot(yaw, pitch, roll);
01339         if (m_leftImageNr == imgNr) {
01340             DEBUG_DEBUG("left image dirty "<< imgNr);
01341             if (m_leftFile != pano.getImage(imgNr).getFilename()
01342                 || m_leftRot != rot ) 
01343             {
01344                 m_leftRot = rot;
01345                 m_leftFile = pano.getImage(imgNr).getFilename();
01346                 m_leftImg->setImage(m_leftFile, m_leftRot);
01347             }
01348             update=true;
01349         }
01350 
01351         if (m_rightImageNr == imgNr) {
01352             DEBUG_DEBUG("right image dirty "<< imgNr);
01353             if (m_rightFile != pano.getImage(imgNr).getFilename()
01354                  || m_rightRot != rot ) 
01355             {
01356                 m_rightRot = rot;
01357                 m_rightFile = pano.getImage(imgNr).getFilename();
01358                 m_rightImg->setImage(m_rightFile, m_rightRot);
01359             }
01360             update=true;
01361         }
01362     }
01363     // check if number of control points has changed, if so we need to update our variables
01364     if (pano.getNrOfCtrlPoints() != m_countCP)
01365     {
01366         m_countCP = pano.getNrOfCtrlPoints();
01367         update = true;
01368     };
01369 
01370     // if there is no selection, select the first one.
01371     if (m_rightImageNr == UINT_MAX && nrImages > 0) {
01372         setRightImage(0);
01373     }
01374     if (m_leftImageNr == UINT_MAX && nrImages > 0) {
01375         setLeftImage(0);
01376     }
01377 
01378     if (update || nrImages == 0) {
01379         UpdateDisplay(false);
01380     }
01381     m_leftChoice->CalcCPDistance(m_pano);
01382     m_rightChoice->CalcCPDistance(m_pano);
01383 }
01384 
01385 void CPEditorPanel::UpdateDisplay(bool newPair)
01386 {
01387     DEBUG_DEBUG("")
01388     int fI = m_leftChoice->GetSelection();
01389     int sI = m_rightChoice->GetSelection();
01390 
01391     // valid selection and already set left image
01392     if (fI >= 0 && m_leftImageNr != UINT_MAX)
01393     {
01394         // set image number to selection
01395         m_leftImageNr = (unsigned int) fI;
01396     }
01397     // valid selection and already set right image
01398     if (sI >= 0 && m_rightImageNr != UINT_MAX)
01399     {
01400         // set image number to selection
01401         m_rightImageNr = (unsigned int) sI;
01402     }
01403     // reset selection
01404     m_x1Text->Clear();
01405     m_y1Text->Clear();
01406     m_x2Text->Clear();
01407     m_y2Text->Clear();
01408     if (m_cpModeChoice->GetSelection() < 3) {
01409         m_cpModeChoice->SetSelection(0);
01410     }
01411 
01412     m_leftImg->setSameImage(m_leftImageNr==m_rightImageNr);
01413     m_rightImg->setSameImage(m_leftImageNr==m_rightImageNr);
01414 
01415     // update control points
01416     const HuginBase::CPVector & controlPoints = m_pano->getCtrlPoints();
01417     currentPoints.clear();
01418     mirroredPoints.clear();
01419 
01420     // create a list of all control points
01421     HuginBase::CPVector::size_type i = 0;
01422     m_leftImg->clearCtrlPointList();
01423     m_rightImg->clearCtrlPointList();
01424     for (HuginBase::CPVector::size_type index = 0; index < controlPoints.size(); ++index)
01425     {
01426         HuginBase::ControlPoint point(controlPoints[index]);
01427         if ((point.image1Nr == m_leftImageNr) && (point.image2Nr == m_rightImageNr)){
01428             m_leftImg->setCtrlPoint(point, false);
01429             m_rightImg->setCtrlPoint(point, true);
01430             currentPoints.push_back(make_pair(index, point));
01431             i++;
01432         } else if ((point.image2Nr == m_leftImageNr) && (point.image1Nr == m_rightImageNr)){
01433             m_leftImg->setCtrlPoint(point, true);
01434             m_rightImg->setCtrlPoint(point, false);
01435             point.mirror();
01436             mirroredPoints.insert(i);
01437             currentPoints.push_back(std::make_pair(index, point));
01438             i++;
01439         }
01440     }
01441     m_leftImg->update();
01442     m_rightImg->update();
01443 
01444     // put these control points into our listview.
01445     unsigned int selectedCP = UINT_MAX;
01446     for ( int i=0; i < m_cpList->GetItemCount() ; i++ ) {
01447       if ( m_cpList->GetItemState( i, wxLIST_STATE_SELECTED ) ) {
01448         selectedCP = i;            // remembers the old selection
01449       }
01450     }
01451     m_cpList->Freeze();
01452     m_cpList->DeleteAllItems();
01453 
01454     for (unsigned int i=0; i < currentPoints.size(); ++i) {
01455         const HuginBase::ControlPoint & p(currentPoints[i].second);
01456         DEBUG_DEBUG("inserting LVItem " << i);
01457         m_cpList->InsertItem(i,wxString::Format(wxT("%d"),i));
01458         m_cpList->SetItem(i,1,wxString::Format(wxT("%.2f"),p.x1));
01459         m_cpList->SetItem(i,2,wxString::Format(wxT("%.2f"),p.y1));
01460         m_cpList->SetItem(i,3,wxString::Format(wxT("%.2f"),p.x2));
01461         m_cpList->SetItem(i,4,wxString::Format(wxT("%.2f"),p.y2));
01462         wxString mode;
01463         switch (p.mode) {
01464         case HuginBase::ControlPoint::X_Y:
01465             mode = _("normal");
01466             break;
01467         case HuginBase::ControlPoint::X:
01468             mode = _("vert. Line");
01469             break;
01470         case HuginBase::ControlPoint::Y:
01471             mode = _("horiz. Line");
01472             break;
01473         default:
01474             mode = wxString::Format(_("Line %d"), p.mode);
01475             break;
01476         }
01477         m_cpList->SetItem(i,5,mode);
01478         m_cpList->SetItem(i,6,wxString::Format(wxT("%.2f"),p.error));
01479     }
01480 
01481     if ( selectedCP < (unsigned int) m_cpList->GetItemCount() && ! newPair) {
01482         // sets an old selection again, only if the images have not changed
01483         m_cpList->SetItemState( selectedCP,
01484                                 wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
01485         m_cpList->EnsureVisible(selectedCP);
01486         m_selectedPoint = selectedCP;
01487         EnablePointEdit(true);
01488 
01489         const HuginBase::ControlPoint & p = currentPoints[m_selectedPoint].second;
01490         m_x1Text->SetValue(wxString::Format(wxT("%.2f"),p.x1));
01491         m_y1Text->SetValue(wxString::Format(wxT("%.2f"),p.y1));
01492         m_x2Text->SetValue(wxString::Format(wxT("%.2f"),p.x2));
01493         m_y2Text->SetValue(wxString::Format(wxT("%.2f"),p.y2));
01494         m_cpModeChoice->SetSelection(p.mode);
01495         m_leftImg->selectPoint(m_selectedPoint);
01496         m_rightImg->selectPoint(m_selectedPoint);
01497 
01498     } else {
01499         m_selectedPoint = UINT_MAX;
01500         EnablePointEdit(false);
01501     }
01502 
01503     for ( int j=0; j < m_cpList->GetColumnCount() ; j++ )
01504     {
01505         //get saved width
01506         // -1 is auto
01507         int width = wxConfigBase::Get()->Read(wxString::Format( wxT("/CPEditorPanel/ColumnWidth%d"), j ), -1);
01508         if(width != -1)
01509             m_cpList->SetColumnWidth(j, width);
01510     }
01511 
01512     m_cpList->Thaw();
01513 }
01514 
01515 void CPEditorPanel::EnablePointEdit(bool state)
01516 {
01517     m_delButton->Enable(state);
01518     XRCCTRL(*this, "cp_editor_finetune_button", wxButton)->Enable(state);
01519     m_x1Text->Enable(state);
01520     m_y1Text->Enable(state);
01521     m_x2Text->Enable(state);
01522     m_y2Text->Enable(state);
01523     m_cpModeChoice->Enable(state);
01524 }
01525 
01526 void CPEditorPanel::OnTextPointChange(wxCommandEvent &e)
01527 {
01528     DEBUG_TRACE("");
01529     // find selected point
01530     long item = -1;
01531     item = m_cpList->GetNextItem(item,
01532                                  wxLIST_NEXT_ALL,
01533                                  wxLIST_STATE_SELECTED);
01534     // no selected item.
01535     if (item == -1) {
01536         return;
01537     }
01538     unsigned int nr = (unsigned int) item;
01539     assert(nr < currentPoints.size());
01540     HuginBase::ControlPoint cp = currentPoints[nr].second;
01541 
01542     // update point state
01543     double oldValue=cp.x1;
01544     bool valid_input=str2double(m_x1Text->GetValue(), cp.x1);
01545     if(valid_input)
01546         valid_input=(cp.x1>=0) && (cp.x1<=m_pano->getSrcImage(cp.image1Nr).getWidth());
01547     if (!valid_input) {
01548         m_x1Text->Clear();
01549         *m_x1Text << oldValue;
01550         return;
01551     }
01552     oldValue=cp.y1;
01553     valid_input=str2double(m_y1Text->GetValue(), cp.y1);
01554     if(valid_input)
01555         valid_input=(cp.y1>=0) && (cp.y1<=m_pano->getSrcImage(cp.image1Nr).getHeight());
01556     if (!valid_input) {
01557         m_y1Text->Clear();
01558         *m_y1Text << oldValue;
01559         return;
01560     }
01561     oldValue=cp.x2;
01562     valid_input=str2double(m_x2Text->GetValue(), cp.x2);
01563     if(valid_input)
01564         valid_input=(cp.x2>=0) && (cp.x2<=m_pano->getSrcImage(cp.image2Nr).getWidth());
01565     if (!valid_input) {
01566         m_x2Text->Clear();
01567         *m_x2Text << oldValue;
01568         return;
01569     }
01570     oldValue=cp.y2;
01571     valid_input=str2double(m_y2Text->GetValue(), cp.y2);
01572     if(valid_input)
01573         valid_input=(cp.y2>=0) && (cp.y2<=m_pano->getSrcImage(cp.image1Nr).getHeight());
01574     if (!valid_input) {
01575         m_y2Text->Clear();
01576         *m_y2Text << oldValue;
01577         return;
01578     }
01579 
01580     cp.mode = m_cpModeChoice->GetSelection();
01581     // if point was mirrored, reverse before setting it.
01582     if (set_contains(mirroredPoints, nr)) {
01583         cp.mirror();
01584     }
01585     PanoCommand::GlobalCmdHist::getInstance().addCommand(
01586         new PanoCommand::ChangeCtrlPointCmd(*m_pano, currentPoints[nr].first, cp)
01587         );
01588 
01589 }
01590 
01591 void CPEditorPanel::OnLeftChoiceChange(wxCommandEvent & e)
01592 {
01593     DEBUG_TRACE("OnLeftChoiceChange() to " << e.GetSelection());
01594     if (m_listenToPageChange && e.GetSelection() >= 0) {
01595         setLeftImage((unsigned int) e.GetSelection());
01596     }
01597 }
01598 
01599 void CPEditorPanel::OnRightChoiceChange(wxCommandEvent & e)
01600 {
01601     DEBUG_TRACE("OnRightChoiceChange() to " << e.GetSelection());
01602     if (m_listenToPageChange && e.GetSelection() >= 0) {
01603         setRightImage((unsigned int) e.GetSelection());
01604     }
01605 }
01606 void CPEditorPanel::OnCPListSelect(wxListEvent & ev)
01607 {
01608     int t = ev.GetIndex();
01609     DEBUG_TRACE("selected: " << t);
01610     if (t >=0) {
01611         SelectLocalPoint((unsigned int) t);
01612         changeState(NO_POINT);
01613     }
01614     EnablePointEdit(true);
01615 }
01616 
01617 void CPEditorPanel::OnCPListDeselect(wxListEvent & ev)
01618 {
01619     // disable controls
01620     // when doing changes to this procedure do also check
01621     // interaction with control point table
01622     // e.g. m_selectedPoint=UINT_MAX will result in a endless loop and crash
01623     changeState(NO_POINT);
01624     EnablePointEdit(false);
01625     m_leftImg->deselect();
01626     m_rightImg->deselect();
01627 }
01628 
01629 void CPEditorPanel::OnZoom(wxCommandEvent & e)
01630 {
01631     double factor;
01632     switch (e.GetSelection()) {
01633     case 0:
01634         factor = 1;
01635         m_detailZoomFactor = factor;
01636         break;
01637     case 1:
01638         // fit to window
01639         factor = 0;
01640         break;
01641     case 2:
01642         factor = 2;
01643         m_detailZoomFactor = factor;
01644         break;
01645     case 3:
01646         factor = 1.5;
01647         m_detailZoomFactor = factor;
01648         break;
01649     case 4:
01650         factor = 0.75;
01651         break;
01652     case 5:
01653         factor = 0.5;
01654         break;
01655     case 6:
01656         factor = 0.25;
01657         break;
01658     default:
01659         DEBUG_ERROR("unknown scale factor");
01660         factor = 1;
01661     }
01662     m_leftImg->setScale(factor);
01663     m_rightImg->setScale(factor);
01664     // if a point is selected, keep it in view
01665     if (m_selectedPoint < UINT_MAX) {
01666         SelectLocalPoint(m_selectedPoint);
01667     }
01668 }
01669 
01670 void CPEditorPanel::OnKey(wxKeyEvent & e)
01671 {
01672     DEBUG_DEBUG("key " << e.GetKeyCode()
01673                 << " origin: id:" << e.GetId() << " obj: "
01674                 << e.GetEventObject());
01675 
01676     if (e.m_keyCode == WXK_DELETE){
01677         DEBUG_DEBUG("Delete pressed");
01678         // remove working points..
01679         if (cpCreationState != NO_POINT) {
01680             changeState(NO_POINT);
01681         } else {
01682             // remove selected point
01683             // find selected point
01684             long item = -1;
01685             item = m_cpList->GetNextItem(item,
01686                                          wxLIST_NEXT_ALL,
01687                                          wxLIST_STATE_SELECTED);
01688             // no selected item.
01689             if (item == -1) {
01690                 wxBell();
01691                 return;
01692             }
01693             unsigned int pNr = localPNr2GlobalPNr((unsigned int) item);
01694             DEBUG_DEBUG("about to delete point " << pNr);
01695             PanoCommand::GlobalCmdHist::getInstance().addCommand(
01696                 new PanoCommand::RemoveCtrlPointCmd(*m_pano,pNr)
01697                 );
01698         }
01699     } else if (e.m_keyCode == '0') {
01700         wxCommandEvent dummy;
01701         dummy.SetInt(1);
01702         OnZoom(dummy);
01703         XRCCTRL(*this,"cp_editor_choice_zoom",wxChoice)->SetSelection(1);
01704     } else if (e.m_keyCode == '1') {
01705         wxCommandEvent dummy;
01706         dummy.SetInt(0);
01707         OnZoom(dummy);
01708         XRCCTRL(*this,"cp_editor_choice_zoom",wxChoice)->SetSelection(0);
01709     } else if (e.m_keyCode == '2') {
01710         wxCommandEvent dummy;
01711         dummy.SetInt(2);
01712         OnZoom(dummy);
01713         XRCCTRL(*this,"cp_editor_choice_zoom",wxChoice)->SetSelection(2);
01714     } else if (e.CmdDown() && e.GetKeyCode() == WXK_LEFT) {
01715         // move to previous
01716         wxCommandEvent dummy;
01717         OnPrevImg(dummy);
01718     } else if (e.CmdDown() && e.GetKeyCode() == WXK_RIGHT) {
01719         // move to next
01720         wxCommandEvent dummy;
01721         OnNextImg(dummy);
01722     } else if (e.GetKeyCode() == 'f') {
01723         bool left =  e.GetEventObject() == m_leftImg;
01724         if (cpCreationState == NO_POINT) {
01725             FineTuneSelectedPoint(left);
01726         } else if (cpCreationState == BOTH_POINTS_SELECTED) { 
01727             FineTuneNewPoint(left);
01728         }
01729     } else if (e.GetKeyCode() == 'g') {
01730         // generate keypoints
01731         long th = wxGetNumberFromUser(_("Create control points.\nTo create less points,\nenter a higher number."), _("Corner Detection threshold"), _("Create control points"), 400, 0, 32000);
01732         if (th == -1) {
01733             return;
01734         }
01735         long scale = wxGetNumberFromUser(_("Create control points"), _("Corner Detection scale"), _("Create control points"), 2);
01736         if (scale == -1) {
01737             return;
01738         }
01739 
01740         try {
01741             wxBusyCursor busy;
01742             DEBUG_DEBUG("corner threshold: " << th << "  scale: " << scale);
01743             PanoCommand::GlobalCmdHist::getInstance().addCommand(
01744                 new PanoCommand::wxAddCtrlPointGridCmd(*m_pano, m_leftImageNr, m_rightImageNr, scale, th)
01745                             );
01746         } catch (std::exception & e) {
01747             wxLogError(_("Error during control point creation:\n") + wxString(e.what(), wxConvLocal));
01748         }
01749     } else {
01750         e.Skip();
01751     }
01752 }
01753 
01754 void CPEditorPanel::OnAddButton(wxCommandEvent & e)
01755 {
01756     // check if the point can be created..
01757     if (cpCreationState == BOTH_POINTS_SELECTED) {
01758         CreateNewPoint();
01759     }
01760 }
01761 
01762 void CPEditorPanel::OnDeleteButton(wxCommandEvent & e)
01763 {
01764     DEBUG_TRACE("");
01765     // check if a point has been selected, but not added.
01766     if (cpCreationState != NO_POINT) {
01767         changeState(NO_POINT);
01768     } else {
01769         // find selected point
01770         long item = -1;
01771         item = m_cpList->GetNextItem(item,
01772                                      wxLIST_NEXT_ALL,
01773                                      wxLIST_STATE_SELECTED);
01774         // no selected item.
01775         if (item == -1) {
01776             wxBell();
01777             return;
01778         }
01779         // get the global point number
01780         unsigned int pNr = localPNr2GlobalPNr((unsigned int) item);
01781 
01782         PanoCommand::GlobalCmdHist::getInstance().addCommand(
01783             new PanoCommand::RemoveCtrlPointCmd(*m_pano,pNr )
01784             );
01785         m_leftChoice->CalcCPDistance(m_pano);
01786         m_rightChoice->CalcCPDistance(m_pano);
01787     }
01788 }
01789 
01790 // show a global control point
01791 void CPEditorPanel::ShowControlPoint(unsigned int cpNr)
01792 {
01793     const HuginBase::ControlPoint & p = m_pano->getCtrlPoint(cpNr);
01794     setLeftImage(p.image1Nr);
01795     setRightImage(p.image2Nr);
01796     // FIXME reset display state
01797     changeState(NO_POINT);
01798 
01799     SelectGlobalPoint(cpNr);
01800 }
01801 
01802 void CPEditorPanel::changeState(CPCreationState newState)
01803 {
01804     DEBUG_TRACE(cpCreationState << " --> " << newState);
01805     // handle global state changes.
01806     bool fineTune = m_fineTuneCB->IsChecked() && (m_leftImageNr != m_rightImageNr);
01807     switch(newState) {
01808     case NO_POINT:
01809         // disable all drawing search boxes.
01810         m_leftImg->showSearchArea(false);
01811         m_rightImg->showSearchArea(false);
01812         // but draw template size, if fine-tune enabled
01813         m_leftImg->showTemplateArea(fineTune);
01814         m_rightImg->showTemplateArea(fineTune);
01815         m_addButton->Enable(false);
01816         if (m_selectedPoint < UINT_MAX) {
01817             m_delButton->Enable(true);
01818         } else {
01819             m_delButton->Enable(false);
01820         }
01821         if (cpCreationState != NO_POINT) {
01822             // reset zoom to previous setting
01823             wxCommandEvent tmpEvt;
01824             tmpEvt.SetInt(XRCCTRL(*this,"cp_editor_choice_zoom",wxChoice)->GetSelection());
01825             OnZoom(tmpEvt);
01826             m_leftImg->clearNewPoint();
01827             m_rightImg->clearNewPoint();
01828         }
01829         break;
01830     case LEFT_POINT:
01831         // disable search area on left window
01832         m_leftImg->showSearchArea(false);
01833         // show search area on right window
01834         m_rightImg->showSearchArea(fineTune);
01835 
01836         // show template area
01837         m_leftImg->showTemplateArea(fineTune);
01838         m_rightImg->showTemplateArea(false);
01839 
01840         // unselect point
01841         ClearSelection();
01842         m_addButton->Enable(false);
01843         m_delButton->Enable(false);
01844         MainFrame::Get()->SetStatusText(_("Select point in right image"),0);
01845         break;
01846     case RIGHT_POINT:
01847         m_leftImg->showSearchArea(fineTune);
01848         m_rightImg->showSearchArea(false);
01849 
01850         m_leftImg->showTemplateArea(false);
01851         m_rightImg->showTemplateArea(fineTune);
01852 
01853         ClearSelection();
01854         m_addButton->Enable(false);
01855         m_delButton->Enable(false);
01856         MainFrame::Get()->SetStatusText(_("Select point in left image"),0);
01857         break;
01858     case LEFT_POINT_RETRY:
01859     case RIGHT_POINT_RETRY:
01860         m_leftImg->showSearchArea(false);
01861         m_rightImg->showSearchArea(false);
01862         // but draw template size, if fine-tune enabled
01863         m_leftImg->showTemplateArea(false);
01864         m_rightImg->showTemplateArea(false);
01865         m_addButton->Enable(false);
01866         m_delButton->Enable(false);
01867         break;
01868     case BOTH_POINTS_SELECTED:
01869         m_leftImg->showTemplateArea(false);
01870         m_rightImg->showTemplateArea(false);
01871         m_leftImg->showSearchArea(false);
01872         m_rightImg->showSearchArea(false);
01873         m_addButton->Enable(true);
01874         m_delButton->Enable(false);
01875     }
01876     // apply the change
01877     cpCreationState = newState;
01878 }
01879 
01880 void CPEditorPanel::OnPrevImg(wxCommandEvent & e)
01881 {
01882     if (m_pano->getNrOfImages() < 2) return;
01883     int nImgs = m_pano->getNrOfImages();
01884     int left = m_leftImageNr -1;
01885     int right = m_rightImageNr -1;
01886     if (left < 0) {
01887         left += nImgs;
01888     } else if (left >= nImgs) {
01889         left -= nImgs;
01890     }
01891 
01892     if (right < 0) {
01893         right += nImgs;
01894     } else if (right >= nImgs) {
01895         right -= nImgs;
01896     }
01897     setLeftImage((unsigned int) left);
01898     setRightImage((unsigned int) right);
01899 }
01900 
01901 void CPEditorPanel::OnNextImg(wxCommandEvent & e)
01902 {
01903     if (m_pano->getNrOfImages() < 2) return;
01904     int nImgs = m_pano->getNrOfImages();
01905     int left = m_leftImageNr + 1;
01906     int right = m_rightImageNr + 1;
01907     if (left < 0) {
01908         left += nImgs;
01909     } else if (left >= nImgs) {
01910         left -= nImgs;
01911     }
01912 
01913     if (right < 0) {
01914         right += nImgs;
01915     } else if (right >= nImgs) {
01916         right -= nImgs;
01917     }
01918     setLeftImage((unsigned int) left);
01919     setRightImage((unsigned int) right);
01920 }
01921 
01922 void CPEditorPanel::OnFineTuneButton(wxCommandEvent & e)
01923 {
01924     if (cpCreationState == NO_POINT) {
01925         FineTuneSelectedPoint(false);
01926     } else if (cpCreationState == BOTH_POINTS_SELECTED) {
01927         FineTuneNewPoint(false);
01928     }
01929 }
01930 
01931 void CPEditorPanel::OnActionContextMenu(wxContextMenuEvent& e)
01932 {
01933     m_cpActionContextMenu->SetLabel(XRCID("cp_menu_create_cp"), wxString::Format(_("Create cp (Current setting: %s)"), MainFrame::Get()->GetSelectedCPGenerator().c_str()));
01934     PopupMenu(m_cpActionContextMenu);
01935 };
01936 
01937 void CPEditorPanel::OnActionButton(wxCommandEvent& e)
01938 {
01939     switch (m_cpActionButtonMode)
01940     {
01941         case CPTAB_ACTION_CREATE_CP:
01942             OnCreateCPButton(e);
01943             break;
01944         case CPTAB_ACTION_CLEAN_CP:
01945             OnCleanCPButton(e);
01946             break;
01947         case CPTAB_ACTION_CELESTE:
01948         default:
01949             OnCelesteButton(e);
01950             break;
01951     };
01952 };
01953 
01954 void CPEditorPanel::OnCreateCPButton(wxCommandEvent& e)
01955 {
01956     if (m_leftImageNr == m_rightImageNr)
01957     {
01958         // when the same image is selected left and right we are running linefind 
01959         // with default parameters
01960         CPDetectorSetting linefindSetting;
01961 #ifdef __WXMSW__
01962         linefindSetting.SetProg(wxT("linefind.exe"));
01963 #else
01964         linefindSetting.SetProg(wxT("linefind"));
01965 #endif
01966         linefindSetting.SetArgs(wxT("-o %o %s"));
01967         HuginBase::UIntSet imgs;
01968         imgs.insert(m_leftImageNr);
01969         MainFrame::Get()->RunCPGenerator(linefindSetting, imgs);
01970     }
01971     else
01972     {
01973         HuginBase::UIntSet imgs;
01974         imgs.insert(m_leftImageNr);
01975         imgs.insert(m_rightImageNr);
01976         MainFrame::Get()->RunCPGenerator(imgs);
01977     };
01978 };
01979 
01980 void CPEditorPanel::OnCelesteButton(wxCommandEvent & e)
01981 {
01982     if (currentPoints.empty())
01983     {
01984         wxMessageBox(_("Cannot run celeste without at least one control point connecting the two images"),_("Error"));
01985         cout << "Cannot run celeste without at least one control point connecting the two images" << endl;
01986     }
01987     else
01988     {
01989         ProgressReporterDialog progress(4, _("Running Celeste"), _("Running Celeste"), this);
01990         progress.updateDisplayValue(_("Loading model file"));
01991 
01992         struct celeste::svm_model* model=MainFrame::Get()->GetSVMModel();
01993         if(model==NULL)
01994         {
01995             return;
01996         };
01997 
01998         // Get Celeste parameters
01999         wxConfigBase *cfg = wxConfigBase::Get();
02000         // SVM threshold
02001         double threshold = HUGIN_CELESTE_THRESHOLD;
02002         cfg->Read(wxT("/Celeste/Threshold"), &threshold, HUGIN_CELESTE_THRESHOLD);
02003 
02004         // Mask resolution - 1 sets it to fine
02005         bool t = (cfg->Read(wxT("/Celeste/Filter"), HUGIN_CELESTE_FILTER) == 0);
02006         int radius=(t)?10:20;
02007         DEBUG_TRACE("Running Celeste");
02008 
02009         if (!progress.updateDisplayValue(_("Running Celeste")))
02010         {
02011             return;
02012         }
02013         // Image to analyse
02014         ImageCache::EntryPtr img=ImageCache::getInstance().getImage(m_pano->getImage(m_leftImageNr).getFilename());
02015         vigra::UInt16RGBImage in;
02016         if(img->image16->width()>0)
02017         {
02018             in.resize(img->image16->size());
02019             vigra::omp::copyImage(srcImageRange(*(img->image16)),destImage(in));
02020         }
02021         else
02022         {
02023             ImageCache::ImageCacheRGB8Ptr im8=img->get8BitImage();
02024             in.resize(im8->size());
02025             vigra::omp::transformImage(srcImageRange(*im8),destImage(in),vigra::functor::Arg1()*vigra::functor::Param(65535/255));
02026         };
02027         if (!progress.updateDisplayValue())
02028         {
02029             return;
02030         };
02031         UIntSet cloudCP=celeste::getCelesteControlPoints(model,in,currentPoints,radius,threshold,800);
02032         in.resize(0,0);
02033         if (!progress.updateDisplay())
02034         {
02035             return;
02036         }
02037 
02038         if(cloudCP.size()>0)
02039         {
02040             PanoCommand::GlobalCmdHist::getInstance().addCommand(
02041                 new PanoCommand::RemoveCtrlPointsCmd(*m_pano,cloudCP)
02042                 );
02043         };
02044 
02045         progress.updateDisplayValue();
02046         wxMessageBox(wxString::Format(_("Removed %lu control points"), static_cast<unsigned long int>(cloudCP.size())), _("Celeste result"), wxOK | wxICON_INFORMATION, this);
02047         DEBUG_TRACE("Finished running Celeste");
02048     }
02049 }
02050 
02051 void CPEditorPanel::OnCleanCPButton(wxCommandEvent& e)
02052 {
02053     if (currentPoints.size() < 2)
02054     {
02055         wxBell();
02056         return;
02057     };
02058     // calculate mean and variance only for currently active cp
02059     double mean = 0;
02060     double var = 0;
02061     size_t n = 0;
02062     for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end(); ++it)
02063     {
02064         n++;
02065         double x = it->second.error;
02066         double delta = x - mean;
02067         mean += delta / n;
02068         var += delta*(x - mean);
02069     }
02070     var = var / (n - 1);
02071     const double limit = (sqrt(var) > mean) ? mean : (mean + sqrt(var));
02072     HuginBase::UIntSet removedCPs;
02073     for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end(); ++it)
02074     {
02075         if (it->second.error > limit)
02076         {
02077             removedCPs.insert(it->first);
02078         };
02079     };
02080     if (!removedCPs.empty())
02081     {
02082         wxMessageBox(wxString::Format(_("Removed %lu control points"), (unsigned long int)removedCPs.size()), _("Cleaning"), wxOK | wxICON_INFORMATION, this);
02083         PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::RemoveCtrlPointsCmd(*m_pano, removedCPs));
02084     }
02085     else
02086     {
02087         wxBell();
02088     }
02089 };
02090 
02091 void CPEditorPanel::OnActionSelectCreate(wxCommandEvent& e)
02092 {
02093     m_cpActionButtonMode = CPTAB_ACTION_CREATE_CP;
02094     m_actionButton->SetLabel(_("Create cp"));
02095     m_actionButton->SetToolTip(_("Create control points for image pair with currently selected control point detector on photos tab."));
02096     Layout();
02097     wxConfig::Get()->Write(wxT("/CPEditorPanel/ActionMode"), static_cast<long>(m_cpActionButtonMode));
02098 };
02099 
02100 void CPEditorPanel::OnActionSelectCeleste(wxCommandEvent& e)
02101 {
02102     m_cpActionButtonMode = CPTAB_ACTION_CELESTE;
02103     m_actionButton->SetLabel(_("Celeste"));
02104     m_actionButton->SetToolTip(_("Tries to remove control points from clouds"));
02105     Layout();
02106     wxConfig::Get()->Write(wxT("/CPEditorPanel/ActionMode"), static_cast<long>(m_cpActionButtonMode));
02107 };
02108 
02109 void CPEditorPanel::OnActionSelectCleanCP(wxCommandEvent& e)
02110 {
02111     m_cpActionButtonMode = CPTAB_ACTION_CLEAN_CP;
02112     m_actionButton->SetLabel(_("Clean cp"));
02113     m_actionButton->SetToolTip(_("Remove outlying control points by statistical method"));
02114     Layout();
02115     wxConfig::Get()->Write(wxT("/CPEditorPanel/ActionMode"), static_cast<long>(m_cpActionButtonMode));
02116 };
02117 
02118 FDiff2D CPEditorPanel::LocalFineTunePoint(unsigned int srcNr,
02119                                           const Diff2D & srcPnt,
02120                                           hugin_utils::FDiff2D & movedSrcPnt,
02121                                           unsigned int moveNr,
02122                                           const FDiff2D & movePnt)
02123 {
02124     long templWidth = wxConfigBase::Get()->Read(wxT("/Finetune/TemplateSize"),HUGIN_FT_TEMPLATE_SIZE);
02125     long sWidth = templWidth + wxConfigBase::Get()->Read(wxT("/Finetune/LocalSearchWidth"),HUGIN_FT_LOCAL_SEARCH_WIDTH);
02126     CorrelationResult result;
02127     PointFineTune(srcNr,
02128                   srcPnt,
02129                   templWidth,
02130                   moveNr,
02131                   movePnt,
02132                   sWidth,
02133                   result);
02134     movedSrcPnt = result.corrPos;
02135     if (result.corrPos.x < 0 || result.corrPos.y < 0 || result.maxpos.x < 0 || result.maxpos.y < 0)
02136     {
02137         return FDiff2D(-1, -1);
02138     }
02139     return result.maxpos;
02140 }
02141 
02142 void CPEditorPanel::FineTuneSelectedPoint(bool left)
02143 {
02144     DEBUG_DEBUG(" selected Point: " << m_selectedPoint);
02145     if (m_selectedPoint == UINT_MAX) return;
02146     DEBUG_ASSERT(m_selectedPoint < currentPoints.size());
02147 
02148     HuginBase::ControlPoint cp = currentPoints[m_selectedPoint].second;
02149 
02150     unsigned int srcNr = cp.image1Nr;
02151     unsigned int moveNr = cp.image2Nr;
02152     Diff2D srcPnt(roundi(cp.x1), roundi(cp.y1));
02153     Diff2D movePnt(roundi(cp.x2), roundi(cp.y2));
02154     if (left) {
02155         srcNr = cp.image2Nr;
02156         moveNr = cp.image1Nr;
02157         srcPnt = Diff2D(roundi(cp.x2), roundi(cp.y2));
02158         movePnt = Diff2D(roundi(cp.x1), roundi(cp.y1));
02159     }
02160 
02161     FDiff2D movedSrcPnt;
02162     FDiff2D result = LocalFineTunePoint(srcNr, srcPnt, movedSrcPnt, moveNr, movePnt);
02163 
02164     if (result.x < 0 || result.y < 0)
02165     {
02166         wxBell();
02167         return;
02168     };
02169     
02170     if (left) {
02171        cp.x1 = result.x;
02172        cp.y1 = result.y;
02173        cp.x2 = movedSrcPnt.x;
02174        cp.y2 = movedSrcPnt.y;
02175     } else {
02176        cp.x2 = result.x;
02177        cp.y2 = result.y;
02178        cp.x1 = movedSrcPnt.x;
02179        cp.y1 = movedSrcPnt.y;
02180     }
02181 
02182     // if point was mirrored, reverse before setting it.
02183     if (set_contains(mirroredPoints, m_selectedPoint)) {
02184         cp.mirror();
02185     }
02186     PanoCommand::GlobalCmdHist::getInstance().addCommand(
02187         new PanoCommand::ChangeCtrlPointCmd(*m_pano, currentPoints[m_selectedPoint].first, cp)
02188         );
02189 }
02190 
02191 
02192 void CPEditorPanel::FineTuneNewPoint(bool left)
02193 {
02194     if (!(cpCreationState == RIGHT_POINT_RETRY ||
02195           cpCreationState == LEFT_POINT_RETRY ||
02196           cpCreationState == BOTH_POINTS_SELECTED))
02197     {
02198         return;
02199     }
02200 
02201     FDiff2D leftP = m_leftImg->getNewPoint();
02202     FDiff2D rightP = m_rightImg->getNewPoint();
02203 
02204     unsigned int srcNr = m_leftImageNr;
02205     Diff2D srcPnt(leftP.toDiff2D());
02206     unsigned int moveNr = m_rightImageNr;
02207     Diff2D movePnt(rightP.toDiff2D());
02208     if (left) {
02209         srcNr = m_rightImageNr;
02210         srcPnt = rightP.toDiff2D();
02211         moveNr = m_leftImageNr;
02212         movePnt = leftP.toDiff2D();
02213     }
02214 
02215     FDiff2D movedSrcPnt;
02216     FDiff2D result = LocalFineTunePoint(srcNr, srcPnt, movedSrcPnt, moveNr, movePnt);
02217 
02218     if (result.x < 0 || result.y < 0)
02219     {
02220         wxBell();
02221         return;
02222     };
02223     if (left) {
02224         m_leftImg->setNewPoint(result);
02225         m_leftImg->update();
02226         m_rightImg->setNewPoint(movedSrcPnt);
02227         m_rightImg->update();
02228 
02229     } else {
02230         m_rightImg->setNewPoint(result);
02231         m_rightImg->update();
02232         m_leftImg->setNewPoint(movedSrcPnt);
02233         m_leftImg->update();
02234     }
02235 }
02236 
02237 FDiff2D CPEditorPanel::EstimatePoint(const FDiff2D & p, bool left)
02238 {
02239     size_t nrNormalCp = 0;
02240     for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end(); ++it)
02241     {
02242         if (it->second.mode == HuginBase::ControlPoint::X_Y)
02243         {
02244             ++nrNormalCp;
02245         };
02246     };
02247     if (nrNormalCp==0)
02248     {
02249         DEBUG_WARN("Cannot estimate position without at least one point");
02250         return FDiff2D(0,0);
02251     }
02252 
02253     // get copy of SrcPanoImage and reset position
02254     SrcPanoImage leftImg = m_pano->getSrcImage(left ? m_leftImageNr : m_rightImageNr);
02255     leftImg.setYaw(0);
02256     leftImg.setPitch(0);
02257     leftImg.setRoll(0);
02258     leftImg.setX(0);
02259     leftImg.setY(0);
02260     leftImg.setZ(0);
02261     SrcPanoImage rightImg = m_pano->getSrcImage(left ? m_rightImageNr : m_leftImageNr);
02262     rightImg.setYaw(0);
02263     rightImg.setPitch(0);
02264     rightImg.setRoll(0);
02265     rightImg.setX(0);
02266     rightImg.setY(0);
02267     rightImg.setZ(0);
02268     // generate a temporary pano
02269     Panorama optPano;
02270     optPano.addImage(leftImg);
02271     optPano.addImage(rightImg);
02272     // construct OptimizeVector
02273     HuginBase::OptimizeVector optVec;
02274     std::set<std::string> opt;
02275     optVec.push_back(opt);
02276     opt.insert("y");
02277     opt.insert("p");
02278     if (nrNormalCp > 1)
02279     {
02280         opt.insert("r");
02281     };
02282     optVec.push_back(opt);
02283     optPano.setOptimizeVector(optVec);
02284     // now add control points, need to check image numbers
02285     HuginBase::CPVector cps;
02286     for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end(); ++it)
02287     {
02288         HuginBase::ControlPoint cp(it->second);
02289         if (cp.mode == HuginBase::ControlPoint::X_Y)
02290         {
02291             cp.image1Nr = left ? 0 : 1;
02292             cp.image2Nr = left ? 1 : 0;
02293             cps.push_back(cp);
02294         };
02295     };
02296     optPano.setCtrlPoints(cps);
02297     deregisterPTWXDlgFcn();
02298     HuginBase::PTools::optimize(optPano);
02299     registerPTWXDlgFcn();
02300 
02301     // now transform the wanted point p to other image
02302     HuginBase::PTools::Transform transformBackward;
02303     transformBackward.createInvTransform(optPano.getImage(0), optPano.getOptions());
02304     HuginBase::PTools::Transform transformForward;
02305     transformForward.createTransform(optPano.getImage(1), optPano.getOptions());
02306     FDiff2D t;
02307     if (transformBackward.transformImgCoord(t, p))
02308     {
02309         if (transformForward.transformImgCoord(t, t))
02310         {
02311             // clip to fit to
02312             if (t.x < 0) t.x = 0;
02313             if (t.y < 0) t.y = 0;
02314             if (t.x > optPano.getImage(1).getWidth()) t.x = optPano.getImage(1).getWidth();
02315             if (t.y > optPano.getImage(1).getHeight()) t.y = optPano.getImage(1).getHeight();
02316             DEBUG_DEBUG("estimated point " << t.x << "," << t.y);
02317             return t;
02318         };
02319     };
02320     wxBell();
02321     return FDiff2D(0, 0);
02322 }
02323 
02324 void CPEditorPanel::OnColumnWidthChange( wxListEvent & e )
02325 {
02326     int colNum = e.GetColumn();
02327     wxConfigBase::Get()->Write( wxString::Format(wxT("/CPEditorPanel/ColumnWidth%d"),colNum), m_cpList->GetColumnWidth(colNum) );
02328 }
02329 
02330 CPImageCtrl::ImageRotation CPEditorPanel::GetRot(double yaw, double pitch, double roll)
02331 {
02332     CPImageCtrl::ImageRotation rot = CPImageCtrl::ROT0;
02333     // normalize roll angle
02334     while (roll > 360) roll-= 360;
02335     while (roll < 0) roll += 360;
02336 
02337     while (pitch > 180) pitch -= 360;
02338     while (pitch < -180) pitch += 360;
02339     bool headOver = (pitch > 90 || pitch < -90);
02340 
02341     if (wxConfig::Get()->Read(wxT("/CPEditorPanel/AutoRot"),1L)) {
02342         if (roll >= 315 || roll < 45) {
02343             rot = headOver ? CPImageCtrl::ROT180 : CPImageCtrl::ROT0;
02344         } else if (roll >= 45 && roll < 135) {
02345             rot = headOver ? CPImageCtrl::ROT270 : CPImageCtrl::ROT90;
02346         } else if (roll >= 135 && roll < 225) {
02347             rot = headOver ? CPImageCtrl::ROT0 : CPImageCtrl::ROT180;
02348         } else {
02349             rot = headOver ? CPImageCtrl::ROT90 : CPImageCtrl::ROT270;
02350         }
02351     }
02352     return rot;
02353 }
02354 
02355 IMPLEMENT_DYNAMIC_CLASS(CPEditorPanel, wxPanel)
02356 
02357 CPEditorPanelXmlHandler::CPEditorPanelXmlHandler()
02358                 : wxXmlResourceHandler()
02359 {
02360     AddWindowStyles();
02361 }
02362 
02363 wxObject *CPEditorPanelXmlHandler::DoCreateResource()
02364 {
02365     XRC_MAKE_INSTANCE(cp, CPEditorPanel)
02366 
02367     cp->Create(m_parentAsWindow,
02368                    GetID(),
02369                    GetPosition(), GetSize(),
02370                    GetStyle(wxT("style")),
02371                    GetName());
02372 
02373     SetupWindow( cp);
02374 
02375     return cp;
02376 }
02377 
02378 bool CPEditorPanelXmlHandler::CanHandle(wxXmlNode *node)
02379 {
02380     return IsOfClass(node, wxT("CPEditorPanel"));
02381 }
02382 
02383 IMPLEMENT_DYNAMIC_CLASS(CPEditorPanelXmlHandler, wxXmlResourceHandler)
02384 

Generated on 2 Aug 2015 for Hugintrunk by  doxygen 1.4.7