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

Generated on 5 May 2016 for Hugintrunk by  doxygen 1.4.7