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 "base_wx/CommandHistory.h"
00039 #include "base_wx/PanoCommand.h"
00040 #include "hugin/huginApp.h"
00041 #include "hugin_base/panotools/PanoToolsUtils.h"
00042 #include "algorithms/basic/CalculateCPStatistics.h"
00043 
00044 BEGIN_EVENT_TABLE(CPListCtrl, wxListCtrl)
00045     EVT_CHAR(CPListCtrl::OnChar)
00046     EVT_LIST_ITEM_SELECTED(wxID_ANY, CPListCtrl::OnCPListSelectionChanged)
00047     EVT_LIST_ITEM_DESELECTED(wxID_ANY, CPListCtrl::OnCPListSelectionChanged)
00048     EVT_LIST_COL_CLICK(wxID_ANY, CPListCtrl::OnCPListHeaderClick)
00049     EVT_LIST_COL_END_DRAG(wxID_ANY, CPListCtrl::OnColumnWidthChange)
00050 END_EVENT_TABLE()
00051 
00052 std::string makePairId(unsigned int id1, unsigned int id2)
00053 {
00054     // Control points from same image pair, regardless of which is left or right
00055     // are counted the same so return the identical hash id.
00056     std::ostringstream oss;
00057 
00058     if (id1 < id2) {
00059         oss << id1 << "_" << id2;
00060     }
00061     else if (id2 < id1)  {
00062         oss << id2 << "_" << id1;
00063     }
00064     else {
00065         // Control points are from same image.
00066         oss << id1;
00067     }
00068     return oss.str();
00069 }
00070 
00071 CPListCtrl::CPListCtrl() : m_pano(NULL)
00072 {
00073     m_sortCol = 0;
00074     m_sortAscend = true;
00075 };
00076 
00077 CPListCtrl::~CPListCtrl()
00078 {
00079     if (m_pano)
00080     {
00081         m_pano->removeObserver(this);
00082     };
00083 };
00084 
00085 bool CPListCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos,
00086     const wxSize& size, long style, const wxValidator& validator, const wxString& name)
00087 {
00088     if (!wxListCtrl::Create(parent, id, pos, size, style))
00089     {
00090         return false;
00091     };
00092     InsertColumn(0, _("G CP#"), wxLIST_FORMAT_RIGHT, 25);
00093     InsertColumn(1, _("Left Img."), wxLIST_FORMAT_RIGHT, 65);
00094     InsertColumn(2, _("Right Img."), wxLIST_FORMAT_RIGHT, 65);
00095     InsertColumn(3, _("P CP#"), wxLIST_FORMAT_RIGHT, 25);
00096     InsertColumn(4, _("Alignment"), wxLIST_FORMAT_LEFT, 80);
00097     InsertColumn(5, _("Distance"), wxLIST_FORMAT_RIGHT, 80);
00098 
00099     //get saved width
00100     for (int j = 0; j < GetColumnCount(); j++)
00101     {
00102         // -1 is auto
00103         int width = wxConfigBase::Get()->Read(wxString::Format(wxT("/CPListFrame/ColumnWidth%d"), j), -1);
00104         if (width != -1)
00105         {
00106             SetColumnWidth(j, width);
00107         };
00108     };
00109     EnableAlternateRowColours(true);
00110     return true;
00111 };
00112 
00113 void CPListCtrl::Init(HuginBase::Panorama* pano)
00114 {
00115     m_pano = pano;
00116     m_pano->addObserver(this);
00117     panoramaChanged(*pano);
00118 };
00119 
00120 wxString CPListCtrl::OnGetItemText(long item, long column) const
00121 {
00122     if (item > m_internalCPList.size())
00123     {
00124         return wxEmptyString;
00125     };
00126     const HuginBase::ControlPoint& cp = m_pano->getCtrlPoint(m_internalCPList[item].globalIndex);
00127     switch (column)
00128     {
00129         case 0:
00130             return wxString::Format(wxT("%lu"), static_cast<unsigned long>(m_internalCPList[item].globalIndex));
00131             break;
00132         case 1:
00133             return wxString::Format(wxT("%u"), cp.image1Nr);
00134             break;
00135         case 2:
00136             return wxString::Format(wxT("%u"), cp.image2Nr);
00137             break;
00138         case 3:
00139             return wxString::Format(wxT("%lu"), static_cast<unsigned long>(m_internalCPList[item].localNumber));
00140             break;
00141         case 4:
00142             switch (cp.mode)
00143             {
00144                 case HuginBase::ControlPoint::X_Y:
00145                     return wxString(_("normal"));
00146                     break;
00147                 case HuginBase::ControlPoint::X:
00148                     return wxString(_("vert. Line"));
00149                     break;
00150                 case HuginBase::ControlPoint::Y:
00151                     return wxString(_("horiz. Line"));
00152                     break;
00153                 default:
00154                     return wxString::Format(_("Line %d"), cp.mode);
00155                     break;
00156             };
00157             break;
00158         case 5:
00159             return wxString::Format(wxT("%.2f"), cp.error);
00160             break;
00161         default:
00162             return wxEmptyString;
00163     };
00164     return wxEmptyString;
00165 };
00166 
00167 void CPListCtrl::panoramaChanged(HuginBase::Panorama &pano)
00168 {
00169     m_onlyActiveImages = MainFrame::Get()->GetOptimizeOnlyActiveImages();
00170     UpdateInternalCPList();
00171     SetItemCount(m_internalCPList.size());
00172     Refresh();
00173 };
00174 
00175 void CPListCtrl::UpdateInternalCPList()
00176 {
00177     const HuginBase::CPVector& cps = m_pano->getCtrlPoints();
00178     const HuginBase::UIntSet activeImgs = m_pano->getActiveImages();
00179     // Rebuild the global->local CP map on each update as CPs might have been
00180     // removed.
00181     m_localIds.clear();
00182     m_internalCPList.clear();
00183     m_internalCPList.reserve(cps.size());
00184     for (size_t i = 0; i < cps.size(); i++)
00185     {
00186         const HuginBase::ControlPoint& cp = cps[i];
00187         if (m_onlyActiveImages && (!set_contains(activeImgs, cp.image1Nr) || !set_contains(activeImgs, cp.image2Nr)))
00188         {
00189             continue;
00190         };
00191         CPListItem cpListItem;
00192         cpListItem.globalIndex = i;
00193         std::string pairId = makePairId(cp.image1Nr, cp.image2Nr);
00194         std::map<std::string, int>::iterator it = m_localIds.find(pairId);
00195         if (it != m_localIds.end())
00196         {
00197             ++(it->second);
00198         }
00199         else
00200         {
00201             m_localIds[pairId] = 0;
00202         }
00203         cpListItem.localNumber=m_localIds[pairId];
00204         m_internalCPList.push_back(cpListItem);
00205     };
00206     SortInternalList(true);
00207 };
00208 
00209 // sort helper function
00210 #define CompareStruct(VAR) \
00211 struct Compare##VAR\
00212 {\
00213     bool operator()(const CPListItem& item1, const CPListItem& item2)\
00214     {\
00215         return item1.VAR < item2.VAR;\
00216     };\
00217 };
00218 CompareStruct(globalIndex)
00219 CompareStruct(localNumber)
00220 #undef CompareStruct
00221 
00222 #define CompareStruct(VAR) \
00223 struct Compare##VAR##Greater\
00224 {\
00225     bool operator()(const CPListItem& item1, const CPListItem& item2)\
00226     {\
00227         return item1.VAR > item2.VAR;\
00228     };\
00229 };
00230 CompareStruct(globalIndex)
00231 CompareStruct(localNumber)
00232 #undef CompareStruct
00233 
00234 #define CompareStruct(VAR)\
00235 struct Compare##VAR\
00236 {\
00237     explicit Compare##VAR(const HuginBase::CPVector& cps) : m_cps(cps) {};\
00238     bool operator()(const CPListItem& item1, const CPListItem& item2)\
00239     {\
00240          return m_cps[item1.globalIndex].VAR < m_cps[item2.globalIndex].VAR; \
00241     }\
00242 private:\
00243     const HuginBase::CPVector& m_cps;\
00244 };
00245 CompareStruct(image1Nr)
00246 CompareStruct(image2Nr)
00247 CompareStruct(mode)
00248 CompareStruct(error)
00249 #undef CompareStruct
00250 
00251 #define CompareStruct(VAR)\
00252 struct Compare##VAR##Greater\
00253 {\
00254     explicit Compare##VAR##Greater(const HuginBase::CPVector& cps) : m_cps(cps) {};\
00255     bool operator()(const CPListItem& item1, const CPListItem& item2)\
00256     {\
00257          return m_cps[item1.globalIndex].VAR > m_cps[item2.globalIndex].VAR; \
00258     }\
00259 private:\
00260     const HuginBase::CPVector& m_cps;\
00261 };
00262 CompareStruct(image1Nr)
00263 CompareStruct(image2Nr)
00264 CompareStruct(mode)
00265 CompareStruct(error)
00266 #undef CompareStruct
00267 
00268 void CPListCtrl::SortInternalList(bool isAscending)
00269 {
00270     // nothing to sort
00271     if (m_internalCPList.empty())
00272     {
00273         return;
00274     };
00275 
00276     switch (m_sortCol)
00277     {
00278         case 0:
00279             if (m_sortAscend)
00280             {
00281                 if (!isAscending)
00282                 {
00283                     std::sort(m_internalCPList.begin(), m_internalCPList.end(), CompareglobalIndex());
00284                 };
00285             }
00286             else
00287             {
00288                 std::sort(m_internalCPList.begin(), m_internalCPList.end(), CompareglobalIndexGreater());
00289             };
00290             break;
00291         case 1:
00292             if (m_sortAscend)
00293             {
00294                 std::sort(m_internalCPList.begin(), m_internalCPList.end(), Compareimage1Nr(m_pano->getCtrlPoints()));
00295             }
00296             else
00297             {
00298                 std::sort(m_internalCPList.begin(), m_internalCPList.end(), Compareimage1NrGreater(m_pano->getCtrlPoints()));
00299             };
00300             break;
00301         case 2:
00302             if (m_sortAscend)
00303             {
00304                 std::sort(m_internalCPList.begin(), m_internalCPList.end(), Compareimage2Nr(m_pano->getCtrlPoints()));
00305             }
00306             else
00307             {
00308                 std::sort(m_internalCPList.begin(), m_internalCPList.end(), Compareimage2NrGreater(m_pano->getCtrlPoints()));
00309             };
00310             break;
00311         case 3:
00312             if (m_sortAscend)
00313             {
00314                 std::sort(m_internalCPList.begin(), m_internalCPList.end(), ComparelocalNumber());
00315             }
00316             else
00317             {
00318                 std::sort(m_internalCPList.begin(), m_internalCPList.end(), ComparelocalNumberGreater());
00319             };
00320             break;
00321         case 4:
00322             if (m_sortAscend)
00323             {
00324                 std::sort(m_internalCPList.begin(), m_internalCPList.end(), Comparemode(m_pano->getCtrlPoints()));
00325             }
00326             else
00327             {
00328                 std::sort(m_internalCPList.begin(), m_internalCPList.end(), ComparemodeGreater(m_pano->getCtrlPoints()));
00329             };
00330             break;
00331         case 5:
00332             if (m_sortAscend)
00333             {
00334                 std::sort(m_internalCPList.begin(), m_internalCPList.end(), Compareerror(m_pano->getCtrlPoints()));
00335             }
00336             else
00337             {
00338                 std::sort(m_internalCPList.begin(), m_internalCPList.end(), CompareerrorGreater(m_pano->getCtrlPoints()));
00339             };
00340             break;
00341     };
00342 };
00343 
00344 void CPListCtrl::OnCPListSelectionChanged(wxListEvent & e)
00345 {
00346     if (GetSelectedItemCount() == 1)
00347     {
00348         if (e.GetIndex() < m_internalCPList.size())
00349         {
00350             MainFrame::Get()->ShowCtrlPoint(m_internalCPList[e.GetIndex()].globalIndex);
00351         };
00352     };
00353 };
00354 
00355 void CPListCtrl::OnCPListHeaderClick(wxListEvent& e)
00356 {
00357     const int newCol = e.GetColumn();
00358     if (m_sortCol == newCol)
00359     {
00360         m_sortAscend = !m_sortAscend;
00361     }
00362     else
00363     {
00364         m_sortCol = newCol;
00365         m_sortAscend = true;
00366     }
00367     SortInternalList(false);
00368     Refresh();
00369 };
00370 
00371 void CPListCtrl::OnColumnWidthChange(wxListEvent& e)
00372 {
00373     const int colNum = e.GetColumn();
00374     wxConfigBase::Get()->Write(wxString::Format(wxT("/CPListFrame/ColumnWidth%d"), colNum), GetColumnWidth(colNum));
00375 };
00376 
00377 void CPListCtrl::DeleteSelected()
00378 {
00379     // no selected item.
00380     const int nSelected = GetSelectedItemCount();
00381     if (nSelected == 0)
00382     {
00383         wxBell();
00384         return;
00385     };
00386 
00387     HuginBase::UIntSet selected;
00388     long item = GetFirstSelected();
00389     long newSelection = -1;
00390     if (m_internalCPList.size() - nSelected > 0)
00391     {
00392         newSelection = item;
00393         if (item >= m_internalCPList.size() - nSelected)
00394         {
00395             newSelection = m_internalCPList.size() - nSelected - 1;
00396         };
00397     };
00398     while (item>=0)
00399     {
00400         // deselect item
00401         Select(item, false);
00402         selected.insert(m_internalCPList[item].globalIndex);
00403         item = GetNextSelected(item);
00404     }
00405     DEBUG_DEBUG("about to delete " << selected.size() << " points");
00406     PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::RemoveCtrlPointsCmd(*m_pano, selected));
00407 
00408     if (newSelection >= 0)
00409     {
00410         MainFrame::Get()->ShowCtrlPoint(m_internalCPList[newSelection].globalIndex);
00411         Select(newSelection, true);
00412     };
00413 };
00414 
00415 void CPListCtrl::SelectDistanceThreshold(double threshold)
00416 {
00417     const bool invert = threshold < 0;
00418     if (invert)
00419     {
00420         threshold = -threshold;
00421     };
00422     const HuginBase::CPVector& cps = m_pano->getCtrlPoints();
00423     Freeze();
00424     for (size_t i = 0; i < m_internalCPList.size(); i++)
00425     {
00426         const double error = cps[m_internalCPList[i].globalIndex].error;
00427         Select(i, ((error > threshold) && (!invert)) || ((error < threshold) && (invert)));
00428     };
00429     Thaw();
00430 };
00431 
00432 void CPListCtrl::SelectAll()
00433 {
00434     for (long i = 0; i < m_internalCPList.size(); i++)
00435     {
00436         Select(i, true);
00437     };
00438 };
00439 
00440 void CPListCtrl::OnChar(wxKeyEvent& e)
00441 {
00442     switch (e.GetKeyCode())
00443     {
00444         case WXK_DELETE:
00445         case WXK_NUMPAD_DELETE:
00446             DeleteSelected();
00447             break;
00448         case WXK_CONTROL_A:
00449             SelectAll();
00450             break;
00451         default:
00452             e.Skip();
00453     };
00454 };
00455 
00456 
00457 IMPLEMENT_DYNAMIC_CLASS(CPListCtrl, wxListCtrl)
00458 
00459 IMPLEMENT_DYNAMIC_CLASS(CPListCtrlXmlHandler, wxListCtrlXmlHandler)
00460 
00461 CPListCtrlXmlHandler::CPListCtrlXmlHandler()
00462 : wxListCtrlXmlHandler()
00463 {
00464     AddWindowStyles();
00465 }
00466 
00467 wxObject *CPListCtrlXmlHandler::DoCreateResource()
00468 {
00469     XRC_MAKE_INSTANCE(cp, CPListCtrl)
00470     cp->Create(m_parentAsWindow, GetID(), GetPosition(), GetSize(), GetStyle(wxT("style")), wxDefaultValidator, GetName());
00471     SetupWindow(cp);
00472     return cp;
00473 }
00474 
00475 bool CPListCtrlXmlHandler::CanHandle(wxXmlNode *node)
00476 {
00477     return IsOfClass(node, wxT("CPListCtrl"));
00478 }
00479 
00480 
00481 BEGIN_EVENT_TABLE(CPListFrame, wxFrame)
00482     EVT_CLOSE(CPListFrame::OnClose)
00483     EVT_BUTTON(XRCID("cp_list_delete"), CPListFrame::OnDeleteButton)
00484     EVT_BUTTON(XRCID("cp_list_select"), CPListFrame::OnSelectButton)
00485 END_EVENT_TABLE()
00486 
00487 CPListFrame::CPListFrame(wxFrame* parent, HuginBase::Panorama& pano) : m_pano(pano)
00488 {
00489     DEBUG_TRACE("");
00490     bool ok = wxXmlResource::Get()->LoadFrame(this, parent, wxT("cp_list_frame"));
00491     DEBUG_ASSERT(ok);
00492     m_list = XRCCTRL(*this, "cp_list_frame_list", CPListCtrl);
00493     DEBUG_ASSERT(m_list);
00494     m_list->Init(&m_pano);
00495 
00496 #ifdef __WXMSW__
00497     // wxFrame does have a strange background color on Windows, copy color from a child widget
00498     this->SetBackgroundColour(XRCCTRL(*this, "cp_list_select", wxButton)->GetBackgroundColour());
00499 #endif
00500 #ifdef __WXMSW__
00501     wxIcon myIcon(huginApp::Get()->GetXRCPath() + wxT("data/hugin.ico"),wxBITMAP_TYPE_ICO);
00502 #else
00503     wxIcon myIcon(huginApp::Get()->GetXRCPath() + wxT("data/hugin.png"),wxBITMAP_TYPE_PNG);
00504 #endif
00505     SetIcon(myIcon);
00506 
00507     //set minumum size
00508     SetSizeHints(200, 300);
00509     //size
00510     RestoreFramePosition(this, wxT("CPListFrame"));
00511 }
00512 
00513 CPListFrame::~CPListFrame()
00514 {
00515     DEBUG_TRACE("dtor");
00516     StoreFramePosition(this, wxT("CPListFrame"));
00517     DEBUG_TRACE("dtor end");
00518 }
00519 
00520 void CPListFrame::OnClose(wxCloseEvent& event)
00521 {
00522     DEBUG_DEBUG("OnClose");
00523     MainFrame::Get()->OnCPListFrameClosed();
00524     DEBUG_DEBUG("closing");
00525     Destroy();
00526 }
00527 
00528 void CPListFrame::OnDeleteButton(wxCommandEvent & e)
00529 {
00530     m_list->DeleteSelected();
00531 }
00532 
00533 void CPListFrame::OnSelectButton(wxCommandEvent & e)
00534 {
00535     // calculate the mean error and the standard deviation
00536     HuginBase::PTools::calcCtrlPointErrors(m_pano);
00537     double min, max, mean, var;
00538     HuginBase::CalculateCPStatisticsError::calcCtrlPntsErrorStats(m_pano, min, max, mean, var);
00539 
00540     // select points whos distance is greater than the mean
00541     // hmm, maybe some theory would be nice.. this is just a
00542     // guess.
00543     double threshold = mean + sqrt(var);
00544     wxString t;
00545     do
00546     {
00547         t = wxGetTextFromUser(_("Enter minimum control point error.\nAll points with a higher error will be selected"), _("Select Control Points"),
00548             hugin_utils::doubleTowxString(threshold, 2));
00549         if (t == wxEmptyString) {
00550             // do not select anything
00551             return;
00552         }
00553     }
00554     while (!hugin_utils::str2double(t, threshold));
00555 
00556     m_list->SelectDistanceThreshold(threshold);
00557 };

Generated on 7 Dec 2016 for Hugintrunk by  doxygen 1.4.7