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 "hugin/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 "hugin/wxPanoCommand.h"
00046 #include "base_wx/MyProgressDialog.h"
00047 
00048 // more standard includes if needed
00049 #include <algorithm>
00050 #include <float.h>
00051 #include <vector>
00052 
00053 // more vigra include if needed
00054 #include "vigra/cornerdetection.hxx"
00055 #include "vigra/localminmax.hxx"
00056 #include "vigra_ext/Correlation.h"
00057 
00058 // Celeste header
00059 #include "Celeste.h"
00060 
00061 using namespace std;
00062 using namespace PT;
00063 using namespace vigra;
00064 using namespace vigra_ext;
00065 using namespace vigra::functor;
00066 using namespace hugin_utils;
00067 
00068 BEGIN_EVENT_TABLE(CPEditorPanel, wxPanel)
00069     EVT_CPEVENT(CPEditorPanel::OnCPEvent)
00070     EVT_COMBOBOX(XRCID("cp_editor_left_choice"), CPEditorPanel::OnLeftChoiceChange )
00071     EVT_COMBOBOX(XRCID("cp_editor_right_choice"), CPEditorPanel::OnRightChoiceChange )
00072     EVT_LIST_ITEM_SELECTED(XRCID("cp_editor_cp_list"), CPEditorPanel::OnCPListSelect)
00073     EVT_LIST_ITEM_DESELECTED(XRCID("cp_editor_cp_list"), CPEditorPanel::OnCPListDeselect)
00074     EVT_LIST_COL_END_DRAG(XRCID("cp_editor_cp_list"), CPEditorPanel::OnColumnWidthChange)
00075     EVT_CHOICE(XRCID("cp_editor_choice_zoom"), CPEditorPanel::OnZoom)
00076     EVT_TEXT_ENTER(XRCID("cp_editor_x1"), CPEditorPanel::OnTextPointChange )
00077     EVT_TEXT_ENTER(XRCID("cp_editor_y1"), CPEditorPanel::OnTextPointChange )
00078     EVT_TEXT_ENTER(XRCID("cp_editor_x2"), CPEditorPanel::OnTextPointChange )
00079     EVT_TEXT_ENTER(XRCID("cp_editor_y2"), CPEditorPanel::OnTextPointChange )
00080     EVT_CHOICE(XRCID("cp_editor_mode"), CPEditorPanel::OnTextPointChange )
00081     EVT_CHAR(CPEditorPanel::OnKey)
00082     EVT_BUTTON(XRCID("cp_editor_delete"), CPEditorPanel::OnDeleteButton)
00083     EVT_BUTTON(XRCID("cp_editor_add"), CPEditorPanel::OnAddButton)
00084     EVT_BUTTON(XRCID("cp_editor_previous_img"), CPEditorPanel::OnPrevImg)
00085     EVT_BUTTON(XRCID("cp_editor_next_img"), CPEditorPanel::OnNextImg)
00086     EVT_BUTTON(XRCID("cp_editor_finetune_button"), CPEditorPanel::OnFineTuneButton)
00087     EVT_BUTTON(XRCID("cp_editor_celeste_button"), CPEditorPanel::OnCelesteButton)
00088 END_EVENT_TABLE()
00089 
00090 CPEditorPanel::CPEditorPanel()
00091 {
00092     DEBUG_TRACE("**********************");
00093     m_pano = 0;
00094 }
00095 
00096 bool CPEditorPanel::Create(wxWindow* parent, wxWindowID id,
00097                     const wxPoint& pos,
00098                     const wxSize& size,
00099                     long style,
00100                     const wxString& name)
00101 {
00102     DEBUG_TRACE(" Create called *************");
00103     if (! wxPanel::Create(parent, id, pos, size, style, name) ) {
00104         return false;
00105     }
00106 
00107     cpCreationState = NO_POINT;
00108     m_leftImageNr=UINT_MAX;
00109     m_rightImageNr=UINT_MAX;
00110     m_listenToPageChange=true;
00111     m_detailZoomFactor=1;
00112     m_selectedPoint=UINT_MAX;
00113     m_leftRot=CPImageCtrl::ROT0;
00114     m_rightRot=CPImageCtrl::ROT0;
00115 
00116     DEBUG_TRACE("");
00117     wxXmlResource::Get()->LoadPanel(this, wxT("cp_editor_panel"));
00118     wxPanel * panel = XRCCTRL(*this, "cp_editor_panel", wxPanel);
00119 
00120     wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
00121     topsizer->Add(panel, 1, wxEXPAND, 0);
00122 
00123     m_leftChoice = XRCCTRL(*this, "cp_editor_left_choice", CPImagesComboBox); 
00124     m_leftImg = XRCCTRL(*this, "cp_editor_left_img", CPImageCtrl);
00125     assert(m_leftImg);
00126     m_leftImg->Init(this);
00127     m_leftImg->setTransforms(&m_leftTransform, &m_leftInvTransform, &m_rightInvTransform);
00128 
00129     // right image
00130     m_rightChoice = XRCCTRL(*this, "cp_editor_right_choice", CPImagesComboBox);
00131     m_rightImg = XRCCTRL(*this, "cp_editor_right_img", CPImageCtrl);
00132     assert(m_rightImg);
00133     m_rightImg->Init(this);
00134     m_rightImg->setTransforms(&m_rightTransform, &m_rightInvTransform, &m_leftInvTransform);
00135 
00136     // setup list view
00137     m_cpList = XRCCTRL(*this, "cp_editor_cp_list", wxListCtrl);
00138     m_cpList->Connect(wxEVT_CHAR,wxKeyEventHandler(CPEditorPanel::OnKey),NULL,this);
00139     m_cpList->InsertColumn( 0, _("#"), wxLIST_FORMAT_RIGHT, 35);
00140     m_cpList->InsertColumn( 1, _("left x"), wxLIST_FORMAT_RIGHT, 65);
00141     m_cpList->InsertColumn( 2, _("left y"), wxLIST_FORMAT_RIGHT, 65);
00142     m_cpList->InsertColumn( 3, _("right x"), wxLIST_FORMAT_RIGHT, 65);
00143     m_cpList->InsertColumn( 4, _("right y"), wxLIST_FORMAT_RIGHT, 65);
00144     m_cpList->InsertColumn( 5, _("Alignment"), wxLIST_FORMAT_LEFT,110 );
00145     m_cpList->InsertColumn( 6, _("Distance"), wxLIST_FORMAT_RIGHT, 110);
00146 
00147     //get saved width
00148     for ( int j=0; j < m_cpList->GetColumnCount() ; j++ )
00149     {
00150         // -1 is auto
00151         int width = wxConfigBase::Get()->Read(wxString::Format( wxT("/CPEditorPanel/ColumnWidth%d"), j ), -1);
00152         if(width != -1)
00153             m_cpList->SetColumnWidth(j, width);
00154     }
00155 
00156     // other controls
00157     m_x1Text = XRCCTRL(*this,"cp_editor_x1", wxTextCtrl);
00158     m_x1Text->PushEventHandler(new TextKillFocusHandler(this));
00159     m_y1Text = XRCCTRL(*this,"cp_editor_y1", wxTextCtrl);
00160     m_y1Text->PushEventHandler(new TextKillFocusHandler(this));
00161     m_x2Text = XRCCTRL(*this,"cp_editor_x2", wxTextCtrl);
00162     m_x2Text->PushEventHandler(new TextKillFocusHandler(this));
00163     m_y2Text = XRCCTRL(*this,"cp_editor_y2", wxTextCtrl);
00164     m_y2Text->PushEventHandler(new TextKillFocusHandler(this));
00165 
00166     m_cpModeChoice = XRCCTRL(*this, "cp_editor_mode", wxChoice);
00167     m_addButton = XRCCTRL(*this, "cp_editor_add", wxButton);
00168     m_delButton = XRCCTRL(*this, "cp_editor_delete", wxButton);
00169 
00170     m_autoAddCB = XRCCTRL(*this,"cp_editor_auto_add", wxCheckBox);
00171     DEBUG_ASSERT(m_autoAddCB);
00172     m_fineTuneCB = XRCCTRL(*this,"cp_editor_fine_tune_check",wxCheckBox);
00173     DEBUG_ASSERT(m_fineTuneCB);
00174 
00175     m_estimateCB = XRCCTRL(*this,"cp_editor_auto_estimate", wxCheckBox);
00176     DEBUG_ASSERT(m_estimateCB);
00177 
00178     // setup scroll window for the controls under the images
00179     m_cp_ctrls = XRCCTRL(*this, "cp_controls_panel", wxPanel);
00180     DEBUG_ASSERT(m_cp_ctrls);
00181 
00182     wxConfigBase *config = wxConfigBase::Get();
00183 
00184     m_autoAddCB->SetValue(config->Read(wxT("/CPEditorPanel/autoAdd"),0l) != 0 );
00185     m_fineTuneCB->SetValue(config->Read(wxT("/CPEditorPanel/autoFineTune"),1l) != 0 );
00186     m_estimateCB->SetValue(config->Read(wxT("/CPEditorPanel/autoEstimate"),1l) != 0 );
00187 
00188     // disable controls by default
00189     m_cpModeChoice->Disable();
00190     m_addButton->Disable();
00191     m_delButton->Disable();
00192     m_autoAddCB->Disable();
00193     m_fineTuneCB->Disable();
00194     m_estimateCB->Disable();
00195     XRCCTRL(*this, "cp_editor_finetune_button", wxButton)->Disable();
00196     XRCCTRL(*this, "cp_editor_celeste_button", wxButton)->Disable();
00197     XRCCTRL(*this, "cp_editor_choice_zoom", wxChoice)->Disable();
00198     XRCCTRL(*this, "cp_editor_previous_img", wxButton)->Disable();
00199     XRCCTRL(*this, "cp_editor_next_img", wxButton)->Disable();
00200     m_leftChoice->Disable();
00201     m_rightChoice->Disable();
00202 
00203     // apply zoom specified in xrc file
00204     wxCommandEvent dummy;
00205     dummy.SetInt(XRCCTRL(*this,"cp_editor_choice_zoom",wxChoice)->GetSelection());
00206     OnZoom(dummy);
00207 
00208     SetSizer( topsizer );
00209 
00210     return true;
00211 }
00212 
00213 void CPEditorPanel::Init(PT::Panorama * pano)
00214 {
00215     m_pano=pano;
00216     // observe the panorama
00217     m_pano->addObserver(this);
00218 }
00219 
00220 CPEditorPanel::~CPEditorPanel()
00221 {
00222     DEBUG_TRACE("dtor");
00223 
00224     m_x1Text->PopEventHandler(true);
00225     m_y1Text->PopEventHandler(true);
00226     m_x2Text->PopEventHandler(true);
00227     m_y2Text->PopEventHandler(true);
00228 
00229     wxConfigBase::Get()->Write(wxT("/CPEditorPanel/autoAdd"), m_autoAddCB->IsChecked() ? 1 : 0);
00230     wxConfigBase::Get()->Write(wxT("/CPEditorPanel/autoFineTune"), m_fineTuneCB->IsChecked() ? 1 : 0);
00231     wxConfigBase::Get()->Write(wxT("/CPEditorPanel/autoEstimate"), m_estimateCB->IsChecked() ? 1 : 0);
00232 
00233     m_pano->removeObserver(this);
00234     DEBUG_TRACE("dtor end");
00235 }
00236 
00237 void CPEditorPanel::setLeftImage(unsigned int imgNr)
00238 {
00239     DEBUG_TRACE("image " << imgNr);
00240     if (imgNr == UINT_MAX) {
00241         m_leftImg->setImage("", CPImageCtrl::ROT0);
00242         m_leftImageNr = imgNr;
00243         m_leftFile = "";
00244         changeState(NO_POINT);
00245         UpdateDisplay(true);
00246     } else if (m_leftImageNr != imgNr) {
00247         double yaw = const_map_get(m_pano->getImageVariables(imgNr),"y").getValue();
00248         double pitch = const_map_get(m_pano->getImageVariables(imgNr),"p").getValue();
00249         double roll = const_map_get(m_pano->getImageVariables(imgNr),"r").getValue();
00250         m_leftRot = GetRot(yaw, pitch, roll);
00251         m_leftImg->setImage(m_pano->getImage(imgNr).getFilename(), m_leftRot);
00252         m_leftImageNr = imgNr;
00253         if (m_leftChoice->GetSelection() != (int) imgNr) {
00254             m_leftChoice->SetSelection(imgNr);
00255         }
00256         m_rightChoice->SetRefImage(m_pano,m_leftImageNr);
00257         m_rightChoice->Refresh();
00258         m_leftFile = m_pano->getImage(imgNr).getFilename();
00259         changeState(NO_POINT);
00260         UpdateDisplay(true);
00261     }
00262     m_selectedPoint = UINT_MAX;
00263     // FIXME: lets hope that nobody holds references to these images..
00264     ImageCache::getInstance().softFlush();
00265     UpdateTransforms();
00266 }
00267 
00268 
00269 void CPEditorPanel::setRightImage(unsigned int imgNr)
00270 {
00271     DEBUG_TRACE("image " << imgNr);
00272     if (imgNr == UINT_MAX) {
00273         m_rightImg->setImage("", CPImageCtrl::ROT0);
00274         m_rightImageNr = imgNr;
00275         m_rightFile = "";
00276         m_rightRot = CPImageCtrl::ROT0;
00277         changeState(NO_POINT);
00278         UpdateDisplay(true);
00279     } else if (m_rightImageNr != imgNr) {
00280         // set the new image
00281         double yaw = const_map_get(m_pano->getImageVariables(imgNr),"y").getValue();
00282         double pitch = const_map_get(m_pano->getImageVariables(imgNr),"p").getValue();
00283         double roll = const_map_get(m_pano->getImageVariables(imgNr),"r").getValue();
00284         m_rightRot = GetRot(yaw, pitch, roll);
00285         m_rightImg->setImage(m_pano->getImage(imgNr).getFilename(), m_rightRot);
00286         // select tab
00287         m_rightImageNr = imgNr;
00288         if (m_rightChoice->GetSelection() != (int) imgNr) {
00289             m_rightChoice->SetSelection(imgNr);
00290         }
00291         m_leftChoice->SetRefImage(m_pano,m_rightImageNr);
00292         m_leftChoice->Refresh();
00293         m_rightFile = m_pano->getImage(imgNr).getFilename();
00294         // update the rest of the display (new control points etc)
00295         changeState(NO_POINT);
00296         UpdateDisplay(true);
00297     }
00298     m_selectedPoint = UINT_MAX;
00299 
00300     // FIXME: lets hope that nobody holds references to these images..
00301     ImageCache::getInstance().softFlush();
00302     UpdateTransforms();
00303 }
00304 
00305 void CPEditorPanel::UpdateTransforms()
00306 {
00307     if(m_leftImageNr<m_pano->getNrOfImages())
00308     {
00309         m_leftTransform.createTransform(m_pano->getImage(m_leftImageNr), m_pano->getOptions());
00310         m_leftInvTransform.createInvTransform(m_pano->getImage(m_leftImageNr), m_pano->getOptions());
00311     };
00312     if(m_rightImageNr<m_pano->getNrOfImages())
00313     {
00314         m_rightTransform.createTransform(m_pano->getImage(m_rightImageNr), m_pano->getOptions());
00315         m_rightInvTransform.createInvTransform(m_pano->getImage(m_rightImageNr), m_pano->getOptions());
00316     };
00317 };
00318 
00319 void CPEditorPanel::OnCPEvent( CPEvent&  ev)
00320 {
00321     DEBUG_TRACE("");
00322     wxString text;
00323     unsigned int nr = ev.getPointNr();
00324     FDiff2D point = ev.getPoint();
00325     bool left (TRUE);
00326     if (ev.GetEventObject() == m_leftImg) {
00327         left = true;
00328     } else  if (ev.GetEventObject() == m_rightImg){
00329         left = false;
00330     } else {
00331         DEBUG_FATAL("UNKNOWN SOURCE OF CPEvent");
00332     }
00333 
00334     switch (ev.getMode()) {
00335     case CPEvent::NONE:
00336         text = wxT("NONE");
00337         break;
00338     case CPEvent::NEW_POINT_CHANGED:
00339         NewPointChange(ev.getPoint(),left);
00340         break;
00341     case CPEvent::POINT_SELECTED:
00342         // need to reset cpEditState
00343         DEBUG_DEBUG("selected point " << nr);
00344         SelectLocalPoint(nr);
00345         changeState(NO_POINT);
00346         break;
00347     case CPEvent::NEW_LINE_ADDED:
00348         {
00349             float vertBias = getVerticalCPBias();
00350             ControlPoint cp=ev.getControlPoint();
00351             cp.image1Nr=m_leftImageNr;
00352             cp.image2Nr=m_rightImageNr;
00353             bool  hor = abs(cp.x1 - cp.x2) > (abs(cp.y1 - cp.y2) * vertBias);
00354             switch (m_leftRot)
00355             {
00356                 case CPImageCtrl::ROT0:
00357                 case CPImageCtrl::ROT180:
00358                     if (hor)
00359                         cp.mode = PT::ControlPoint::Y;
00360                     else
00361                         cp.mode = PT::ControlPoint::X;
00362                     break;
00363                 default:
00364                     if (hor)
00365                         cp.mode = PT::ControlPoint::X;
00366                     else
00367                         cp.mode = PT::ControlPoint::Y;
00368                     break;
00369             }
00370             changeState(NO_POINT);
00371             // create points
00372             GlobalCmdHist::getInstance().addCommand(new PT::AddCtrlPointCmd(*m_pano, cp));
00373             // select new control Point
00374             unsigned int lPoint = m_pano->getNrOfCtrlPoints()-1;
00375             SelectGlobalPoint(lPoint);
00376             changeState(NO_POINT);
00377             MainFrame::Get()->SetStatusText(_("new control point added"));
00378             m_leftChoice->CalcCPDistance(m_pano);
00379             m_rightChoice->CalcCPDistance(m_pano);
00380             break;
00381         };
00382     case CPEvent::POINT_CHANGED:
00383         {
00384             DEBUG_DEBUG("move point("<< nr << ")");
00385             if (nr >= currentPoints.size()) {
00386                 DEBUG_ERROR("invalid point number while moving point")
00387                 return;
00388             }
00389             ControlPoint cp = ev.getControlPoint();
00390             changeState(NO_POINT);
00391             DEBUG_DEBUG("changing point to: " << cp.x1 << "," << cp.y1
00392                         << "  " << cp.x2 << "," << cp.y2);
00393 
00394             GlobalCmdHist::getInstance().addCommand(
00395                 new PT::ChangeCtrlPointCmd(*m_pano, currentPoints[nr].first, cp)
00396                 );
00397 
00398             break;
00399         }
00400     case CPEvent::RIGHT_CLICK:
00401         {
00402             if (cpCreationState == BOTH_POINTS_SELECTED) {
00403                 DEBUG_DEBUG("right click -> adding point");
00404                 CreateNewPoint();
00405             } else {
00406                 DEBUG_DEBUG("right click without two points..");
00407                 changeState(NO_POINT);
00408             }
00409             break;
00410         }
00411     case CPEvent::SCROLLED:
00412         {
00413             wxPoint d(roundi(point.x), roundi(point.y));
00414             d = m_rightImg->MaxScrollDelta(d);
00415             d = m_leftImg->MaxScrollDelta(d);
00416             m_rightImg->ScrollDelta(d);
00417             m_leftImg->ScrollDelta(d);
00418         }
00419         break;
00420     case CPEvent::DELETE_REGION_SELECTED:
00421         {
00422             UIntSet cpToRemove;
00423             if(currentPoints.size()>0)
00424             {
00425                 wxRect rect=ev.getRect();
00426                 for(unsigned int i=0;i<currentPoints.size();i++)
00427                 {
00428                     ControlPoint cp=currentPoints[i].second;
00429                     if(cp.mode==ControlPoint::X_Y)
00430                     {
00431                         //checking only normal control points
00432                         if(left)
00433                         {
00434                             if(rect.Contains(roundi(cp.x1),roundi(cp.y1)))
00435                             {
00436                                 cpToRemove.insert(localPNr2GlobalPNr(i));
00437                             };
00438                         }
00439                         else
00440                         {
00441                             if(rect.Contains(roundi(cp.x2),roundi(cp.y2)))
00442                             {
00443                                 cpToRemove.insert(localPNr2GlobalPNr(i));
00444                             };
00445                         };
00446                     };
00447                 };
00448             };
00449             changeState(NO_POINT);
00450             if(cpToRemove.size()>0)
00451             {
00452                 GlobalCmdHist::getInstance().addCommand(new PT::RemoveCtrlPointsCmd(*m_pano,cpToRemove));
00453             };
00454             break;
00455         }
00456     } //end switch
00457     m_leftImg->update();
00458     m_rightImg->update();
00459 }
00460 
00461 
00462 void CPEditorPanel::CreateNewPoint()
00463 {
00464     DEBUG_TRACE("");
00465     FDiff2D p1 = m_leftImg->getNewPoint();
00466     FDiff2D p2 = m_rightImg->getNewPoint();
00467     ControlPoint point;
00468     point.image1Nr = m_leftImageNr;
00469     point.x1 = p1.x;
00470     point.y1 = p1.y;
00471     point.image2Nr = m_rightImageNr;
00472     point.x2 = p2.x;
00473     point.y2 = p2.y;
00474     if (point.image1Nr == point.image2Nr) {
00475         if (m_cpModeChoice->GetSelection()>=3) {
00476             // keep line until user chooses new mode
00477             point.mode = m_cpModeChoice->GetSelection();
00478         } else {
00479             // Most projections will have a bias to creating vertical
00480             // constraints.
00481             float vertBias = getVerticalCPBias();
00482             bool  hor = abs(p1.x - p2.x) > (abs(p1.y - p2.y) * vertBias);
00483             switch (m_leftRot) {
00484                 case CPImageCtrl::ROT0:
00485                 case CPImageCtrl::ROT180:
00486                     if (hor)
00487                         point.mode = PT::ControlPoint::Y;
00488                     else
00489                         point.mode = PT::ControlPoint::X;
00490                     break;
00491                 default:
00492                     if (hor)
00493                         point.mode = PT::ControlPoint::X;
00494                     else
00495                         point.mode = PT::ControlPoint::Y;
00496                     break;
00497             }
00498         }
00499     } else {
00500         point.mode = PT::ControlPoint::X_Y;
00501     }
00502 
00503     changeState(NO_POINT);
00504 
00505     // create points
00506     GlobalCmdHist::getInstance().addCommand(
00507         new PT::AddCtrlPointCmd(*m_pano, point)
00508         );
00509 
00510 
00511     // select new control Point
00512     unsigned int lPoint = m_pano->getNrOfCtrlPoints() -1;
00513     SelectGlobalPoint(lPoint);
00514     changeState(NO_POINT);
00515     MainFrame::Get()->SetStatusText(_("new control point added"));
00516     m_leftChoice->CalcCPDistance(m_pano);
00517     m_rightChoice->CalcCPDistance(m_pano);
00518 }
00519 
00520 
00521 const float CPEditorPanel::getVerticalCPBias()
00522 {
00523     PanoramaOptions opts = m_pano->getOptions();
00524     PanoramaOptions::ProjectionFormat projFormat = opts.getProjection();
00525     float bias;
00526     switch (projFormat)
00527     {
00528         case PanoramaOptions::RECTILINEAR:
00529             bias = 1.0;
00530             break;
00531         default:
00532             bias = 2.0;
00533             break;
00534     }
00535     return bias;
00536 }
00537 
00538 
00539 void CPEditorPanel::ClearSelection()
00540 {
00541     if (m_selectedPoint == UINT_MAX) {
00542         // no point selected, no need to select one.
00543         return;
00544     }
00545     m_cpList->SetItemState(m_selectedPoint, 0, wxLIST_STATE_SELECTED);
00546 
00547     m_selectedPoint=UINT_MAX;
00548     changeState(NO_POINT);
00549     m_leftImg->deselect();
00550     m_rightImg->deselect();
00551     UpdateDisplay(false);
00552 }
00553 
00554 void CPEditorPanel::SelectLocalPoint(unsigned int LVpointNr)
00555 {
00556     DEBUG_TRACE("selectLocalPoint(" << LVpointNr << ")");
00557 
00558     if ( m_selectedPoint == LVpointNr) {
00559         DEBUG_DEBUG("already selected");
00560         m_leftImg->selectPoint(LVpointNr);
00561         m_rightImg->selectPoint(LVpointNr);
00562         return;
00563     }
00564     m_selectedPoint = LVpointNr;
00565 
00566     const ControlPoint & p = currentPoints[LVpointNr].second;
00567     m_x1Text->SetValue(wxString::Format(wxT("%.2f"),p.x1));
00568     m_y1Text->SetValue(wxString::Format(wxT("%.2f"),p.y1));
00569     m_x2Text->SetValue(wxString::Format(wxT("%.2f"),p.x2));
00570     m_y2Text->SetValue(wxString::Format(wxT("%.2f"),p.y2));
00571     m_cpModeChoice->SetSelection(p.mode);
00572     m_leftImg->selectPoint(LVpointNr);
00573     m_rightImg->selectPoint(LVpointNr);
00574     m_cpList->SetItemState(LVpointNr, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
00575     m_cpList->EnsureVisible(LVpointNr);
00576 
00577     EnablePointEdit(true);
00578 }
00579 
00580 void CPEditorPanel::SelectGlobalPoint(unsigned int globalNr)
00581 {
00582     unsigned int localNr;
00583     if (globalPNr2LocalPNr(localNr,globalNr)) {
00584         DEBUG_DEBUG("CPEditor::setGlobalPoint(" << globalNr << ") found local point " << localNr);
00585         SelectLocalPoint(localNr);
00586     } else {
00587         DEBUG_ERROR("CPEditor::setGlobalPoint: point " << globalNr << " not found in currentPoints");
00588     }
00589 }
00590 
00591 bool CPEditorPanel::globalPNr2LocalPNr(unsigned int & localNr, unsigned int globalNr) const
00592 {
00593     HuginBase::CPointVector::const_iterator it = currentPoints.begin();
00594 
00595     while(it != currentPoints.end() && (*it).first != globalNr) {
00596         it++;
00597     }
00598 
00599     if (it != currentPoints.end()) {
00600         localNr = it - currentPoints.begin();
00601         return true;
00602     } else {
00603         return false;
00604     }
00605 }
00606 
00607 unsigned int CPEditorPanel::localPNr2GlobalPNr(unsigned int localNr) const
00608 {
00609     assert(localNr < currentPoints.size());
00610     return currentPoints[localNr].first;
00611 }
00612 
00613 
00614 void CPEditorPanel::estimateAndAddOtherPoint(const FDiff2D & p,
00615                                              bool left,
00616                                              CPImageCtrl * thisImg,
00617                                              unsigned int thisImgNr,
00618                                              CPCreationState THIS_POINT,
00619                                              CPCreationState THIS_POINT_RETRY,
00620                                              CPImageCtrl * otherImg,
00621                                              unsigned int otherImgNr,
00622                                              CPCreationState OTHER_POINT,
00623                                              CPCreationState OTHER_POINT_RETRY)
00624 {
00625     FDiff2D op;
00626     op = EstimatePoint(FDiff2D(p.x, p.y), left);
00627     // check if point is in image.
00628     const SrcPanoImage & pImg = m_pano->getImage(otherImgNr);
00629     if (p.x < (int) pImg.getSize().width() && p.x >= 0
00630         && p.y < (int) pImg.getSize().height() && p.y >= 0)
00631     {
00632         otherImg->setNewPoint(op);
00633         // if fine-tune is checked, run a fine-tune session as well.
00634         // hmm probably there should be another separate function for this..
00635         if (m_fineTuneCB->IsChecked()) {
00636             MainFrame::Get()->SetStatusText(_("searching similar points..."),0);
00637             FDiff2D newPoint = otherImg->getNewPoint();
00638 
00639             long templWidth = wxConfigBase::Get()->Read(wxT("/Finetune/TemplateSize"), HUGIN_FT_TEMPLATE_SIZE);
00640             const SrcPanoImage & img = m_pano->getImage(thisImgNr);
00641             double sAreaPercent = wxConfigBase::Get()->Read(wxT("/Finetune/SearchAreaPercent"),HUGIN_FT_SEARCH_AREA_PERCENT);
00642             int sWidth = (int) (img.getWidth() * sAreaPercent / 100.0);
00643             CorrelationResult corrPoint;
00644             double corrOk=false;
00645             Diff2D roundp(p.toDiff2D());
00646             try {
00647                 corrOk = PointFineTune(thisImgNr,
00648                                       roundp,
00649                                       templWidth,
00650                                       otherImgNr,
00651                                       newPoint,
00652                                       sWidth,
00653                                       corrPoint);
00654             } catch (std::exception & e) {
00655                 wxMessageBox(wxString (e.what(), wxConvLocal), _("Error during Fine-tune"));
00656             }
00657             if (! corrOk) {
00658                 // just set point, PointFineTune already complained
00659                 otherImg->setScale(m_detailZoomFactor);
00660                 otherImg->setNewPoint(corrPoint.maxpos);
00661                 changeState(BOTH_POINTS_SELECTED);
00662             } else {
00663                 // show point & zoom in if auto add is not set
00664                 if (!m_autoAddCB->IsChecked()) {
00665                     otherImg->setScale(m_detailZoomFactor);
00666                     otherImg->setNewPoint(corrPoint.maxpos);
00667                     changeState(BOTH_POINTS_SELECTED);
00668                     wxString s1;
00669                     s1.Printf(_("Point fine-tuned, angle: %.0f deg, correlation coefficient: %0.3f, curvature: %0.3f %0.3f "),
00670                               corrPoint.maxAngle, corrPoint.maxi, corrPoint.curv.x, corrPoint.curv.y );
00671                     
00672                     wxString s2 = s1 + wxT(" -- ") + wxString(_("change points, or press right mouse button to add the pair"));
00673                     MainFrame::Get()->SetStatusText(s2,0);
00674                 } else {
00675                     // add point
00676                     otherImg->setNewPoint(corrPoint.maxpos);
00677                     changeState(BOTH_POINTS_SELECTED);
00678                     CreateNewPoint();
00679                 }
00680             }
00681         } else {
00682             // no fine-tune, set 100% scale and set both points to selected
00683             otherImg->setScale(m_detailZoomFactor);
00684             otherImg->showPosition(op);
00685             changeState(BOTH_POINTS_SELECTED);
00686         }
00687 
00688     } else {
00689         // estimate was outside of image
00690         // do nothing special
00691         wxBell();
00692         MainFrame::Get()->SetStatusText(_("Estimated point outside image"),0);
00693     }
00694 }
00695 
00696 void CPEditorPanel::NewPointChange(FDiff2D p, bool left)
00697 {
00698     DEBUG_TRACE("");
00699 
00700     wxString corrMsg;
00701 
00702     CPImageCtrl * thisImg = m_leftImg;
00703     unsigned int thisImgNr = m_leftImageNr;
00704     CPImageCtrl * otherImg = m_rightImg;
00705     unsigned int otherImgNr = m_rightImageNr;
00706     CPCreationState THIS_POINT = LEFT_POINT;
00707     CPCreationState THIS_POINT_RETRY = LEFT_POINT_RETRY;
00708     CPCreationState OTHER_POINT = RIGHT_POINT;
00709     CPCreationState OTHER_POINT_RETRY = RIGHT_POINT_RETRY;
00710 
00711     bool estimate = m_estimateCB->IsChecked();
00712 
00713     if (!left) {
00714         thisImg = m_rightImg;
00715         thisImgNr = m_rightImageNr;
00716         otherImg = m_leftImg;
00717         otherImgNr = m_leftImageNr;
00718         THIS_POINT = RIGHT_POINT;
00719         THIS_POINT_RETRY = RIGHT_POINT_RETRY;
00720         OTHER_POINT = LEFT_POINT;
00721         OTHER_POINT_RETRY = LEFT_POINT_RETRY;
00722     }
00723 
00724 
00725     if (cpCreationState == NO_POINT) {
00726         //case NO_POINT
00727         changeState(THIS_POINT);
00728         // zoom into our window
00729         if (thisImg->getScale() < 1) {
00730             thisImg->setScale(m_detailZoomFactor);
00731             thisImg->showPosition(p);
00732         } else {
00733             // run auto-estimate procedure?
00734             if (estimate && (thisImgNr != otherImgNr) && currentPoints.size() > 0) {
00735                 estimateAndAddOtherPoint(p, left,
00736                                          thisImg, thisImgNr, THIS_POINT, THIS_POINT_RETRY,
00737                                          otherImg, otherImgNr, OTHER_POINT, OTHER_POINT_RETRY);
00738             };
00739         }
00740 
00741     } else if (cpCreationState == OTHER_POINT_RETRY) {
00742         thisImg->showPosition(p);
00743     } else if (cpCreationState == THIS_POINT) {
00744         thisImg->showPosition(p);
00745 
00746         if (estimate && (thisImgNr != otherImgNr) && currentPoints.size() > 0) {
00747             estimateAndAddOtherPoint(p, left,
00748                                      thisImg, thisImgNr, THIS_POINT, THIS_POINT_RETRY,
00749                                      otherImg, otherImgNr, OTHER_POINT, OTHER_POINT_RETRY);
00750         }
00751     } else if (cpCreationState == OTHER_POINT || cpCreationState == THIS_POINT_RETRY) {
00752         // the try for the second point.
00753         if (cpCreationState == OTHER_POINT) {
00754             // other point already selected, finalize point.
00755 
00756             // TODO: option to ignore the auto fine tune button when multiple images are selected.
00757             if (m_fineTuneCB->IsChecked() ) {
00758                 CorrelationResult corrRes;
00759 
00760                 FDiff2D newPoint = otherImg->getNewPoint();
00761 
00762                 long templWidth = wxConfigBase::Get()->Read(wxT("/Finetune/TemplateSize"),HUGIN_FT_TEMPLATE_SIZE);
00763                 const SrcPanoImage & img = m_pano->getImage(thisImgNr);
00764                 double sAreaPercent = wxConfigBase::Get()->Read(wxT("/Finetune/SearchAreaPercent"),
00765                                                                 HUGIN_FT_SEARCH_AREA_PERCENT);
00766                 int sWidth = (int) (img.getWidth() * sAreaPercent / 100.0);
00767                 bool corrOk = false;
00768                 // corr point
00769                 Diff2D newPoint_round = newPoint.toDiff2D();
00770                 try {
00771                     corrOk = PointFineTune(otherImgNr,
00772                                            newPoint_round,
00773                                            templWidth,
00774                                            thisImgNr,
00775                                            p,
00776                                            sWidth,
00777                                            corrRes);
00778                 } catch (std::exception & e) {
00779                     wxMessageBox(wxString (e.what(), wxConvLocal), _("Error during Fine-tune"));
00780                 }
00781 
00782                 if (! corrOk) {
00783                     // low xcorr
00784                     // zoom to 100 percent. & set second stage
00785                     // to abandon finetune this time.
00786                     thisImg->setScale(m_detailZoomFactor);
00787                     thisImg->setNewPoint(corrRes.maxpos);
00788                     thisImg->update();
00789                     otherImg->setNewPoint(FDiff2D(newPoint_round.x, newPoint_round.y));
00790                     changeState(BOTH_POINTS_SELECTED);
00791                 } else {
00792                     // show point & zoom in if auto add is not set
00793                     changeState(BOTH_POINTS_SELECTED);
00794                     if (!m_autoAddCB->IsChecked()) {
00795                         thisImg->setScale(m_detailZoomFactor);
00796                     }
00797                     thisImg->setNewPoint(corrRes.maxpos);
00798                     wxString s1;
00799                     s1.Printf(_("Point fine-tuned, angle: %.0f deg, correlation coefficient: %0.3f, curvature: %0.3f %0.3f "),
00800                               corrRes.maxAngle, corrRes.maxi, corrRes.curv.x, corrRes.curv.y );
00801                     
00802                     corrMsg = s1 + wxT(" -- ") +  wxString(_("change points, or press right mouse button to add the pair"));
00803                     MainFrame::Get()->SetStatusText(corrMsg,0);
00804                     
00805                 }
00806             } else {
00807                 // no finetune. but zoom into picture, when we where zoomed out
00808                 if (thisImg->getScale() < 1) {
00809                     // zoom to 100 percent. & set second stage
00810                     // to abandon finetune this time.
00811                     thisImg->setScale(m_detailZoomFactor);
00812                     thisImg->clearNewPoint();
00813                     thisImg->showPosition(p);
00814                     //thisImg->setNewPoint(p.x, p.y);
00815                     changeState(THIS_POINT_RETRY);
00816                     return;
00817                 } else {
00818                     // point is already set. no need to move.
00819                     // setNewPoint(p);
00820                     changeState(BOTH_POINTS_SELECTED);
00821                 }
00822             }
00823         } else {
00824             // selection retry
00825             // nothing special, no second stage fine-tune yet.
00826         }
00827 
00828         // ok, we have determined the other point.. apply if auto add is on
00829         if (m_autoAddCB->IsChecked()) {
00830             CreateNewPoint();
00831         } else {
00832             // keep both point floating around, until they are
00833             // added with a right mouse click or the add button
00834             changeState(BOTH_POINTS_SELECTED);
00835             if (corrMsg != wxT("")) {
00836                 MainFrame::Get()->SetStatusText(corrMsg,0);
00837             }
00838         }
00839 
00840     } else if (cpCreationState == BOTH_POINTS_SELECTED) {
00841         // nothing to do.. maybe a special fine-tune with
00842         // a small search region
00843 
00844     } else {
00845         // should never reach this, else state machine is broken.
00846         DEBUG_ASSERT(0);
00847     }
00848 }
00849 
00850 bool CPEditorPanel::PointFineTune(unsigned int tmplImgNr,
00851                                   const Diff2D & tmplPoint,
00852                                   int templSize,
00853                                   unsigned int subjImgNr,
00854                                   const FDiff2D & o_subjPoint,
00855                                   int sWidth,
00856                                   CorrelationResult & res)
00857 {
00858     DEBUG_TRACE("tmpl img nr: " << tmplImgNr << " corr src: "
00859                 << subjImgNr);
00860 
00861     MainFrame::Get()->SetStatusText(_("searching similar points..."),0);
00862 
00863     double corrThresh=HUGIN_FT_CORR_THRESHOLD;
00864     wxConfigBase::Get()->Read(wxT("/Finetune/CorrThreshold"),&corrThresh,
00865                               HUGIN_FT_CORR_THRESHOLD);
00866 
00867     double curvThresh = HUGIN_FT_CURV_THRESHOLD;
00868     wxConfigBase::Get()->Read(wxT("/Finetune/CurvThreshold"),&curvThresh,
00869                               HUGIN_FT_CURV_THRESHOLD);
00870 
00871     const SrcPanoImage & img = m_pano->getImage(subjImgNr);
00872 
00873     // fixme: just cutout suitable gray 
00874     ImageCache::EntryPtr subjImg = ImageCache::getInstance().getImage(img.getFilename());
00875     ImageCache::EntryPtr tmplImg = ImageCache::getInstance().getImage( m_pano->getImage(tmplImgNr).getFilename());
00876 
00877     wxConfigBase *cfg = wxConfigBase::Get();
00878     bool rotatingFinetune = cfg->Read(wxT("/Finetune/RotationSearch"), HUGIN_FT_ROTATION_SEARCH) == 1;
00879 
00880     if (rotatingFinetune) {
00881         double startAngle=HUGIN_FT_ROTATION_START_ANGLE;
00882         cfg->Read(wxT("/Finetune/RotationStartAngle"),&startAngle,HUGIN_FT_ROTATION_START_ANGLE);
00883         startAngle=DEG_TO_RAD(startAngle);
00884         double stopAngle=HUGIN_FT_ROTATION_STOP_ANGLE;
00885         cfg->Read(wxT("/Finetune/RotationStopAngle"),&stopAngle,HUGIN_FT_ROTATION_STOP_ANGLE);
00886         stopAngle=DEG_TO_RAD(stopAngle);
00887         int nSteps = cfg->Read(wxT("/Finetune/RotationSteps"), HUGIN_FT_ROTATION_STEPS);
00888         {
00889             wxBusyCursor busy;
00890             if (subjImg->image8 && tmplImg->image8) {
00891                 res = vigra_ext::PointFineTuneRotSearch(*(tmplImg->image8),
00892                                                         tmplPoint, templSize,
00893                                                         *(subjImg->image8),
00894                                                         o_subjPoint.toDiff2D(),
00895                                                         sWidth,
00896                                                         startAngle, stopAngle, nSteps);
00897             } else if (subjImg->imageFloat && tmplImg->imageFloat) {
00898                 res = vigra_ext::PointFineTuneRotSearch(*(tmplImg->imageFloat),
00899                                                         tmplPoint, templSize,
00900                                                         *(subjImg->imageFloat),
00901                                                         o_subjPoint.toDiff2D(),
00902                                                         sWidth,
00903                                                         startAngle, stopAngle, nSteps);
00904             } else if (subjImg->image8 && tmplImg->imageFloat) {
00905                 res = vigra_ext::PointFineTuneRotSearch(*(tmplImg->imageFloat),
00906                                                         tmplPoint, templSize,
00907                                                         *(subjImg->image8),
00908                                                         o_subjPoint.toDiff2D(),
00909                                                         sWidth,
00910                                                         startAngle, stopAngle, nSteps);
00911             } else {
00912                 res = vigra_ext::PointFineTuneRotSearch(*(tmplImg->image8),
00913                                                         tmplPoint, templSize,
00914                                                         *(subjImg->imageFloat),
00915                                                         o_subjPoint.toDiff2D(),
00916                                                         sWidth,
00917                                                         startAngle, stopAngle, nSteps);
00918 
00919             }
00920         }
00921     } else {
00922         wxBusyCursor busy;
00923         res = vigra_ext::PointFineTune(*(tmplImg->image8), tmplPoint, templSize,
00924                                        *(subjImg->image8), o_subjPoint.toDiff2D(),
00925                                        sWidth);
00926     }
00927     // invert curvature. we always assume its a maxima, the curvature there is negative
00928     // however, we allow the user to specify a positive threshold, so we need to
00929     // invert it
00930     res.curv.x = - res.curv.x;
00931     res.curv.y = - res.curv.y;
00932 
00933     MainFrame::Get()->SetStatusText(wxString::Format(_("Point fine-tuned, angle: %.0f deg, correlation coefficient: %0.3f, curvature: %0.3f %0.3f "),
00934                                     res.maxAngle, res.maxi, res.curv.x, res.curv.y ),0);
00935     if (res.maxi < corrThresh ||res.curv.x < curvThresh || res.curv.y < curvThresh  )
00936     {
00937         // Bad correlation result.
00938 #if wxCHECK_VERSION(2, 9, 0)
00939         wxMessageDialog dlg(this,
00940             _("No similar point found."),
00941 #ifdef _WINDOWS
00942             _("Hugin"),
00943 #else
00944             wxT(""),
00945 #endif
00946             wxICON_ERROR | wxOK);
00947         dlg.SetExtendedMessage(wxString::Format(_("Check the similarity visually.\nCorrelation coefficient (%.3f) is lower than the threshold set in the preferences."),
00948                              res.maxi));
00949         dlg.ShowModal();
00950 #else
00951         wxMessageBox(
00952             wxString::Format(_("No similar point found. Check the similarity visually.\nCorrelation coefficient (%.3f) is lower than the threshold set in the preferences."),
00953                              res.maxi),
00954 #ifdef _WINDOWS
00955             _("Hugin"),
00956 #else
00957             wxT(""),
00958 #endif
00959             wxICON_ERROR | wxOK, this);
00960 #endif
00961         return false;
00962     }
00963 
00964     return true;
00965 }
00966 
00967 void CPEditorPanel::panoramaChanged(PT::Panorama &pano)
00968 {
00969     int nGui = m_cpModeChoice->GetCount();
00970     int nPano = pano.getNextCPTypeLineNumber()+1;
00971     DEBUG_DEBUG("mode choice: " << nGui << " entries, required: " << nPano);
00972 
00973     if (nGui > nPano)
00974     {
00975         m_cpModeChoice->Freeze();
00976         // remove some items.
00977         for (int i = nGui-1; i >=nPano-1; --i) {
00978             m_cpModeChoice->Delete(i);
00979         }
00980         if (nPano > 3) {
00981             m_cpModeChoice->SetString(nPano-1, _("Add new Line"));
00982         }
00983         m_cpModeChoice->Thaw();
00984     } else if (nGui < nPano) {
00985         m_cpModeChoice->Freeze();
00986         if (nGui > 3) {
00987             m_cpModeChoice->SetString(nGui-1, wxString::Format(_("Line %d"), nGui-1));
00988         }
00989         for (int i = nGui; i < nPano-1; i++) {
00990             m_cpModeChoice->Append(wxString::Format(_("Line %d"), i));
00991         }
00992         m_cpModeChoice->Append(_("Add new Line"));
00993         m_cpModeChoice->Thaw();
00994     }
00995     UpdateTransforms();
00996     DEBUG_TRACE("");
00997 }
00998 
00999 void CPEditorPanel::panoramaImagesChanged(Panorama &pano, const UIntSet &changed)
01000 {
01001     unsigned int nrImages = pano.getNrOfImages();
01002     unsigned int nrTabs = m_leftChoice->GetCount();
01003     DEBUG_TRACE("nrImages:" << nrImages << " nrTabs:" << nrTabs);
01004 
01005 #ifdef __WXMSW__
01006     int oldLeftSelection = m_leftChoice->GetSelection();
01007     int oldRightSelection = m_rightChoice->GetSelection();
01008 #endif
01009 
01010     if (nrImages == 0)
01011     {
01012         // disable controls
01013         m_cpModeChoice->Disable();
01014         m_addButton->Disable();
01015         m_delButton->Disable();
01016         m_autoAddCB->Disable();
01017         m_fineTuneCB->Disable();
01018         m_estimateCB->Disable();
01019         XRCCTRL(*this, "cp_editor_finetune_button", wxButton)->Disable();
01020         XRCCTRL(*this, "cp_editor_celeste_button", wxButton)->Disable();
01021         XRCCTRL(*this, "cp_editor_choice_zoom", wxChoice)->Disable();
01022         XRCCTRL(*this, "cp_editor_previous_img", wxButton)->Disable();
01023         XRCCTRL(*this, "cp_editor_next_img", wxButton)->Disable();
01024         m_leftChoice->Disable();
01025         m_rightChoice->Disable();
01026     }
01027     else
01028     {
01029         // enable controls
01030         m_cpModeChoice->Enable();
01031         m_autoAddCB->Enable();
01032         m_fineTuneCB->Enable();
01033         m_estimateCB->Enable();
01034         XRCCTRL(*this, "cp_editor_finetune_button", wxButton)->Enable();
01035         XRCCTRL(*this, "cp_editor_celeste_button", wxButton)->Enable();
01036         XRCCTRL(*this, "cp_editor_choice_zoom", wxChoice)->Enable();
01037         XRCCTRL(*this, "cp_editor_previous_img", wxButton)->Enable();
01038         XRCCTRL(*this, "cp_editor_next_img", wxButton)->Enable();
01039         m_leftChoice->Enable();
01040         m_rightChoice->Enable();
01041 
01042         ImageCache::getInstance().softFlush();
01043 
01044         for (unsigned int i=0; i < ((nrTabs < nrImages)? nrTabs: nrImages); i++) {
01045             wxFileName fileName(wxString (pano.getImage(i).getFilename().c_str(), HUGIN_CONV_FILENAME));
01046             m_leftChoice->SetString(i, wxString::Format(wxT("%d"), i) + wxT(". - ") + fileName.GetFullName());
01047             m_rightChoice->SetString(i, wxString::Format(wxT("%d"), i) + wxT(". - ") + fileName.GetFullName());
01048         }
01049         // wxChoice on windows looses the selection when setting new labels. Restore selection
01050 #ifdef __WXMSW__
01051         m_leftChoice->SetSelection(oldLeftSelection);
01052         m_rightChoice->SetSelection(oldRightSelection);
01053 #endif
01054         // add tab bar entries, if needed
01055         if (nrTabs < nrImages)
01056         {
01057             for (unsigned int i=nrTabs; i < nrImages; i++)
01058             {
01059                 wxFileName fileName(wxString (pano.getImage(i).getFilename().c_str(), HUGIN_CONV_FILENAME));
01060                 m_leftChoice->Append(wxString::Format(wxT("%d"), i) + wxT(". - ") + fileName.GetFullName());
01061                 m_rightChoice->Append(wxString::Format(wxT("%d"), i) + wxT(". - ") + fileName.GetFullName());
01062             }
01063         }
01064     }
01065     if (nrTabs > nrImages)
01066     {
01067         // remove tab bar entries if needed
01068         // we have to disable listening to notebook selection events,
01069         // else we might update to a noexisting image
01070         m_listenToPageChange = false;
01071         for (int i=nrTabs-1; i >= (int)nrImages; i--) {
01072             m_leftChoice->Delete(i);
01073             m_rightChoice->Delete(i);
01074         }
01075         m_listenToPageChange = true;
01076         if (nrImages > 0) {
01077             // select some other image if we deleted the current image
01078             if (m_leftImageNr >= nrImages) {
01079                 setLeftImage(nrImages -1);
01080             }
01081             if (m_rightImageNr >= nrImages) {
01082                 setRightImage(nrImages -1);
01083             }
01084         } else {
01085             DEBUG_DEBUG("setting no images");
01086             m_leftImageNr = UINT_MAX;
01087             m_leftFile = "";
01088             m_rightImageNr = UINT_MAX;
01089             m_rightFile = "";
01090             // no image anymore..
01091             m_leftImg->setImage(m_leftFile, CPImageCtrl::ROT0);
01092             m_rightImg->setImage(m_rightFile, CPImageCtrl::ROT0);
01093         }
01094     }
01095 
01096     // update changed images
01097     bool update(false);
01098     for(UIntSet::const_iterator it = changed.begin(); it != changed.end(); ++it) {
01099         unsigned int imgNr = *it;
01100         // we only need to update the view if the currently
01101         // selected images were changed.
01102         // changing the images via the tabbar will always
01103         // take the current state directly from the pano
01104         // object
01105         DEBUG_DEBUG("image changed "<< imgNr);
01106         double yaw = const_map_get(m_pano->getImageVariables(imgNr), "y").getValue();
01107         double pitch = const_map_get(m_pano->getImageVariables(imgNr), "p").getValue();
01108         double roll = const_map_get(m_pano->getImageVariables(imgNr), "r").getValue();
01109         CPImageCtrl::ImageRotation rot = GetRot(yaw, pitch, roll);
01110         if (m_leftImageNr == imgNr) {
01111             DEBUG_DEBUG("left image dirty "<< imgNr);
01112             if (m_leftFile != pano.getImage(imgNr).getFilename()
01113                 || m_leftRot != rot ) 
01114             {
01115                 m_leftRot = rot;
01116                 m_leftFile = pano.getImage(imgNr).getFilename();
01117                 m_leftImg->setImage(m_leftFile, m_leftRot);
01118             }
01119             update=true;
01120         }
01121 
01122         if (m_rightImageNr == imgNr) {
01123             DEBUG_DEBUG("right image dirty "<< imgNr);
01124             if (m_rightFile != pano.getImage(imgNr).getFilename()
01125                  || m_rightRot != rot ) 
01126             {
01127                 m_rightRot = rot;
01128                 m_rightFile = pano.getImage(imgNr).getFilename();
01129                 m_rightImg->setImage(m_rightFile, m_rightRot);
01130             }
01131             update=true;
01132         }
01133     }
01134 
01135     // if there is no selection, select the first one.
01136     if (m_rightImageNr == UINT_MAX && nrImages > 0) {
01137         setRightImage(0);
01138     }
01139     if (m_leftImageNr == UINT_MAX && nrImages > 0) {
01140         setLeftImage(0);
01141     }
01142 
01143     if (update || nrImages == 0) {
01144         UpdateDisplay(false);
01145     }
01146     m_leftChoice->CalcCPDistance(m_pano);
01147     m_rightChoice->CalcCPDistance(m_pano);
01148 }
01149 
01150 void CPEditorPanel::UpdateDisplay(bool newPair)
01151 {
01152     DEBUG_DEBUG("")
01153     int fI = m_leftChoice->GetSelection();
01154     int sI = m_rightChoice->GetSelection();
01155 
01156     // valid selection and already set left image
01157     if (fI >= 0 && m_leftImageNr != UINT_MAX)
01158     {
01159         // set image number to selection
01160         m_leftImageNr = (unsigned int) fI;
01161     }
01162     // valid selection and already set right image
01163     if (sI >= 0 && m_rightImageNr != UINT_MAX)
01164     {
01165         // set image number to selection
01166         m_rightImageNr = (unsigned int) sI;
01167     }
01168     // reset selection
01169     m_x1Text->Clear();
01170     m_y1Text->Clear();
01171     m_x2Text->Clear();
01172     m_y2Text->Clear();
01173     if (m_cpModeChoice->GetSelection() < 3) {
01174         m_cpModeChoice->SetSelection(0);
01175     }
01176 
01177     m_leftImg->setSameImage(m_leftImageNr==m_rightImageNr);
01178     m_rightImg->setSameImage(m_leftImageNr==m_rightImageNr);
01179 
01180     // update control points
01181     const PT::CPVector & controlPoints = m_pano->getCtrlPoints();
01182     currentPoints.clear();
01183     mirroredPoints.clear();
01184 
01185     // create a list of all control points
01186     unsigned int i = 0;
01187     m_leftImg->clearCtrlPointList();
01188     m_rightImg->clearCtrlPointList();
01189     for (PT::CPVector::const_iterator it = controlPoints.begin(); it != controlPoints.end(); ++it) {
01190         PT::ControlPoint point = *it;
01191         if ((point.image1Nr == m_leftImageNr) && (point.image2Nr == m_rightImageNr)){
01192             m_leftImg->setCtrlPoint(point, false);
01193             m_rightImg->setCtrlPoint(point, true);
01194             currentPoints.push_back(make_pair(it - controlPoints.begin(), *it));
01195             i++;
01196         } else if ((point.image2Nr == m_leftImageNr) && (point.image1Nr == m_rightImageNr)){
01197             point.mirror();
01198             mirroredPoints.insert(i);
01199             m_leftImg->setCtrlPoint(point, true);
01200             m_rightImg->setCtrlPoint(point, false);
01201             currentPoints.push_back(std::make_pair(it - controlPoints.begin(), point));
01202             i++;
01203         }
01204     }
01205     m_leftImg->update();
01206     m_rightImg->update();
01207 
01208     // put these control points into our listview.
01209     unsigned int selectedCP = UINT_MAX;
01210     for ( int i=0; i < m_cpList->GetItemCount() ; i++ ) {
01211       if ( m_cpList->GetItemState( i, wxLIST_STATE_SELECTED ) ) {
01212         selectedCP = i;            // remembers the old selection
01213       }
01214     }
01215     m_cpList->Freeze();
01216     m_cpList->DeleteAllItems();
01217 
01218     for (unsigned int i=0; i < currentPoints.size(); ++i) {
01219         const ControlPoint & p = currentPoints[i].second;
01220         DEBUG_DEBUG("inserting LVItem " << i);
01221         m_cpList->InsertItem(i,wxString::Format(wxT("%d"),i));
01222         m_cpList->SetItem(i,1,wxString::Format(wxT("%.2f"),p.x1));
01223         m_cpList->SetItem(i,2,wxString::Format(wxT("%.2f"),p.y1));
01224         m_cpList->SetItem(i,3,wxString::Format(wxT("%.2f"),p.x2));
01225         m_cpList->SetItem(i,4,wxString::Format(wxT("%.2f"),p.y2));
01226         wxString mode;
01227         switch (p.mode) {
01228         case ControlPoint::X_Y:
01229             mode = _("normal");
01230             break;
01231         case ControlPoint::X:
01232             mode = _("vert. Line");
01233             break;
01234         case ControlPoint::Y:
01235             mode = _("horiz. Line");
01236             break;
01237         default:
01238             mode = wxString::Format(_("Line %d"), p.mode);
01239             break;
01240         }
01241         m_cpList->SetItem(i,5,mode);
01242         m_cpList->SetItem(i,6,wxString::Format(wxT("%.2f"),p.error));
01243     }
01244 
01245     if ( selectedCP < (unsigned int) m_cpList->GetItemCount() && ! newPair) {
01246         // sets an old selection again, only if the images have not changed
01247         m_cpList->SetItemState( selectedCP,
01248                                 wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
01249         m_cpList->EnsureVisible(selectedCP);
01250         m_selectedPoint = selectedCP;
01251         EnablePointEdit(true);
01252 
01253         const ControlPoint & p = currentPoints[m_selectedPoint].second;
01254         m_x1Text->SetValue(wxString::Format(wxT("%.2f"),p.x1));
01255         m_y1Text->SetValue(wxString::Format(wxT("%.2f"),p.y1));
01256         m_x2Text->SetValue(wxString::Format(wxT("%.2f"),p.x2));
01257         m_y2Text->SetValue(wxString::Format(wxT("%.2f"),p.y2));
01258         m_cpModeChoice->SetSelection(p.mode);
01259         m_leftImg->selectPoint(m_selectedPoint);
01260         m_rightImg->selectPoint(m_selectedPoint);
01261 
01262     } else {
01263         m_selectedPoint = UINT_MAX;
01264         EnablePointEdit(false);
01265     }
01266 
01267     for ( int j=0; j < m_cpList->GetColumnCount() ; j++ )
01268     {
01269         //get saved width
01270         // -1 is auto
01271         int width = wxConfigBase::Get()->Read(wxString::Format( wxT("/CPEditorPanel/ColumnWidth%d"), j ), -1);
01272         if(width != -1)
01273             m_cpList->SetColumnWidth(j, width);
01274     }
01275 
01276     m_cpList->Thaw();
01277 }
01278 
01279 void CPEditorPanel::EnablePointEdit(bool state)
01280 {
01281     m_delButton->Enable(state);
01282     XRCCTRL(*this, "cp_editor_finetune_button", wxButton)->Enable(state);
01283     m_x1Text->Enable(state);
01284     m_y1Text->Enable(state);
01285     m_x2Text->Enable(state);
01286     m_y2Text->Enable(state);
01287     m_cpModeChoice->Enable(state);
01288 }
01289 
01290 void CPEditorPanel::OnTextPointChange(wxCommandEvent &e)
01291 {
01292     DEBUG_TRACE("");
01293     // find selected point
01294     long item = -1;
01295     item = m_cpList->GetNextItem(item,
01296                                  wxLIST_NEXT_ALL,
01297                                  wxLIST_STATE_SELECTED);
01298     // no selected item.
01299     if (item == -1) {
01300         return;
01301     }
01302     unsigned int nr = (unsigned int) item;
01303     assert(nr < currentPoints.size());
01304     ControlPoint cp = currentPoints[nr].second;
01305 
01306     // update point state
01307     double oldValue=cp.x1;
01308     bool valid_input=str2double(m_x1Text->GetValue(), cp.x1);
01309     if(valid_input)
01310         valid_input=(cp.x1>=0) && (cp.x1<=m_pano->getSrcImage(cp.image1Nr).getWidth());
01311     if (!valid_input) {
01312         m_x1Text->Clear();
01313         *m_x1Text << oldValue;
01314         return;
01315     }
01316     oldValue=cp.y1;
01317     valid_input=str2double(m_y1Text->GetValue(), cp.y1);
01318     if(valid_input)
01319         valid_input=(cp.y1>=0) && (cp.y1<=m_pano->getSrcImage(cp.image1Nr).getHeight());
01320     if (!valid_input) {
01321         m_y1Text->Clear();
01322         *m_y1Text << oldValue;
01323         return;
01324     }
01325     oldValue=cp.x2;
01326     valid_input=str2double(m_x2Text->GetValue(), cp.x2);
01327     if(valid_input)
01328         valid_input=(cp.x2>=0) && (cp.x2<=m_pano->getSrcImage(cp.image2Nr).getWidth());
01329     if (!valid_input) {
01330         m_x2Text->Clear();
01331         *m_x2Text << oldValue;
01332         return;
01333     }
01334     oldValue=cp.y2;
01335     valid_input=str2double(m_y2Text->GetValue(), cp.y2);
01336     if(valid_input)
01337         valid_input=(cp.y2>=0) && (cp.y2<=m_pano->getSrcImage(cp.image1Nr).getHeight());
01338     if (!valid_input) {
01339         m_y2Text->Clear();
01340         *m_y2Text << oldValue;
01341         return;
01342     }
01343 
01344     cp.mode = m_cpModeChoice->GetSelection();
01345     // if point was mirrored, reverse before setting it.
01346     if (set_contains(mirroredPoints, nr)) {
01347         cp.mirror();
01348     }
01349     GlobalCmdHist::getInstance().addCommand(
01350         new PT::ChangeCtrlPointCmd(*m_pano, currentPoints[nr].first, cp)
01351         );
01352 
01353 }
01354 
01355 void CPEditorPanel::OnLeftChoiceChange(wxCommandEvent & e)
01356 {
01357     DEBUG_TRACE("OnLeftChoiceChange() to " << e.GetSelection());
01358     if (m_listenToPageChange && e.GetSelection() >= 0) {
01359         setLeftImage((unsigned int) e.GetSelection());
01360     }
01361 }
01362 
01363 void CPEditorPanel::OnRightChoiceChange(wxCommandEvent & e)
01364 {
01365     DEBUG_TRACE("OnRightChoiceChange() to " << e.GetSelection());
01366     if (m_listenToPageChange && e.GetSelection() >= 0) {
01367         setRightImage((unsigned int) e.GetSelection());
01368     }
01369 }
01370 void CPEditorPanel::OnCPListSelect(wxListEvent & ev)
01371 {
01372     int t = ev.GetIndex();
01373     DEBUG_TRACE("selected: " << t);
01374     if (t >=0) {
01375         SelectLocalPoint((unsigned int) t);
01376         changeState(NO_POINT);
01377     }
01378     EnablePointEdit(true);
01379 }
01380 
01381 void CPEditorPanel::OnCPListDeselect(wxListEvent & ev)
01382 {
01383     // disable controls
01384     // when doing changes to this procedure do also check
01385     // interaction with control point table
01386     // e.g. m_selectedPoint=UINT_MAX will result in a endless loop and crash
01387     changeState(NO_POINT);
01388     EnablePointEdit(false);
01389     m_leftImg->deselect();
01390     m_rightImg->deselect();
01391 }
01392 
01393 void CPEditorPanel::OnZoom(wxCommandEvent & e)
01394 {
01395     double factor;
01396     switch (e.GetSelection()) {
01397     case 0:
01398         factor = 1;
01399         m_detailZoomFactor = factor;
01400         break;
01401     case 1:
01402         // fit to window
01403         factor = 0;
01404         break;
01405     case 2:
01406         factor = 2;
01407         m_detailZoomFactor = factor;
01408         break;
01409     case 3:
01410         factor = 1.5;
01411         m_detailZoomFactor = factor;
01412         break;
01413     case 4:
01414         factor = 0.75;
01415         break;
01416     case 5:
01417         factor = 0.5;
01418         break;
01419     case 6:
01420         factor = 0.25;
01421         break;
01422     default:
01423         DEBUG_ERROR("unknown scale factor");
01424         factor = 1;
01425     }
01426     m_leftImg->setScale(factor);
01427     m_rightImg->setScale(factor);
01428     // if a point is selected, keep it in view
01429     if (m_selectedPoint < UINT_MAX) {
01430         SelectLocalPoint(m_selectedPoint);
01431     }
01432 }
01433 
01434 void CPEditorPanel::OnKey(wxKeyEvent & e)
01435 {
01436     DEBUG_DEBUG("key " << e.GetKeyCode()
01437                 << " origin: id:" << e.GetId() << " obj: "
01438                 << e.GetEventObject());
01439 
01440     if (e.m_keyCode == WXK_DELETE){
01441         DEBUG_DEBUG("Delete pressed");
01442         // remove working points..
01443         if (cpCreationState != NO_POINT) {
01444             changeState(NO_POINT);
01445         } else {
01446             // remove selected point
01447             // find selected point
01448             long item = -1;
01449             item = m_cpList->GetNextItem(item,
01450                                          wxLIST_NEXT_ALL,
01451                                          wxLIST_STATE_SELECTED);
01452             // no selected item.
01453             if (item == -1) {
01454                 wxBell();
01455                 return;
01456             }
01457             unsigned int pNr = localPNr2GlobalPNr((unsigned int) item);
01458             DEBUG_DEBUG("about to delete point " << pNr);
01459             GlobalCmdHist::getInstance().addCommand(
01460                 new PT::RemoveCtrlPointCmd(*m_pano,pNr)
01461                 );
01462         }
01463     } else if (e.m_keyCode == '0') {
01464         wxCommandEvent dummy;
01465         dummy.SetInt(1);
01466         OnZoom(dummy);
01467         XRCCTRL(*this,"cp_editor_choice_zoom",wxChoice)->SetSelection(1);
01468     } else if (e.m_keyCode == '1') {
01469         wxCommandEvent dummy;
01470         dummy.SetInt(0);
01471         OnZoom(dummy);
01472         XRCCTRL(*this,"cp_editor_choice_zoom",wxChoice)->SetSelection(0);
01473     } else if (e.m_keyCode == '2') {
01474         wxCommandEvent dummy;
01475         dummy.SetInt(2);
01476         OnZoom(dummy);
01477         XRCCTRL(*this,"cp_editor_choice_zoom",wxChoice)->SetSelection(2);
01478     } else if (e.CmdDown() && e.GetKeyCode() == WXK_LEFT) {
01479         // move to previous
01480         wxCommandEvent dummy;
01481         OnPrevImg(dummy);
01482     } else if (e.CmdDown() && e.GetKeyCode() == WXK_RIGHT) {
01483         // move to next
01484         wxCommandEvent dummy;
01485         OnNextImg(dummy);
01486     } else if (e.GetKeyCode() == 'f') {
01487         bool left =  e.GetEventObject() == m_leftImg;
01488         if (cpCreationState == NO_POINT) {
01489             FineTuneSelectedPoint(left);
01490         } else if (cpCreationState == BOTH_POINTS_SELECTED) { 
01491             FineTuneNewPoint(left);
01492         }
01493     } else if (e.GetKeyCode() == 'g') {
01494         // generate keypoints
01495         long th = wxGetNumberFromUser(_("Create control points.\nTo create less points,\nenter a higher number."), _("Corner Detection threshold"), _("Create control points"), 400, 0, 32000);
01496         if (th == -1) {
01497             return;
01498         }
01499         long scale = wxGetNumberFromUser(_("Create control points"), _("Corner Detection scale"), _("Create control points"), 2);
01500         if (scale == -1) {
01501             return;
01502         }
01503 
01504         try {
01505             wxBusyCursor busy;
01506             DEBUG_DEBUG("corner threshold: " << th << "  scale: " << scale);
01507             GlobalCmdHist::getInstance().addCommand(
01508                     new wxAddCtrlPointGridCmd(*m_pano, m_leftImageNr, m_rightImageNr, scale, th)
01509                             );
01510         } catch (std::exception & e) {
01511             wxLogError(_("Error during control point creation:\n") + wxString(e.what(), wxConvLocal));
01512         }
01513     } else {
01514         e.Skip();
01515     }
01516 }
01517 
01518 void CPEditorPanel::OnAddButton(wxCommandEvent & e)
01519 {
01520     // check if the point can be created..
01521     if (cpCreationState == BOTH_POINTS_SELECTED) {
01522         CreateNewPoint();
01523     }
01524 }
01525 
01526 void CPEditorPanel::OnDeleteButton(wxCommandEvent & e)
01527 {
01528     DEBUG_TRACE("");
01529     // check if a point has been selected, but not added.
01530     if (cpCreationState != NO_POINT) {
01531         changeState(NO_POINT);
01532     } else {
01533         // find selected point
01534         long item = -1;
01535         item = m_cpList->GetNextItem(item,
01536                                      wxLIST_NEXT_ALL,
01537                                      wxLIST_STATE_SELECTED);
01538         // no selected item.
01539         if (item == -1) {
01540             wxBell();
01541             return;
01542         }
01543         // get the global point number
01544         unsigned int pNr = localPNr2GlobalPNr((unsigned int) item);
01545 
01546         GlobalCmdHist::getInstance().addCommand(
01547             new PT::RemoveCtrlPointCmd(*m_pano,pNr )
01548             );
01549         m_leftChoice->CalcCPDistance(m_pano);
01550         m_rightChoice->CalcCPDistance(m_pano);
01551     }
01552 }
01553 
01554 // show a global control point
01555 void CPEditorPanel::ShowControlPoint(unsigned int cpNr)
01556 {
01557     const ControlPoint & p = m_pano->getCtrlPoint(cpNr);
01558     setLeftImage(p.image1Nr);
01559     setRightImage(p.image2Nr);
01560     // FIXME reset display state
01561     changeState(NO_POINT);
01562 
01563     SelectGlobalPoint(cpNr);
01564 }
01565 
01566 void CPEditorPanel::changeState(CPCreationState newState)
01567 {
01568     DEBUG_TRACE(cpCreationState << " --> " << newState);
01569     // handle global state changes.
01570     bool fineTune = m_fineTuneCB->IsChecked() && (m_leftImageNr != m_rightImageNr);
01571     switch(newState) {
01572     case NO_POINT:
01573         // disable all drawing search boxes.
01574         m_leftImg->showSearchArea(false);
01575         m_rightImg->showSearchArea(false);
01576         // but draw template size, if fine-tune enabled
01577         m_leftImg->showTemplateArea(fineTune);
01578         m_rightImg->showTemplateArea(fineTune);
01579         m_addButton->Enable(false);
01580         if (m_selectedPoint < UINT_MAX) {
01581             m_delButton->Enable(true);
01582         } else {
01583             m_delButton->Enable(false);
01584         }
01585         if (cpCreationState != NO_POINT) {
01586             // reset zoom to previous setting
01587             wxCommandEvent tmpEvt;
01588             tmpEvt.SetInt(XRCCTRL(*this,"cp_editor_choice_zoom",wxChoice)->GetSelection());
01589             OnZoom(tmpEvt);
01590             m_leftImg->clearNewPoint();
01591             m_rightImg->clearNewPoint();
01592         }
01593         break;
01594     case LEFT_POINT:
01595         // disable search area on left window
01596         m_leftImg->showSearchArea(false);
01597         // show search area on right window
01598         m_rightImg->showSearchArea(fineTune);
01599 
01600         // show template area
01601         m_leftImg->showTemplateArea(fineTune);
01602         m_rightImg->showTemplateArea(false);
01603 
01604         // unselect point
01605         ClearSelection();
01606         m_addButton->Enable(false);
01607         m_delButton->Enable(false);
01608         MainFrame::Get()->SetStatusText(_("Select point in right image"),0);
01609         break;
01610     case RIGHT_POINT:
01611         m_leftImg->showSearchArea(fineTune);
01612         m_rightImg->showSearchArea(false);
01613 
01614         m_leftImg->showTemplateArea(false);
01615         m_rightImg->showTemplateArea(fineTune);
01616 
01617         ClearSelection();
01618         m_addButton->Enable(false);
01619         m_delButton->Enable(false);
01620         MainFrame::Get()->SetStatusText(_("Select point in left image"),0);
01621         break;
01622     case LEFT_POINT_RETRY:
01623     case RIGHT_POINT_RETRY:
01624         m_leftImg->showSearchArea(false);
01625         m_rightImg->showSearchArea(false);
01626         // but draw template size, if fine-tune enabled
01627         m_leftImg->showTemplateArea(false);
01628         m_rightImg->showTemplateArea(false);
01629         m_addButton->Enable(false);
01630         m_delButton->Enable(false);
01631         break;
01632     case BOTH_POINTS_SELECTED:
01633         m_leftImg->showTemplateArea(false);
01634         m_rightImg->showTemplateArea(false);
01635         m_leftImg->showSearchArea(false);
01636         m_rightImg->showSearchArea(false);
01637         m_addButton->Enable(true);
01638         m_delButton->Enable(false);
01639     }
01640     // apply the change
01641     cpCreationState = newState;
01642 }
01643 
01644 void CPEditorPanel::OnPrevImg(wxCommandEvent & e)
01645 {
01646     if (m_pano->getNrOfImages() < 2) return;
01647     int nImgs = m_pano->getNrOfImages();
01648     int left = m_leftImageNr -1;
01649     int right = m_rightImageNr -1;
01650     if (left < 0) {
01651         left += nImgs;
01652     } else if (left >= nImgs) {
01653         left -= nImgs;
01654     }
01655 
01656     if (right < 0) {
01657         right += nImgs;
01658     } else if (right >= nImgs) {
01659         right -= nImgs;
01660     }
01661     setLeftImage((unsigned int) left);
01662     setRightImage((unsigned int) right);
01663 }
01664 
01665 void CPEditorPanel::OnNextImg(wxCommandEvent & e)
01666 {
01667     if (m_pano->getNrOfImages() < 2) return;
01668     int nImgs = m_pano->getNrOfImages();
01669     int left = m_leftImageNr + 1;
01670     int right = m_rightImageNr + 1;
01671     if (left < 0) {
01672         left += nImgs;
01673     } else if (left >= nImgs) {
01674         left -= nImgs;
01675     }
01676 
01677     if (right < 0) {
01678         right += nImgs;
01679     } else if (right >= nImgs) {
01680         right -= nImgs;
01681     }
01682     setLeftImage((unsigned int) left);
01683     setRightImage((unsigned int) right);
01684 }
01685 
01686 void CPEditorPanel::OnFineTuneButton(wxCommandEvent & e)
01687 {
01688     if (cpCreationState == NO_POINT) {
01689         FineTuneSelectedPoint(false);
01690     } else if (cpCreationState == BOTH_POINTS_SELECTED) {
01691         FineTuneNewPoint(false);
01692     }
01693 }
01694 
01695 void CPEditorPanel::OnCelesteButton(wxCommandEvent & e)
01696 {
01697     if (currentPoints.size() == 0)
01698     {
01699         wxMessageBox(_("Cannot run celeste without at least one control point connecting the two images"),_("Error"));
01700         cout << "Cannot run celeste without at least one control point connecting the two images" << endl;
01701     }
01702     else
01703     {
01704         ProgressReporterDialog progress(4, _("Running Celeste"), _("Running Celeste"),this);
01705         MainFrame::Get()->SetStatusText(_("searching for cloud-like control points..."),0);
01706         progress.increaseProgress(1.0, std::wstring(wxString(_("Loading model file")).wc_str(wxConvLocal)));
01707 
01708         struct celeste::svm_model* model=MainFrame::Get()->GetSVMModel();
01709         if(model==NULL)
01710         {
01711             MainFrame::Get()->SetStatusText(wxT(""),0);
01712             return;
01713         };
01714 
01715         // Get Celeste parameters
01716         wxConfigBase *cfg = wxConfigBase::Get();
01717         // SVM threshold
01718         double threshold = HUGIN_CELESTE_THRESHOLD;
01719         cfg->Read(wxT("/Celeste/Threshold"), &threshold, HUGIN_CELESTE_THRESHOLD);
01720 
01721         // Mask resolution - 1 sets it to fine
01722         bool t = (cfg->Read(wxT("/Celeste/Filter"), HUGIN_CELESTE_FILTER) == 0);
01723         int radius=(t)?10:20;
01724         DEBUG_TRACE("Running Celeste");
01725 
01726         progress.increaseProgress(1.0, std::wstring(wxString(_("Running Celeste")).wc_str(wxConvLocal)));
01727         // Image to analyse
01728         ImageCache::EntryPtr img=ImageCache::getInstance().getImage(m_pano->getImage(m_leftImageNr).getFilename());
01729         vigra::UInt16RGBImage in;
01730         if(img->image16->width()>0)
01731         {
01732             in.resize(img->image16->size());
01733             vigra::copyImage(srcImageRange(*(img->image16)),destImage(in));
01734         }
01735         else
01736         {
01737             ImageCache::ImageCacheRGB8Ptr im8=img->get8BitImage();
01738             in.resize(im8->size());
01739             vigra::transformImage(srcImageRange(*im8),destImage(in),vigra::functor::Arg1()*vigra::functor::Param(65535/255));
01740         };
01741         UIntSet cloudCP=celeste::getCelesteControlPoints(model,in,currentPoints,radius,threshold,800);
01742         in.resize(0,0);
01743         progress.increaseProgress(1.0, std::wstring(wxString(_("Running Celeste")).wc_str(wxConvLocal)));
01744 
01745         if(cloudCP.size()>0)
01746         {
01747             GlobalCmdHist::getInstance().addCommand(
01748                 new PT::RemoveCtrlPointsCmd(*m_pano,cloudCP)
01749                 );
01750         };
01751 
01752         progress.increaseProgress(1.0, std::wstring(wxString(_("Running Celeste")).wc_str(wxConvLocal)));
01753         wxMessageBox(wxString::Format(_("Removed %d control points"), cloudCP.size()), _("Celeste result"),wxOK|wxICON_INFORMATION,this);
01754         DEBUG_TRACE("Finished running Celeste");
01755         MainFrame::Get()->SetStatusText(wxT(""),0);
01756     }
01757 }
01758 
01759 FDiff2D CPEditorPanel::LocalFineTunePoint(unsigned int srcNr,
01760                                           const Diff2D & srcPnt,
01761                                           unsigned int moveNr,
01762                                           const FDiff2D & movePnt)
01763 {
01764     long templWidth = wxConfigBase::Get()->Read(wxT("/Finetune/TemplateSize"),HUGIN_FT_TEMPLATE_SIZE);
01765     long sWidth = templWidth + wxConfigBase::Get()->Read(wxT("/Finetune/LocalSearchWidth"),HUGIN_FT_LOCAL_SEARCH_WIDTH);
01766     CorrelationResult result;
01767     PointFineTune(srcNr,
01768                   srcPnt,
01769                   templWidth,
01770                   moveNr,
01771                   movePnt,
01772                   sWidth,
01773                   result);
01774     return result.maxpos;
01775 }
01776 
01777 void CPEditorPanel::FineTuneSelectedPoint(bool left)
01778 {
01779     DEBUG_DEBUG(" selected Point: " << m_selectedPoint);
01780     if (m_selectedPoint == UINT_MAX) return;
01781     DEBUG_ASSERT(m_selectedPoint < currentPoints.size());
01782 
01783     ControlPoint cp = currentPoints[m_selectedPoint].second;
01784 
01785     unsigned int srcNr = cp.image1Nr;
01786     unsigned int moveNr = cp.image2Nr;
01787     Diff2D srcPnt(roundi(cp.x1), roundi(cp.y1));
01788     Diff2D movePnt(roundi(cp.x2), roundi(cp.y2));
01789     if (left) {
01790         srcNr = cp.image2Nr;
01791         moveNr = cp.image1Nr;
01792         srcPnt = Diff2D(roundi(cp.x2), roundi(cp.y2));
01793         movePnt = Diff2D(roundi(cp.x1), roundi(cp.y1));
01794     }
01795 
01796     FDiff2D result = LocalFineTunePoint(srcNr, srcPnt, moveNr, movePnt);
01797 
01798     if (left) {
01799        cp.x1 = result.x;
01800        cp.y1 = result.y;
01801        cp.x2 = srcPnt.x;
01802        cp.y2 = srcPnt.y;
01803     } else {
01804        cp.x2 = result.x;
01805        cp.y2 = result.y;
01806        cp.x1 = srcPnt.x;
01807        cp.y1 = srcPnt.y;
01808     }
01809 
01810     // if point was mirrored, reverse before setting it.
01811     if (set_contains(mirroredPoints, m_selectedPoint)) {
01812         cp.mirror();
01813     }
01814     GlobalCmdHist::getInstance().addCommand(
01815         new PT::ChangeCtrlPointCmd(*m_pano, currentPoints[m_selectedPoint].first, cp)
01816         );
01817 }
01818 
01819 
01820 void CPEditorPanel::FineTuneNewPoint(bool left)
01821 {
01822     if (!(cpCreationState == RIGHT_POINT_RETRY ||
01823           cpCreationState == LEFT_POINT_RETRY ||
01824           cpCreationState == BOTH_POINTS_SELECTED))
01825     {
01826         return;
01827     }
01828 
01829     FDiff2D leftP = m_leftImg->getNewPoint();
01830     FDiff2D rightP = m_rightImg->getNewPoint();
01831 
01832     unsigned int srcNr = m_leftImageNr;
01833     Diff2D srcPnt(leftP.toDiff2D());
01834     unsigned int moveNr = m_rightImageNr;
01835     Diff2D movePnt(rightP.toDiff2D());
01836     if (left) {
01837         srcNr = m_rightImageNr;
01838         srcPnt = rightP.toDiff2D();
01839         moveNr = m_leftImageNr;
01840         movePnt = leftP.toDiff2D();
01841     }
01842 
01843     FDiff2D result = LocalFineTunePoint(srcNr, srcPnt, moveNr, movePnt);
01844 
01845     if (left) {
01846         m_leftImg->setNewPoint(result);
01847         m_leftImg->update();
01848         m_rightImg->setNewPoint(srcPnt);
01849         m_rightImg->update();
01850 
01851     } else {
01852         m_rightImg->setNewPoint(result);
01853         m_rightImg->update();
01854         m_leftImg->setNewPoint(srcPnt);
01855         m_leftImg->update();
01856     }
01857 }
01858 
01859 FDiff2D CPEditorPanel::EstimatePoint(const FDiff2D & p, bool left)
01860 {
01861     int imgNr = left? m_rightImageNr : m_leftImageNr;
01862     const SrcPanoImage & img = m_pano->getImage(imgNr);
01863     FDiff2D t;
01864     if (currentPoints.size() == 0) {
01865         DEBUG_WARN("Cannot estimate position without at least one point");
01866         return FDiff2D(0,0);
01867     }
01868 
01869     for (HuginBase::CPointVector::const_iterator it = currentPoints.begin(); it != currentPoints.end(); ++it) {
01870         t.x += it->second.x2 - it->second.x1;
01871         t.y += it->second.y2 - it->second.y1;
01872     }
01873     t.x /= currentPoints.size();
01874     t.y /= currentPoints.size();
01875     DEBUG_DEBUG("estimated translation: x: " << t.x << " y: " << t.y);
01876 
01877     if (left) {
01878         t.x += p.x;
01879         t.y += p.y;
01880     } else {
01881         t.x = p.x - t.x;
01882         t.y = p.y - t.y;
01883     }
01884 
01885     // clip to fit to
01886     if (t.x < 0) t.x=0;
01887     if (t.y < 0) t.y=0;
01888     if (t.x > img.getWidth()) t.x = img.getWidth();
01889     if (t.y > img.getHeight()) t.y = img.getHeight();
01890     DEBUG_DEBUG("estimated point " << t.x << "," << t.y);
01891     return t;
01892 }
01893 
01894 void CPEditorPanel::OnColumnWidthChange( wxListEvent & e )
01895 {
01896     int colNum = e.GetColumn();
01897     wxConfigBase::Get()->Write( wxString::Format(wxT("/CPEditorPanel/ColumnWidth%d"),colNum), m_cpList->GetColumnWidth(colNum) );
01898 }
01899 
01900 CPImageCtrl::ImageRotation CPEditorPanel::GetRot(double yaw, double pitch, double roll)
01901 {
01902     CPImageCtrl::ImageRotation rot = CPImageCtrl::ROT0;
01903     // normalize roll angle
01904     while (roll > 360) roll-= 360;
01905     while (roll < 0) roll += 360;
01906 
01907     while (pitch > 180) pitch -= 360;
01908     while (pitch < -180) pitch += 360;
01909     bool headOver = (pitch > 90 || pitch < -90);
01910 
01911     if (wxConfig::Get()->Read(wxT("/CPEditorPanel/AutoRot"),1L)) {
01912         if (roll >= 315 || roll < 45) {
01913             rot = headOver ? CPImageCtrl::ROT180 : CPImageCtrl::ROT0;
01914         } else if (roll >= 45 && roll < 135) {
01915             rot = headOver ? CPImageCtrl::ROT270 : CPImageCtrl::ROT90;
01916         } else if (roll >= 135 && roll < 225) {
01917             rot = headOver ? CPImageCtrl::ROT0 : CPImageCtrl::ROT180;
01918         } else {
01919             rot = headOver ? CPImageCtrl::ROT90 : CPImageCtrl::ROT270;
01920         }
01921     }
01922     return rot;
01923 }
01924 
01925 IMPLEMENT_DYNAMIC_CLASS(CPEditorPanel, wxPanel)
01926 
01927 CPEditorPanelXmlHandler::CPEditorPanelXmlHandler()
01928                 : wxXmlResourceHandler()
01929 {
01930     AddWindowStyles();
01931 }
01932 
01933 wxObject *CPEditorPanelXmlHandler::DoCreateResource()
01934 {
01935     XRC_MAKE_INSTANCE(cp, CPEditorPanel)
01936 
01937     cp->Create(m_parentAsWindow,
01938                    GetID(),
01939                    GetPosition(), GetSize(),
01940                    GetStyle(wxT("style")),
01941                    GetName());
01942 
01943     SetupWindow( cp);
01944 
01945     return cp;
01946 }
01947 
01948 bool CPEditorPanelXmlHandler::CanHandle(wxXmlNode *node)
01949 {
01950     return IsOfClass(node, wxT("CPEditorPanel"));
01951 }
01952 
01953 IMPLEMENT_DYNAMIC_CLASS(CPEditorPanelXmlHandler, wxXmlResourceHandler)
01954 

Generated on Wed Jul 30 01:25:36 2014 for Hugintrunk by  doxygen 1.3.9.1