Hugin trunk 0.1
Loading...
Searching...
No Matches
CPListFrame.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
2
27#include "hugin_config.h"
28#include "panoinc_WX.h"
29#include "panoinc.h"
30
31#include <algorithm>
32#include <utility>
33#include <functional>
34
35#include "base_wx/wxPlatform.h"
36#include "hugin/CPListFrame.h"
37#include "hugin/MainFrame.h"
39#include "base_wx/PanoCommand.h"
40#include "base_wx/wxutils.h"
41#include "hugin/huginApp.h"
45
46std::string makePairId(unsigned int id1, unsigned int id2)
47{
48 // Control points from same image pair, regardless of which is left or right
49 // are counted the same so return the identical hash id.
50 std::ostringstream oss;
51
52 if (id1 < id2) {
53 oss << id1 << "_" << id2;
54 }
55 else if (id2 < id1) {
56 oss << id2 << "_" << id1;
57 }
58 else {
59 // Control points are from same image.
60 oss << id1;
61 }
62 return oss.str();
63}
64
66{
67 m_sortCol = 0;
68 m_sortAscend = true;
69};
70
72{
73 wxConfigBase* config = wxConfig::Get();
74 config->Write("/CPListFrame/SortColumn", m_sortCol);
75 config->Write("/CPListFrame/SortAscending", m_sortAscend ? 1 : 0);
76 config->Flush();
77 if (m_pano)
78 {
80 };
81};
82
83bool CPListCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos,
84 const wxSize& size, long style, const wxValidator& validator, const wxString& name)
85{
86 if (!wxListCtrl::Create(parent, id, pos, size, style))
87 {
88 return false;
89 };
90 InsertColumn(0, _("G CP#"), wxLIST_FORMAT_RIGHT, 25);
91 InsertColumn(1, _("Left Img."), wxLIST_FORMAT_RIGHT, 65);
92 InsertColumn(2, _("Right Img."), wxLIST_FORMAT_RIGHT, 65);
93 InsertColumn(3, _("P CP#"), wxLIST_FORMAT_RIGHT, 25);
94 InsertColumn(4, _("Alignment"), wxLIST_FORMAT_LEFT, 80);
95 InsertColumn(5, MainFrame::Get()->IsShowingCorrelation() ? _("Correlation") : _("Distance"), wxLIST_FORMAT_RIGHT, 80);
96
97 //get saved width
98 for (int j = 0; j < GetColumnCount(); j++)
99 {
100 // -1 is auto
101 int width = wxConfigBase::Get()->Read(wxString::Format("/CPListFrame/ColumnWidth%d", j), -1);
102 if (width != -1)
103 {
104 SetColumnWidth(j, width);
105 };
106 };
108
109 wxConfigBase* config = wxConfig::Get();
110 m_sortCol=config->Read("/CPListFrame/SortColumn", 0l);
111 m_sortAscend = config->Read("/CPListFrame/SortAscending", 1l) == 1;
112 config->Flush();
114 // bind event handler
115 Bind(wxEVT_CHAR, &CPListCtrl::OnChar, this);
120 return true;
121};
122
124{
125 m_pano = pano;
126 m_pano->addObserver(this);
127 panoramaChanged(*pano);
128};
129
131{
132 if (item > m_internalCPList.size())
133 {
134 return wxEmptyString;
135 };
137 switch (column)
138 {
139 case 0:
140 return wxString::Format("%lu", static_cast<unsigned long>(m_internalCPList[item].globalIndex));
141 break;
142 case 1:
143 return wxString::Format("%u", cp.image1Nr);
144 break;
145 case 2:
146 return wxString::Format("%u", cp.image2Nr);
147 break;
148 case 3:
149 return wxString::Format("%lu", static_cast<unsigned long>(m_internalCPList[item].localNumber));
150 break;
151 case 4:
152 switch (cp.mode)
153 {
155 return wxString(_("normal"));
156 break;
158 return wxString(_("vert. Line"));
159 break;
161 return wxString(_("horiz. Line"));
162 break;
163 default:
164 return wxString::Format(_("Line %d"), cp.mode);
165 break;
166 };
167 break;
168 case 5:
169 return wxString::Format("%.2f", cp.error);
170 break;
171 default:
172 return wxEmptyString;
173 };
174 return wxEmptyString;
175};
176
178{
179 return -1;
180};
181
183{
187 if (GetColumn(5, item))
188 {
190 {
191 item.SetText(_("Correlation"));
192 }
193 else
194 {
195 item.SetText(_("Distance"));
196 }
197 SetColumn(5, item);
198 };
199 XRCCTRL(*GetParent(), "cp_list_select", wxButton)->SetLabel(isShowingCorrelation ? _("Select by Correlation") : _("Select by Distance"));
202 Refresh();
203};
204
206{
209 // Rebuild the global->local CP map on each update as CPs might have been
210 // removed.
211 m_localIds.clear();
212 m_internalCPList.clear();
213 m_internalCPList.reserve(cps.size());
214 for (size_t i = 0; i < cps.size(); i++)
215 {
216 const HuginBase::ControlPoint& cp = cps[i];
217 if (m_onlyActiveImages && (!set_contains(activeImgs, cp.image1Nr) || !set_contains(activeImgs, cp.image2Nr)))
218 {
219 continue;
220 };
223 std::string pairId = makePairId(cp.image1Nr, cp.image2Nr);
224 std::map<std::string, int>::iterator it = m_localIds.find(pairId);
225 if (it != m_localIds.end())
226 {
227 ++(it->second);
228 }
229 else
230 {
231 m_localIds[pairId] = 0;
232 }
233 cpListItem.localNumber=m_localIds[pairId];
234 m_internalCPList.push_back(cpListItem);
235 };
236 SortInternalList(true);
237};
238
239// sort helper function
240// sort by global or local number only
241#define CompareStruct(VAR, TYPESUFFIX, OP) \
242struct Compare##TYPESUFFIX\
243{\
244 bool operator()(const CPListItem& item1, const CPListItem& item2)\
245 {\
246 return item1.VAR OP item2.VAR;\
247 };\
248};
249CompareStruct(globalIndex, globalIndex, <)
251CompareStruct(localNumber, localNumber, <)
253#undef CompareStruct
254
255// sort by image number, take second image number as second criterion and local number as third
256#define CompareStruct(VAR1, VAR2, TYPESUFFIX, OP)\
257struct Compare##TYPESUFFIX\
258{\
259 explicit Compare##TYPESUFFIX(const HuginBase::CPVector& cps) : m_cps(cps) {};\
260 bool operator()(const CPListItem& item1, const CPListItem& item2)\
261 {\
262 return m_cps[item1.globalIndex].VAR1 * 1e4 + m_cps[item1.globalIndex].VAR2 + item1.localNumber * 1.0 / m_cps.size() OP\
263 m_cps[item2.globalIndex].VAR1 * 1e4 + m_cps[item2.globalIndex].VAR2 + item2.localNumber * 1.0 / m_cps.size();\
264 }\
265private:\
266 const HuginBase::CPVector& m_cps;\
267};
272#undef CompareStruct
273
274// sort by mode or error
275#define CompareStruct(VAR, TYPESUFFIX, OP)\
276struct Compare##TYPESUFFIX\
277{\
278 explicit Compare##TYPESUFFIX(const HuginBase::CPVector& cps) : m_cps(cps) {};\
279 bool operator()(const CPListItem& item1, const CPListItem& item2)\
280 {\
281 return m_cps[item1.globalIndex].VAR OP m_cps[item2.globalIndex].VAR;\
282 }\
283private:\
284 const HuginBase::CPVector& m_cps;\
285};
286CompareStruct(mode, mode, <)
288CompareStruct(error, error, <)
290#undef CompareStruct
291
293{
294 // nothing to sort
295 if (m_internalCPList.empty())
296 {
297 return;
298 };
299
300 switch (m_sortCol)
301 {
302 case 0:
303 if (m_sortAscend)
304 {
305 if (!isAscending)
306 {
307 std::sort(m_internalCPList.begin(), m_internalCPList.end(), CompareglobalIndex());
308 };
309 }
310 else
311 {
313 };
314 break;
315 case 1:
316 if (m_sortAscend)
317 {
319 }
320 else
321 {
323 };
324 break;
325 case 2:
326 if (m_sortAscend)
327 {
329 }
330 else
331 {
333 };
334 break;
335 case 3:
336 if (m_sortAscend)
337 {
338 std::sort(m_internalCPList.begin(), m_internalCPList.end(), ComparelocalNumber());
339 }
340 else
341 {
343 };
344 break;
345 case 4:
346 if (m_sortAscend)
347 {
349 }
350 else
351 {
353 };
354 break;
355 case 5:
356 if (m_sortAscend)
357 {
359 }
360 else
361 {
363 };
364 break;
365 };
366};
367
369{
370 if (GetSelectedItemCount() == 1)
371 {
372 if (e.GetIndex() < m_internalCPList.size())
373 {
374 MainFrame::Get()->ShowCtrlPoint(m_internalCPList[e.GetIndex()].globalIndex);
375 };
376 };
377};
378
380{
381 const int newCol = e.GetColumn();
382 if (m_sortCol == newCol)
383 {
385 }
386 else
387 {
389 m_sortAscend = true;
390 };
392 SortInternalList(false);
393 Refresh();
394};
395
397{
398 const int colNum = e.GetColumn();
399 wxConfigBase::Get()->Write(wxString::Format("/CPListFrame/ColumnWidth%d", colNum), GetColumnWidth(colNum));
400};
401
403{
404 // no selected item.
405 const int nSelected = GetSelectedItemCount();
406 if (nSelected == 0)
407 {
408 wxBell();
409 return;
410 };
411
413 long item = GetFirstSelected();
414 long newSelection = -1;
415 if (m_internalCPList.size() - nSelected > 0)
416 {
418 if (item >= m_internalCPList.size() - nSelected)
419 {
421 };
422 };
423 while (item>=0)
424 {
425 // deselect item
426 Select(item, false);
427 selected.insert(m_internalCPList[item].globalIndex);
429 }
430 DEBUG_DEBUG("about to delete " << selected.size() << " points");
432
433 if (newSelection >= 0)
434 {
436 Select(newSelection, true);
437 };
438};
439
441{
442 const bool invert = threshold < 0;
443 if (invert)
444 {
446 };
448 Freeze();
449 for (size_t i = 0; i < m_internalCPList.size(); i++)
450 {
451 const double error = cps[m_internalCPList[i].globalIndex].error;
452 Select(i, ((error > threshold) && (!invert)) || ((error < threshold) && (invert)));
453 };
454 Thaw();
455};
456
458{
459 for (long i = 0; i < m_internalCPList.size(); i++)
460 {
461 Select(i, true);
462 };
463};
464
466{
467 switch (e.GetKeyCode())
468 {
469 case WXK_DELETE:
472 break;
473 case WXK_CONTROL_A:
474 SelectAll();
475 break;
476 default:
477 e.Skip();
478 };
479};
480
481
482IMPLEMENT_DYNAMIC_CLASS(CPListCtrl, wxListCtrl)
483
484IMPLEMENT_DYNAMIC_CLASS(CPListCtrlXmlHandler, wxListCtrlXmlHandler)
485
487: wxListCtrlXmlHandler()
488{
490}
491
493{
495 cp->Create(m_parentAsWindow, GetID(), GetPosition(), GetSize(), GetStyle("style"), wxDefaultValidator, GetName());
497 return cp;
498}
499
501{
502 return IsOfClass(node, "CPListCtrl");
503}
504
506{
507 DEBUG_TRACE("");
508 bool ok = wxXmlResource::Get()->LoadDialog(this, parent, "cp_list_frame");
510 m_list = XRCCTRL(*this, "cp_list_frame_list", CPListCtrl);
512 m_list->Init(&m_pano);
513
514 //set minumum size
515 SetSizeHints(200, 300);
516 //size
517 hugin_utils::RestoreFramePosition(this, "CPListFrame");
519 Bind(wxEVT_BUTTON, &CPListFrame::OnDeleteButton, this, XRCID("cp_list_delete"));
520 Bind(wxEVT_BUTTON, &CPListFrame::OnSelectButton, this, XRCID("cp_list_select"));
521}
522
524{
525 DEBUG_TRACE("dtor");
526 hugin_utils::StoreFramePosition(this, "CPListFrame");
527 DEBUG_TRACE("dtor end");
528}
529
531{
532 DEBUG_DEBUG("OnClose");
534 DEBUG_DEBUG("closing");
535 Destroy();
536}
537
538void CPListFrame::OnDeleteButton(wxCommandEvent & e)
539{
541}
542
543void CPListFrame::OnSelectButton(wxCommandEvent & e)
544{
545 double threshold;
548 {
550 wxConfig::Get()->Read("/Finetune/CorrThreshold", &threshold, HUGIN_FT_CORR_THRESHOLD);;
551 }
552 else
553 {
554 // calculate the mean error and the standard deviation
556 double min, max, mean, var;
558
559 // select points whos distance is greater than the mean
560 // hmm, maybe some theory would be nice.. this is just a
561 // guess.
562 threshold = mean + sqrt(var);
563 };
564 wxString t;
565 do
566 {
568 _("Enter minimum control point correlation.\nAll points with lower correlation will be selected.") :
569 _("Enter minimum control point error.\nAll points with a higher error will be selected"),
570 _("Select Control Points"),
572 if (t == wxEmptyString) {
573 // do not select anything
574 return;
575 }
576 }
578
580};
globalIndexGreater
modeGreater
errorGreater
#define CompareStruct(VAR, TYPESUFFIX, OP)
image1Nr
image2NrGreater
std::string makePairId(unsigned int id1, unsigned int id2)
image1NrGreater
image2Nr
localNumberGreater
Utility calls into PanoTools using CPP interface.
xrc handler for CPImagesComboBox
Definition CPListFrame.h:95
virtual bool CanHandle(wxXmlNode *node)
Internal use to identify right xml handler.
virtual wxObject * DoCreateResource()
Create CPImagesComboBox from resource.
List all control points of this project.
Definition CPListFrame.h:44
void SelectDistanceThreshold(double threshold)
select all cp with the given error bigger than the threshold
virtual void panoramaChanged(HuginBase::Panorama &pano)
Notification about a Panorama change.
void OnCPListSelectionChanged(wxListEvent &e)
selection event handler
void OnChar(wxKeyEvent &e)
handle keystrokes
virtual wxString OnGetItemText(long item, long column) const
create labels for virtual list control
virtual int OnGetItemImage(long item) const
show no images
void DeleteSelected()
Delete the selected points.
void SelectAll()
select all items
std::vector< CPListItem > m_internalCPList
Definition CPListFrame.h:87
void OnColumnWidthChange(wxListEvent &e)
column width changed
void OnCPListHeaderClick(wxListEvent &e)
sort criterium changed
void Init(HuginBase::Panorama *pano)
void UpdateInternalCPList()
bool m_onlyActiveImages
Definition CPListFrame.h:86
HuginBase::Panorama * m_pano
Definition CPListFrame.h:82
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxLC_REPORT|wxLC_VIRTUAL, const wxValidator &validator=wxDefaultValidator, const wxString &name=wxListCtrlNameStr)
bool m_sortAscend
Definition CPListFrame.h:85
void SortInternalList(bool isAscending)
std::map< std::string, int > m_localIds
Definition CPListFrame.h:88
void OnSelectButton(wxCommandEvent &e)
HuginBase::Panorama & m_pano
void OnDeleteButton(wxCommandEvent &e)
CPListCtrl * m_list
void OnClose(wxCloseEvent &event)
CPListFrame(wxWindow *parent, HuginBase::Panorama &pano)
ctor.
virtual ~CPListFrame()
dtor.
static void calcCtrlPntsErrorStats(const PanoramaData &pano, double &min, double &max, double &mean, double &var, const int &imgNr=-1, const bool onlyActive=false, const bool ignoreLineCp=false)
represents a control point
@ X
evaluate x, points are on a vertical line
@ Y
evaluate y, points are on a horizontal line
Model for a panorama.
Definition Panorama.h:153
void addObserver(PanoramaObserver *o)
add a panorama observer.
const ControlPoint & getCtrlPoint(std::size_t nr) const
get a control point, counting starts with 0
Definition Panorama.h:312
const CPVector & getCtrlPoints() const
get all control point of this Panorama
Definition Panorama.h:319
bool removeObserver(PanoramaObserver *observer)
remove a panorama observer.
UIntSet getActiveImages() const
get active images
void ShowCtrlPoint(unsigned int cpNr)
static MainFrame * Get()
hack.. kind of a pseudo singleton...
bool IsShowingCorrelation() const
void OnCPListFrameClosed()
const bool GetOptimizeOnlyActiveImages() const
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
static GlobalCmdHist & getInstance()
remove several control points
#define HUGIN_FT_CORR_THRESHOLD
#define DEBUG_ASSERT(cond)
Definition utils.h:80
#define DEBUG_DEBUG(msg)
Definition utils.h:68
#define DEBUG_TRACE(msg)
Definition utils.h:67
void calcCtrlPointErrors(PanoramaData &pano)
Update the Ctrl Point errors without optimizing.
std::vector< ControlPoint > CPVector
std::set< unsigned int > UIntSet
bool str2double(const wxString &s, double &d)
wxString doubleTowxString(double d, int digits)
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
Definition wxutils.cpp:106
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename, const bool ignoreMaximize)
Definition wxutils.cpp:67
include file for the hugin project
include file for the hugin project
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition stl_utils.h:74
helper class for virtual listview control
Definition CPListFrame.h:34
size_t globalIndex
Definition CPListFrame.h:35
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41
platform/compiler specific stuff.