CPListFrame.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00027 #include <config.h>
00028 #include "panoinc_WX.h"
00029 #include "panoinc.h"
00030 
00031 #include <algorithm>
00032 #include <utility>
00033 #include <functional>
00034 
00035 #include "base_wx/wxPlatform.h"
00036 #include "hugin/CPListFrame.h"
00037 #include "hugin/MainFrame.h"
00038 #include "hugin/CommandHistory.h"
00039 #include "hugin/huginApp.h"
00040 
00041 using namespace PT;
00042 using namespace std;
00043 using namespace hugin_utils;
00044 
00045 class DelKeyHandler: public wxEvtHandler
00046 {
00047 public:
00048     DelKeyHandler(CPListFrame & list)
00049         : m_list(list)
00050         {
00051         }
00052 
00053     void OnKey(wxKeyEvent & e)
00054         {
00055             switch(e.m_keyCode)
00056             {
00057                 case WXK_DELETE:
00058                     m_list.DeleteSelected();
00059                     break;
00060                 case 1: //Ctrl+A
00061                     m_list.SelectAll();
00062                     break;
00063                 default:
00064                     e.Skip();
00065             }
00066         }
00067 
00068 private:
00069     CPListFrame & m_list;
00070 
00071     DECLARE_EVENT_TABLE()
00072 
00073 };
00074 
00075 BEGIN_EVENT_TABLE(DelKeyHandler, wxEvtHandler)
00076     EVT_CHAR(DelKeyHandler::OnKey)
00077 END_EVENT_TABLE()
00078 
00079 static Panorama * g_pano;
00080 
00081 #if wxCHECK_VERSION(2,9,2)
00082 #define COMPARETYPEITEM wxIntPtr
00083 #define COMPARETYPESORTDATA wxIntPtr
00084 #else
00085 #if wxCHECK_VERSION(2,9,0)
00086 #define COMPARETYPEITEM long
00087 #define COMPARETYPESORTDATA wxIntPtr
00088 #else
00089 #define COMPARETYPEITEM long
00090 #define COMPARETYPESORTDATA long
00091 #endif
00092 #endif
00093 
00094 static int wxCALLBACK compareError(COMPARETYPEITEM item1, COMPARETYPEITEM item2, COMPARETYPESORTDATA sortData)
00095 {
00096     const ControlPoint &p1 = g_pano->getCtrlPoint(item1);
00097     const ControlPoint &p2 = g_pano->getCtrlPoint(item2);
00098     if (p1.error < p2.error)
00099         return -1;
00100     else if (p1.error > p2.error)
00101         return 1;
00102     else
00103         return 0;
00104 }
00105 
00106 static int wxCALLBACK compareErrorGreater(COMPARETYPEITEM item1, COMPARETYPEITEM item2, COMPARETYPESORTDATA sortData)
00107 {
00108     const ControlPoint &p1 = g_pano->getCtrlPoint(item1);
00109     const ControlPoint &p2 = g_pano->getCtrlPoint(item2);
00110     if (p1.error > p2.error)
00111         return -1;
00112     else if (p1.error < p2.error)
00113         return 1;
00114     else
00115         return 0;
00116 }
00117 
00118 static int wxCALLBACK compareCPNr(COMPARETYPEITEM item1, COMPARETYPEITEM item2, COMPARETYPESORTDATA sortData)
00119 {
00120     if (item1 < item2)
00121         return -1;
00122     else if (item1 > item2)
00123         return 1;
00124     else
00125         return 0;
00126 }
00127 
00128 static int wxCALLBACK compareCPNrGreater(COMPARETYPEITEM p1, COMPARETYPEITEM p2, COMPARETYPESORTDATA sortData)
00129 {
00130     if (p1 > p2)
00131         return -1;
00132     else if (p1 < p2)
00133         return 1;
00134     else
00135         return 0;
00136 }
00137 
00138 static int wxCALLBACK compareImg1Nr(COMPARETYPEITEM item1, COMPARETYPEITEM item2, COMPARETYPESORTDATA sortData)
00139 {
00140     const ControlPoint &p1 = g_pano->getCtrlPoint(item1);
00141     const ControlPoint &p2 = g_pano->getCtrlPoint(item2);
00142     if (p1.image1Nr < p2.image1Nr)
00143         return -1;
00144     else if (p1.image1Nr > p2.image1Nr)
00145         return 1;
00146     else
00147         return 0;
00148 }
00149 
00150 static int wxCALLBACK compareImg1NrGreater(COMPARETYPEITEM item1, COMPARETYPEITEM item2, COMPARETYPESORTDATA sortData)
00151 {
00152     const ControlPoint &p1 = g_pano->getCtrlPoint(item1);
00153     const ControlPoint &p2 = g_pano->getCtrlPoint(item2);
00154     if (p1.image1Nr > p2.image1Nr)
00155         return -1;
00156     else if (p1.image1Nr < p2.image1Nr)
00157         return 1;
00158     else
00159         return 0;
00160 }
00161 
00162 static int wxCALLBACK compareImg2Nr(COMPARETYPEITEM item1, COMPARETYPEITEM item2, COMPARETYPESORTDATA sortData)
00163 {
00164     const ControlPoint &p1 = g_pano->getCtrlPoint(item1);
00165     const ControlPoint &p2 = g_pano->getCtrlPoint(item2);
00166     if (p1.image2Nr < p2.image2Nr)
00167         return -1;
00168     else if (p1.image2Nr > p2.image2Nr)
00169         return 1;
00170     else
00171         return 0;
00172 }
00173 
00174 static int wxCALLBACK compareImg2NrGreater(COMPARETYPEITEM item1, COMPARETYPEITEM item2, COMPARETYPESORTDATA sortData)
00175 {
00176     const ControlPoint &p1 = g_pano->getCtrlPoint(item1);
00177     const ControlPoint &p2 = g_pano->getCtrlPoint(item2);
00178     if (p1.image2Nr > p2.image2Nr)
00179         return -1;
00180     else if (p1.image2Nr < p2.image2Nr)
00181         return 1;
00182     else
00183         return 0;
00184 }
00185 
00186 static int wxCALLBACK compareMode(COMPARETYPEITEM item1, COMPARETYPEITEM item2, COMPARETYPESORTDATA sortData)
00187 {
00188     const ControlPoint &p1 = g_pano->getCtrlPoint(item1);
00189     const ControlPoint &p2 = g_pano->getCtrlPoint(item2);
00190     if (p1.mode < p2.mode)
00191         return -1;
00192     else if (p1.mode > p2.mode)
00193         return 1;
00194     else
00195         return 0;
00196 }
00197 
00198 static int wxCALLBACK compareModeGreater(COMPARETYPEITEM item1, COMPARETYPEITEM item2, COMPARETYPESORTDATA sortData)
00199 {
00200     const ControlPoint &p1 = g_pano->getCtrlPoint(item1);
00201     const ControlPoint &p2 = g_pano->getCtrlPoint(item2);
00202     if (p1.mode > p2.mode)
00203         return -1;
00204     else if (p1.mode < p2.mode)
00205         return 1;
00206     else
00207         return 0;
00208 }
00209 
00210 #if 0
00211 // sort helper function
00212 struct compareError
00213 {
00214     bool operator()(const pair<int, ControlPoint> &p1, const pair<int, ControlPoint> &p2)
00215         { return p1.second.error < p2.second.error; }
00216 };
00217 
00218 // sort helper function
00219 struct compareErrorGreater
00220 {
00221     bool operator()(const pair<int, ControlPoint> &p1, const pair<int, ControlPoint> &p2)
00222         { return p1.second.error > p2.second.error; }
00223 };
00224 
00225 struct compareImg1Nr
00226 {
00227     bool operator()(const pair<int, ControlPoint> &p1, const pair<int, ControlPoint> &p2)
00228         { return p1.second.image1Nr < p2.second.image1Nr; }
00229 };
00230 
00231 struct compareImg1NrGreater
00232 {
00233     bool operator()(const pair<int, ControlPoint> &p1, const pair<int, ControlPoint> &p2)
00234         { return p1.second.image1Nr > p2.second.image1Nr; }
00235 };
00236 
00237 struct compareImg2Nr
00238 {
00239     bool operator()(const pair<int, ControlPoint> &p1, const pair<int, ControlPoint> &p2)
00240         { return p1.second.image2Nr < p2.second.image2Nr; }
00241 };
00242 
00243 struct compareImg2NrGreater
00244 {
00245     bool operator()(const pair<int, ControlPoint> &p1, const pair<int, ControlPoint> &p2)
00246         { return p1.second.image2Nr > p2.second.image2Nr; }
00247 };
00248 
00249 struct compareMode
00250 {
00251     bool operator()(const pair<int, ControlPoint> &p1, const pair<int, ControlPoint> &p2)
00252         { return p1.second.mode < p2.second.mode; }
00253 };
00254 
00255 struct compareModeGreater
00256 {
00257     bool operator()(const pair<int, ControlPoint> &p1, const pair<int, ControlPoint> &p2)
00258         { return p1.second.mode > p2.second.mode; }
00259 };
00260 
00261 #endif
00262 
00263 BEGIN_EVENT_TABLE(CPListFrame, wxFrame)
00264     EVT_CLOSE(CPListFrame::OnClose)
00265     EVT_LIST_ITEM_SELECTED(XRCID("cp_list_frame_list"), CPListFrame::OnCPListSelectionChanged)
00266     EVT_LIST_ITEM_DESELECTED(XRCID("cp_list_frame_list"), CPListFrame::OnCPListSelectionChanged)
00267     EVT_LIST_COL_CLICK(XRCID("cp_list_frame_list"), CPListFrame::OnCPListHeaderClick)
00268     EVT_LIST_COL_END_DRAG(XRCID("cp_list_frame_list"), CPListFrame::OnColumnWidthChange)
00269     EVT_BUTTON(XRCID("cp_list_delete"), CPListFrame::OnDeleteButton)
00270     EVT_BUTTON(XRCID("cp_list_select"), CPListFrame::OnSelectButton)
00271     EVT_BUTTON(XRCID("cp_list_finetune"), CPListFrame::OnFineTuneButton)
00272 //    EVT_CHECKBOX(XRCID("cp_list_multiselect"), CPListFrame::OnMuliSelectCheck)
00273 END_EVENT_TABLE()
00274 
00275 
00276 CPListFrame::CPListFrame(MainFrame * parent, Panorama & pano)
00277     : m_mainFrame(parent), m_pano(pano),m_verbose(false),
00278       m_sortCol(0), m_sortAscend(true), m_freeze(false)
00279 {
00280     DEBUG_TRACE("");
00281     bool ok = wxXmlResource::Get()->LoadFrame(this, parent, wxT("cp_list_frame"));
00282     DEBUG_ASSERT(ok);
00283     m_list = XRCCTRL(*this, "cp_list_frame_list", wxListCtrl);
00284     DEBUG_ASSERT(m_list);
00285 
00286     wxConfigBase * config = wxConfigBase::Get();
00287     m_verbose = (config->Read(wxT("/CPListFrame/verbose"),0l) != 0);
00288 
00289 #ifdef __WXMSW__
00290     // wxFrame does have a strange background color on Windows, copy color from a child widget
00291     this->SetBackgroundColour(XRCCTRL(*this, "cp_list_select", wxButton)->GetBackgroundColour());
00292 #endif
00293 #ifdef __WXMSW__
00294     wxIcon myIcon(huginApp::Get()->GetXRCPath() + wxT("data/hugin.ico"),wxBITMAP_TYPE_ICO);
00295 #else
00296     wxIcon myIcon(huginApp::Get()->GetXRCPath() + wxT("data/hugin.png"),wxBITMAP_TYPE_PNG);
00297 #endif
00298     SetIcon(myIcon);
00299 
00300     if (m_verbose) {
00301         // setup list display
00302         m_list->InsertColumn( 0, _("#"), wxLIST_FORMAT_RIGHT, 25);
00303         m_list->InsertColumn( 1, _("Left Img."), wxLIST_FORMAT_RIGHT, 65);
00304         m_list->InsertColumn( 2, _("x"), wxLIST_FORMAT_RIGHT, 40);
00305         m_list->InsertColumn( 3, _("y"), wxLIST_FORMAT_RIGHT, 40);
00306         m_list->InsertColumn( 4, _("Right Img."), wxLIST_FORMAT_RIGHT, 65);
00307         m_list->InsertColumn( 5, _("x"), wxLIST_FORMAT_RIGHT, 40);
00308         m_list->InsertColumn( 6, _("y"), wxLIST_FORMAT_RIGHT, 40);
00309         m_list->InsertColumn( 7, _("Alignment"), wxLIST_FORMAT_LEFT, 80);
00310         m_list->InsertColumn( 8, _("Distance"), wxLIST_FORMAT_RIGHT, 80);
00311     } else {
00312         m_list->InsertColumn( 0, _("G CP#"), wxLIST_FORMAT_RIGHT, 25);
00313         m_list->InsertColumn( 1, _("Left Img."), wxLIST_FORMAT_RIGHT, 65);
00314         m_list->InsertColumn( 2, _("Right Img."), wxLIST_FORMAT_RIGHT, 65);
00315         m_list->InsertColumn( 3, _("P CP#"), wxLIST_FORMAT_RIGHT, 25);
00316         m_list->InsertColumn( 4, _("Alignment"), wxLIST_FORMAT_LEFT, 80);
00317         m_list->InsertColumn( 5, _("Distance"), wxLIST_FORMAT_RIGHT, 80);
00318     }
00319 
00320     //get saved width
00321     for ( int j=0; j < m_list->GetColumnCount() ; j++ )
00322     {
00323         // -1 is auto
00324         int width = wxConfigBase::Get()->Read(wxString::Format( wxT("/CPListFrame/ColumnWidth%d"), j ), -1);
00325         if(width != -1)
00326             m_list->SetColumnWidth(j, width);
00327     }
00328 
00329     //set minumum size
00330     SetSizeHints(200, 300);
00331     
00332     //size
00333     RestoreFramePosition(this, wxT("CPListFrame"));
00334     
00335     m_list->PushEventHandler(new DelKeyHandler(*this));
00336 
00337     m_list->Show();
00338     // observe the panorama
00339     m_pano.addObserver(this);
00340 
00341     g_pano = & m_pano;
00342 
00343     // force a update of the control points
00344     UIntSet dummy;
00345     panoramaImagesChanged(m_pano, dummy);
00346     /*
00347     if (config->Read(wxT("/CPListFrame/isShown"), 0l) != 0) {
00348         Show();
00349         Raise();
00350     }
00351     */
00352 
00353     DEBUG_TRACE("ctor end");
00354 }
00355 
00356 CPListFrame::~CPListFrame()
00357 {
00358     DEBUG_TRACE("dtor");
00359     // delete our event handler
00360     m_list->PopEventHandler(true);
00361 
00362     StoreFramePosition(this, wxT("CPListFrame"));
00363 
00364     wxConfigBase * config = wxConfigBase::Get();
00365 
00366     if ( (!this->IsIconized()) && (!this->IsMaximized()) && this->IsShown()) {
00367         DEBUG_DEBUG("IsShown()");
00368         config->Write(wxT("/CPListFrame/isShown"), 1l);
00369     } else {
00370         DEBUG_DEBUG(" not shown ");
00371         config->Write(wxT("/CPListFrame/isShown"), 0l);
00372     }
00373 
00374     config->Flush();
00375     m_pano.removeObserver(this);
00376     DEBUG_TRACE("dtor end");
00377 }
00378 
00379 void CPListFrame::panoramaImagesChanged(PT::Panorama &pano, const PT::UIntSet & imgNr)
00380 {
00381     DEBUG_TRACE("");
00382     const CPVector & cpv = pano.getCtrlPoints();
00383     unsigned int nrCP = cpv.size();
00384     unsigned int nrItems = m_list->GetItemCount();
00385     DEBUG_TRACE("nr CP:" << nrCP << " nr listentries:" << nrItems);
00386 
00387     m_list->Freeze();
00388 //    m_list->Hide();
00389     // remove items for nonexisting CP's
00390     for (int i=nrItems-1; i>=(int)nrCP; i--)
00391     {
00392         m_list->DeleteItem(i);
00393     }
00394 
00395     // update existing items
00396     if ( nrCP >= nrItems ) {
00397         for (int i=0; i < (int) nrCP; i++) {
00398             if (i >= (int) nrItems) {
00399                 // create item
00400                 m_list->InsertItem(i, wxString::Format(wxT("%d"),i));
00401             }
00402         }
00403     }
00404     // update list.
00405     updateList();
00406     /*
00407     // force a nice size
00408     int nrCol = m_verbose ? 9 : 5;
00409     for (int col=0; col < nrCol ; col++) {
00410         m_list->SetColumnWidth(col,wxLIST_AUTOSIZE);
00411 
00412         //saved column width
00413         int width = wxConfigBase::Get()->Read(wxString::Format( wxT("/CPListFrame/ColumnWidth%d"), col ), -1);
00414         if(width != -1)
00415             m_list->SetColumnWidth(col, width);
00416     }
00417     */
00418     m_list->Thaw();
00419 }
00420 
00421 void CPListFrame::SetCPItem(int i, const ControlPoint & p)
00422 {
00423     DEBUG_ASSERT(i < m_list->GetItemCount());
00424     wxString mode;
00425     switch (p.mode) {
00426     case ControlPoint::X_Y:
00427         mode = _("normal");
00428         break;
00429     case ControlPoint::X:
00430         mode = _("vert. Line");
00431         break;
00432     case ControlPoint::Y:
00433         mode = _("horiz. Line");
00434         break;
00435     default:
00436         mode = wxString::Format(_("Line %d"), p.mode);
00437         break;
00438     }
00439 
00440     // Map the Global CP number to a local "Pair" CP number
00441     string pairId = makePairId(p.image1Nr,p.image2Nr);
00442     if (m_localIds.count(pairId)) {
00443         m_localIds[pairId]++;
00444     } else {
00445         m_localIds[pairId] = 0;
00446     }
00447     
00448     int localId = m_localIds[pairId];
00449     DEBUG_INFO ("Global ID: " << i << " -> Local ID: " << localId);
00450 
00451     if (m_verbose) {
00452         m_list->SetItem(i,0,wxString::Format(wxT("%d"),i));
00453         m_list->SetItem(i,1,wxString::Format(wxT("%d"),p.image1Nr));
00454         m_list->SetItem(i,2,wxString::Format(wxT("%.1f"),p.x1));
00455         m_list->SetItem(i,3,wxString::Format(wxT("%.1f"),p.y1));
00456         m_list->SetItem(i,4,wxString::Format(wxT("%d"),p.image2Nr));
00457         m_list->SetItem(i,5,wxString::Format(wxT("%.1f"),p.x2));
00458         m_list->SetItem(i,6,wxString::Format(wxT("%.1f"),p.y2));
00459         m_list->SetItem(i,7,mode);
00460         m_list->SetItem(i,8,wxString::Format(wxT("%.2f"),p.error));
00461     } else {
00462         m_list->SetItem(i,0,wxString::Format(wxT("%d"),i));
00463         m_list->SetItem(i,1,wxString::Format(wxT("%d"),p.image1Nr));
00464         m_list->SetItem(i,2,wxString::Format(wxT("%d"),p.image2Nr));
00465         m_list->SetItem(i,3,wxString::Format(wxT("%d"),localId));
00466         m_list->SetItem(i,4,mode);
00467         m_list->SetItem(i,5,wxString::Format(wxT("%.2f"),p.error));
00468     }
00469 }
00470 
00471 
00472 void CPListFrame::updateList()
00473 {
00474     const CPVector & cps = m_pano.getCtrlPoints();
00475 
00476     int sortCol = m_sortCol;
00477     bool sortAscend = m_sortAscend;
00478 
00479     // sort by number, else the updating will shuffle the selected points..
00480     // it seems that the list is traversed in order it is visible on screen
00481 
00482     m_sortCol = 0;
00483     m_sortAscend = true;
00484 
00485     // Rebuild the global->local CP map on each update as CPs might have been
00486     // removed.
00487     m_localIds.clear();
00488 
00489     SortList();
00490 
00491     int nrCP = cps.size();
00492     for (int i=0; i < (int) nrCP; i++) {
00493         SetCPItem(i,cps[i]);
00494         m_list->SetItemData(i, i);
00495         m_list->SetItemState(i, 0, wxLIST_STATE_SELECTED);
00496     }
00497 
00498 #if 0
00499     // we need to save the point numbers...
00500     vector<pair<int,ControlPoint> > cpv(nrCP);
00501     for (int i=0; i < nrCP; ++i) {
00502         cpv[i] = make_pair(i,cps[i]);
00503     }
00504 #endif
00505 
00506     m_sortCol = sortCol;
00507     m_sortAscend = sortAscend;
00508     SortList();
00509 }
00510 
00511 void CPListFrame::SortList()
00512 {
00513     // nothing to sort
00514     if (m_list->GetItemCount() == 0) return;
00515 
00516     int colNumber = 0;
00517     int colLeftImg = 1;
00518     int colRightImg = 4;
00519     int colMode = 7;
00520     int colError = 8;
00521 
00522     int colPairCP = 3;
00523 
00524     if (!m_verbose) {
00525         colRightImg = 2;
00526         colMode = 4;
00527         colError = 5;
00528     }
00529 
00530     DEBUG_TRACE("sorting column " << m_sortCol);
00531     if (m_sortCol == colNumber) {
00532         if (m_sortAscend) {
00533             m_list->SortItems(&compareCPNr, 0);
00534 //            sort(cpv.begin(),cpv.end(), compareImg1Nr());
00535         } else {
00536             m_list->SortItems(&compareCPNrGreater, 0);
00537 //            sort(cpv.begin(),cpv.end(), compareImg1NrGreater());
00538         }
00539     } else if (m_sortCol == colLeftImg) {
00540         if (m_sortAscend) {
00541             m_list->SortItems(&compareImg1Nr, 0);
00542 //            sort(cpv.begin(),cpv.end(), compareImg1Nr());
00543         } else {
00544             m_list->SortItems(&compareImg1NrGreater, 0);
00545 //            sort(cpv.begin(),cpv.end(), compareImg1NrGreater());
00546         }
00547     } else if (m_sortCol == colRightImg) {
00548         if (m_sortAscend) {
00549             m_list->SortItems(&compareImg2Nr, 0);
00550 //            sort(cpv.begin(),cpv.end(), compareImg2Nr());
00551         } else {
00552             m_list->SortItems(&compareImg2NrGreater, 0);
00553 //            sort(cpv.begin(),cpv.end(), compareImg2NrGreater());
00554         }
00555     } else if (m_sortCol == colMode) {
00556         if (m_sortAscend) {
00557             m_list->SortItems(&compareMode, 0);
00558 //            sort(cpv.begin(),cpv.end(), compareMode());
00559         } else {
00560             m_list->SortItems(&compareModeGreater, 0);
00561 //            sort(cpv.begin(),cpv.end(), compareModeGreater());
00562         }
00563     } else if (m_sortCol == colError) {
00564         if (m_sortAscend) {
00565             m_list->SortItems(&compareError, 0);
00566 //            sort(cpv.begin(),cpv.end(), compareError());
00567         } else {
00568             m_list->SortItems(&compareErrorGreater, 0);
00569 //            sort(cpv.begin(),cpv.end(), compareErrorGreater());
00570         }
00571     } else if (m_sortCol == colPairCP) {
00572         DEBUG_DEBUG("Skip sort of pair control points");
00573     } else {
00574         DEBUG_ERROR("Unknown sorting column: " << m_sortCol);
00575     }
00576 }
00577 
00578 void CPListFrame::OnCPListHeaderClick(wxListEvent & e)
00579 {
00580     // do the sorting here
00581     // wxListCtrl has a horrible interface
00582     int newCol = e.GetColumn();
00583     if (m_sortCol == newCol) {
00584         m_sortAscend = ! m_sortAscend;
00585     } else {
00586         m_sortCol = newCol;
00587         m_sortAscend = true;
00588     }
00589     SortList();
00590 }
00591 
00592 void CPListFrame::OnClose(wxCloseEvent& event)
00593 {
00594     DEBUG_DEBUG("OnClose");
00595     m_mainFrame->OnCPListFrameClosed();
00596     DEBUG_DEBUG("closing");
00597     Destroy();
00598 }
00599 
00600 void CPListFrame::OnDeleteButton(wxCommandEvent & e)
00601 {
00602     DeleteSelected();
00603 }
00604 
00605 #if 0
00606 void CPListFrame::OnSelectOutliers
00607 {
00608     // calculate the mean error between all image pairs.
00609 
00610 }
00611 #endif
00612 
00613 void CPListFrame::OnSelectButton(wxCommandEvent & e)
00614 {
00615     // calculate the mean error and the standard deviation
00616 
00617     m_freeze = true;
00618     const CPVector & cps = m_pano.getCtrlPoints();
00619 
00620     double mean_error = 0;
00621     double squared_error = 0;
00622     double max_error = 0;
00623     CPVector::const_iterator it;
00624     for (it = cps.begin() ; it != cps.end(); it++) {
00625         mean_error += (*it).error;
00626         squared_error += (*it).error * (*it).error;
00627         if ((*it).error > max_error) {
00628             max_error = (*it).error;
00629         }
00630     }
00631     mean_error = mean_error / cps.size();
00632     double std_dev = sqrt(squared_error/cps.size());
00633 
00634     // select points whos distance is greater than the mean
00635     // hmm, maybe some theory would be nice.. this is just a
00636     // guess.
00637     double threshold = mean_error + std_dev;
00638     wxString t;
00639     do
00640     {
00641         t=wxGetTextFromUser(_("Enter minimum control point error.\nAll points with a higher error will be selected"), _("Select Control Points"),
00642                                  doubleTowxString(threshold,2));
00643 
00644         if (t == wxEmptyString) {
00645             // do not select anything
00646             return;
00647         }
00648     } while (!str2double(t,threshold));
00649 
00650     bool invert = threshold < 0;
00651     if (invert) {
00652         threshold = -threshold;
00653     }
00654 
00655     m_list->Freeze();
00656     int sortCol = m_sortCol;
00657     bool sortAscend = m_sortAscend;
00658 
00659     long row = -1;
00660     for(;;) {
00661         row = m_list->GetNextItem(row,
00662                                    wxLIST_NEXT_ALL);
00663         if (row < 0) {
00664             break;
00665         }
00666         unsigned int cpNr = (unsigned int) m_list->GetItemData(row);
00667         if (    ((cps[cpNr].error > threshold ) && (!invert)) 
00668              || ((cps[cpNr].error < threshold ) && (invert))  )
00669         {
00670             // select control point
00671             DEBUG_DEBUG("selecting row: " << row << " cpNr: " << cpNr);
00672 
00673             m_list->SetItemState(row, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
00674         } else {
00675             m_list->SetItemState(row, 0, wxLIST_STATE_SELECTED);
00676         }
00677     } while (row != -1);
00678 
00679     m_list->Thaw();
00680 
00681     m_freeze = false;
00682 }
00683 
00684 void CPListFrame::DeleteSelected()
00685 {
00686     DEBUG_DEBUG("Delete pressed");
00687     // find selected point
00688     // no selected item.
00689     int nSelected = m_list->GetSelectedItemCount();
00690     DEBUG_DEBUG(nSelected << " point selected, deleting them");
00691     if (nSelected == 0) {
00692         wxBell();
00693         return;
00694     }
00695 
00696     UIntSet selected;
00697     long item = -1;
00698     for(;;) {
00699         item = m_list->GetNextItem(item,
00700                                    wxLIST_NEXT_ALL,
00701                                    wxLIST_STATE_SELECTED);
00702         // deselect item
00703         m_list->SetItemState(item, 0, wxLIST_STATE_SELECTED);
00704         if (item < 0) {
00705             break;
00706         }
00707         DEBUG_DEBUG("scheduling point " << item << " for deletion");
00708         selected.insert((unsigned int) (m_list->GetItemData(item)));
00709     }
00710     DEBUG_DEBUG("about to delete " << selected.size() << " points");
00711     GlobalCmdHist::getInstance().addCommand(
00712         new PT::RemoveCtrlPointsCmd(m_pano,selected)
00713         );
00714 
00715     item = m_list->GetNextItem(item,
00716                                wxLIST_NEXT_ALL);
00717     if (item >=0) {
00718         int cp = m_list->GetItemData(item);
00719         m_mainFrame->ShowCtrlPoint((unsigned int) cp);
00720     }
00721 }
00722 
00723 void CPListFrame::SelectAll()
00724 {
00725     unsigned int nrItems = m_list->GetItemCount();
00726     for (unsigned int i=0; i < nrItems ; i++)
00727     {
00728         m_list->SetItemState(i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
00729     }
00730 };
00731 
00732 void CPListFrame::OnFineTuneButton(wxCommandEvent & e)
00733 {
00734     DEBUG_WARN("Not yet implemented");
00735 }
00736 
00737 
00738 void CPListFrame::OnColumnWidthChange( wxListEvent & e )
00739 {
00740     int colNum = e.GetColumn();
00741     wxConfigBase::Get()->Write( wxString::Format(wxT("/CPListFrame/ColumnWidth%d"),colNum), m_list->GetColumnWidth(colNum) );
00742 }
00743 
00744 
00745 void CPListFrame::OnCPListSelectionChanged(wxListEvent & e)
00746 {
00747     DEBUG_TRACE(e.GetIndex());
00748     int itemsSelected = m_list->GetSelectedItemCount();
00749     DEBUG_DEBUG("selected control points: " << itemsSelected);
00750     if (1 == itemsSelected) {
00751         int cp = m_list->GetItemData(e.GetIndex());
00752         m_mainFrame->ShowCtrlPoint((unsigned int) cp);
00753     } else if (0 == itemsSelected) {
00754         DEBUG_DEBUG("nothing to do");
00755     } else if (itemsSelected > 1) {
00756         DEBUG_DEBUG("Multiselection nothing to do");
00757     }
00758 
00759 }
00760 
00761 
00762 std::string CPListFrame::makePairId(unsigned int id1, unsigned int id2) 
00763 {
00764     // Control points from same image pair, regardless of which is left or right
00765     // are counted the same so return the identical hash id.
00766     std::ostringstream oss;
00767 
00768     if (id1 < id2) {
00769         oss << id1 << "_" << id2;
00770     } else if (id2 < id1)  {
00771         oss << id2 << "_" << id1;
00772     } else {
00773         // Control points are from same image.
00774         oss << id1;
00775     }
00776     return oss.str();
00777 }

Generated on Mon Jul 28 01:25:31 2014 for Hugintrunk by  doxygen 1.3.9.1