1 // -*- c-basic-offset: 4 -*-
2
3 /** @file ImagesPanel.cpp
4 *
5 * @brief implementation of ImagesPanel Class
6 *
7 * @author Kai-Uwe Behrmann <web@tiscali.de> and
8 * Pablo d'Angelo <pablo.dangelo@web.de>
9 *
10 * $Id$
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This software is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public
23 * License along with this software. If not, see
24 * <http://www.gnu.org/licenses/>.
25 *
26 */
27
28 #include "hugin_config.h"
29 #include "panoinc_WX.h"
30 #include "panoinc.h"
31 #include <time.h>
32
33 #include "base_wx/platform.h"
34 #include "base_wx/wxPlatform.h"
35 #include "base_wx/wxcms.h"
36 #include <vector>
37 #include <map>
38 #include <functional> // std::bind
39
40 #include "hugin/ImagesPanel.h"
41 #include "base_wx/CommandHistory.h"
42 #include "hugin/TextKillFocusHandler.h"
43 #include "hugin/CPEditorPanel.h"
44 #include "hugin/ImagesList.h"
45 #include "hugin/MainFrame.h"
46 #include "hugin/huginApp.h"
47 #include "icpfind/AutoCtrlPointCreator.h"
48 #include "hugin/config_defaults.h"
49 #include "base_wx/PTWXDlg.h"
50 #include "base_wx/LensTools.h"
51 #include "hugin/ImagesTree.h"
52 #include "panodata/OptimizerSwitches.h"
53 #include "base_wx/PanoCommand.h"
54
55 #include <panodata/StandardImageVariableGroups.h>
56
BEGIN_EVENT_TABLE(ImagesPanel,wxPanel)57 BEGIN_EVENT_TABLE(ImagesPanel, wxPanel)
58 EVT_TREE_SEL_CHANGED(XRCID("images_tree_ctrl"), ImagesPanel::OnSelectionChanged )
59 EVT_CHOICE ( XRCID("images_lens_type"), ImagesPanel::OnLensTypeChanged)
60 EVT_CHOICE ( XRCID("images_group_mode"), ImagesPanel::OnGroupModeChanged)
61 EVT_RADIOBOX ( XRCID("images_column_radiobox"), ImagesPanel::OnDisplayModeChanged)
62 EVT_CHOICE ( XRCID("images_optimize_mode"), ImagesPanel::OnOptimizerSwitchChanged)
63 EVT_CHOICE ( XRCID("images_photo_optimize_mode"), ImagesPanel::OnPhotometricOptimizerSwitchChanged)
64 EVT_TEXT_ENTER ( XRCID("images_focal_length"), ImagesPanel::OnFocalLengthChanged)
65 EVT_TEXT_ENTER ( XRCID("images_crop_factor"), ImagesPanel::OnCropFactorChanged)
66 EVT_TEXT_ENTER ( XRCID("images_overlap"), ImagesPanel::OnMinimumOverlapChanged)
67 EVT_TEXT_ENTER ( XRCID("images_maxev"), ImagesPanel::OnMaxEvDiffChanged)
68 EVT_BUTTON ( XRCID("images_feature_matching"), ImagesPanel::CPGenerate)
69 EVT_BUTTON ( XRCID("images_optimize"), ImagesPanel::OnOptimizeButton)
70 EVT_BUTTON ( XRCID("images_photo_optimize"), ImagesPanel::OnPhotometricOptimizeButton)
71 END_EVENT_TABLE()
72
73 ImagesPanel::ImagesPanel()
74 {
75 m_pano = 0;
76 m_guiLevel=GUI_SIMPLE;
77 }
78
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name)79 bool ImagesPanel::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
80 long style, const wxString& name)
81 {
82 if (! wxPanel::Create(parent, id, pos, size, style, name)) {
83 return false;
84 }
85
86 wxXmlResource::Get()->LoadPanel(this, wxT("images_panel"));
87 wxPanel * panel = XRCCTRL(*this, "images_panel", wxPanel);
88 wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
89 topsizer->Add(panel, 1, wxEXPAND, 0);
90 SetSizer(topsizer);
91
92 m_images_tree = XRCCTRL(*this, "images_tree_ctrl", ImagesTreeCtrl);
93 DEBUG_ASSERT(m_images_tree);
94
95 m_showImgNr = INT_MAX;
96
97 m_matchingButton = XRCCTRL(*this, "images_feature_matching", wxButton);
98 DEBUG_ASSERT(m_matchingButton);
99
100 m_CPDetectorChoice = XRCCTRL(*this, "cpdetector_settings", wxChoice);
101
102 // Image Preview
103 m_smallImgCtrl = XRCCTRL(*this, "images_selected_image", wxStaticBitmap);
104 DEBUG_ASSERT(m_smallImgCtrl);
105
106 // empty bitmap with size (0,0) is not valid for wxStaticBitmap
107 // so we create a bitmap with the background color of the static bitmap control
108 wxImage image(1, 1, true);
109 const wxColour imageBackgroundColor = m_smallImgCtrl->GetBackgroundColour();
110 image.SetRGB(0, 0, imageBackgroundColor.Red(), imageBackgroundColor.Green(), imageBackgroundColor.Blue());
111 m_empty = wxBitmap(image);
112 m_smallImgCtrl->SetBitmap(m_empty);
113
114 m_lenstype = XRCCTRL(*this, "images_lens_type", wxChoice);
115 DEBUG_ASSERT(m_lenstype);
116 FillLensProjectionList(m_lenstype);
117 m_lenstype->SetSelection(0);
118
119 m_focallength = XRCCTRL(*this, "images_focal_length", wxTextCtrl);
120 DEBUG_ASSERT(m_focallength);
121 m_focallength->PushEventHandler(new TextKillFocusHandler(this));
122
123 m_cropfactor = XRCCTRL(*this, "images_crop_factor", wxTextCtrl);
124 DEBUG_ASSERT(m_cropfactor);
125 m_cropfactor->PushEventHandler(new TextKillFocusHandler(this));
126
127 m_overlap = XRCCTRL(*this, "images_overlap", wxTextCtrl);
128 DEBUG_ASSERT(m_overlap);
129 m_overlap->PushEventHandler(new TextKillFocusHandler(this));
130
131 m_maxEv = XRCCTRL(*this, "images_maxev", wxTextCtrl);
132 DEBUG_ASSERT(m_maxEv);
133 m_maxEv->PushEventHandler(new TextKillFocusHandler(this));
134
135 FillGroupChoice();
136
137 wxTreeEvent ev;
138 OnSelectionChanged(ev);
139 DEBUG_TRACE("end");
140
141 m_optChoice = XRCCTRL(*this, "images_optimize_mode", wxChoice);
142 DEBUG_ASSERT(m_optChoice);
143
144 m_optPhotoChoice = XRCCTRL(*this, "images_photo_optimize_mode", wxChoice);
145 DEBUG_ASSERT(m_optPhotoChoice);
146
147 FillOptimizerChoice();
148
149 wxConfigBase* config=wxConfigBase::Get();
150 m_degDigits = config->Read(wxT("/General/DegreeFractionalDigitsEdit"),3);
151 //read autopano generator settings
152 cpdetector_config.Read(config,huginApp::Get()->GetDataPath()+wxT("default.setting"));
153 //write current autopano generator settings
154 cpdetector_config.Write(config);
155 config->Flush();
156 cpdetector_config.FillControl(m_CPDetectorChoice,true);
157 Layout();
158 #ifdef __WXGTK__
159 // explicitly set focus to propogate correctly key presses/shortcuts
160 m_images_tree->SetFocus();
161 #endif
162 return true;
163 }
164
Init(HuginBase::Panorama * panorama)165 void ImagesPanel::Init(HuginBase::Panorama * panorama)
166 {
167 m_pano = panorama;
168 m_images_tree->Init(m_pano);
169 // observe the panorama
170 m_pano->addObserver(this);
171 }
172
DeleteClientData(wxChoice * cb)173 void DeleteClientData(wxChoice* cb)
174 {
175 if(cb->HasClientUntypedData())
176 {
177 for(size_t i = 0; i < cb->GetCount(); i++)
178 {
179 delete static_cast<int*>(cb->GetClientData(i));
180 };
181 };
182 };
183
~ImagesPanel()184 ImagesPanel::~ImagesPanel()
185 {
186 DEBUG_TRACE("dtor");
187 m_focallength->PopEventHandler(true);
188 m_cropfactor->PopEventHandler(true);
189 m_overlap->PopEventHandler(true);
190 m_maxEv->PopEventHandler(true);
191 m_pano->removeObserver(this);
192 wxChoice* group=XRCCTRL(*this,"images_group_mode", wxChoice);
193 DeleteClientData(group);
194 DeleteClientData(m_optChoice);
195 DeleteClientData(m_optPhotoChoice);
196 DEBUG_TRACE("dtor end");
197 }
198
199 // We need to override the default handling of size events because the
200 // sizers set the virtual size but not the actual size. We reverse
201 // the standard handling and fit the child to the parent rather than
202 // fitting the parent around the child
203
OnSize(wxSizeEvent & e)204 void ImagesPanel::OnSize( wxSizeEvent & e )
205 {
206 int winWidth, winHeight;
207 GetClientSize(&winWidth, &winHeight);
208 DEBUG_INFO( "image panel: " << winWidth <<"x"<< winHeight );
209 UpdatePreviewImage();
210
211 e.Skip();
212 }
213
panoramaChanged(HuginBase::Panorama & pano)214 void ImagesPanel::panoramaChanged(HuginBase::Panorama & pano)
215 {
216 //update optimizer choice selection
217 int optSwitch=m_pano->getOptimizerSwitch();
218 int found=wxNOT_FOUND;
219 for(size_t i=0;i<m_optChoice->GetCount();i++)
220 {
221 if(optSwitch==*static_cast<int*>(m_optChoice->GetClientData(i)))
222 {
223 found=i;
224 break;
225 };
226 };
227 if(found==wxNOT_FOUND)
228 {
229 PanoCommand::GlobalCmdHist::getInstance().addCommand(
230 new PanoCommand::UpdateOptimizerSwitchCmd(*m_pano, 0)
231 );
232 }
233 else
234 {
235 m_optChoice->SetSelection(found);
236 };
237
238 //update photometric optimizer choice selection
239 optSwitch=m_pano->getPhotometricOptimizerSwitch();
240 found=wxNOT_FOUND;
241 for(size_t i=0;i<m_optPhotoChoice->GetCount();i++)
242 {
243 if(optSwitch==*static_cast<int*>(m_optPhotoChoice->GetClientData(i)))
244 {
245 found=i;
246 break;
247 };
248 };
249 if(found==wxNOT_FOUND)
250 {
251 PanoCommand::GlobalCmdHist::getInstance().addCommand(
252 new PanoCommand::UpdatePhotometricOptimizerSwitchCmd(*m_pano, 0)
253 );
254 }
255 else
256 {
257 m_optPhotoChoice->SetSelection(found);
258 };
259 const HuginBase::PanoramaOptions opts = m_pano->getOptions();
260 m_overlap->ChangeValue(hugin_utils::doubleTowxString(opts.outputStacksMinOverlap,3));
261 m_maxEv->ChangeValue(hugin_utils::doubleTowxString(opts.outputLayersExposureDiff,2));
262 }
263
panoramaImagesChanged(HuginBase::Panorama & pano,const HuginBase::UIntSet & _imgNr)264 void ImagesPanel::panoramaImagesChanged(HuginBase::Panorama &pano, const HuginBase::UIntSet & _imgNr)
265 {
266 DEBUG_TRACE("");
267
268 // update text field if selected
269 const HuginBase::UIntSet & selected = m_images_tree->GetSelectedImages();
270 DEBUG_DEBUG("nr of sel Images: " << selected.size());
271 if (pano.getNrOfImages() == 0)
272 {
273 DisableImageCtrls();
274 m_matchingButton->Disable();
275 }
276 else
277 {
278 m_matchingButton->Enable();
279 wxTreeEvent ev;
280 OnSelectionChanged(ev);
281 };
282 //enable/disable optimize buttons
283 XRCCTRL(*this, "images_optimize", wxButton)->Enable(pano.getNrOfImages()>0);
284 XRCCTRL(*this, "images_photo_optimize", wxButton)->Enable(pano.getNrOfImages()>1);
285 }
286
287 // ##### Here start the eventhandlers #####
288
289 /** run control point detector on selected images, and add control points */
CPGenerate(wxCommandEvent & e)290 void ImagesPanel::CPGenerate(wxCommandEvent & e)
291 {
292 HuginBase::UIntSet selImg = m_images_tree->GetSelectedImages();
293 //if only one image is selected, run detector on all images, except for linefind
294 wxString progName = cpdetector_config.settings[m_CPDetectorChoice->GetSelection()].GetProg().Lower();
295 if ((selImg.empty()) || (selImg.size() == 1 && progName.Find(wxT("linefind")) == wxNOT_FOUND))
296 {
297 // add all images.
298 selImg.clear();
299 fill_set(selImg, 0, m_pano->getNrOfImages() - 1);
300 }
301
302 if (selImg.empty())
303 {
304 return;
305 }
306 RunCPGenerator(cpdetector_config.settings[m_CPDetectorChoice->GetSelection()], selImg);
307 };
308
RunCPGenerator(const HuginBase::UIntSet & img)309 void ImagesPanel::RunCPGenerator(const HuginBase::UIntSet& img)
310 {
311 RunCPGenerator(cpdetector_config.settings[m_CPDetectorChoice->GetSelection()], img);
312 }
313
RunCPGenerator(CPDetectorSetting & setting,const HuginBase::UIntSet & img)314 void ImagesPanel::RunCPGenerator(CPDetectorSetting &setting, const HuginBase::UIntSet& img)
315 {
316 wxConfigBase* config=wxConfigBase::Get();
317 long nFeatures = HUGIN_ASS_NCONTROLPOINTS;
318 if(wxGetKeyState(WXK_COMMAND))
319 {
320 nFeatures = config->Read(wxT("/MainFrame/nControlPoints"), HUGIN_ASS_NCONTROLPOINTS);
321 nFeatures = wxGetNumberFromUser(
322 _("Enter maximal number of control points per image pair"),
323 _("Points per Overlap"),
324 _("Control point detector option"),
325 nFeatures, 1, 10000
326 );
327 if(nFeatures<1)
328 {
329 return;
330 };
331 config->Write(wxT("/MainFrame/nControlPoints"), nFeatures);
332 }
333 else
334 {
335 nFeatures = config->Read(wxT("/Assistant/nControlPoints"), HUGIN_ASS_NCONTROLPOINTS);
336 };
337
338 AutoCtrlPointCreator matcher;
339 HuginBase::CPVector cps = matcher.automatch(setting, *m_pano, img, nFeatures, this);
340 wxString msg;
341 wxMessageBox(wxString::Format(_("Added %lu control points"), (unsigned long) cps.size()), _("Control point detector result"),wxOK|wxICON_INFORMATION,this);
342 PanoCommand::GlobalCmdHist::getInstance().addCommand(
343 new PanoCommand::AddCtrlPointsCmd(*m_pano, cps)
344 );
345
346 };
347
GetSelectedCPGenerator()348 const wxString ImagesPanel::GetSelectedCPGenerator()
349 {
350 return cpdetector_config.settings[m_CPDetectorChoice->GetSelection()].GetCPDetectorDesc();
351 };
352
OnSelectionChanged(wxTreeEvent & e)353 void ImagesPanel::OnSelectionChanged(wxTreeEvent & e)
354 {
355 const HuginBase::UIntSet & sel = m_images_tree->GetSelectedImages();
356 DEBUG_DEBUG("selected Images: " << sel.size());
357 if (sel.empty())
358 {
359 // nothing to edit
360 DisableImageCtrls();
361 }
362 else
363 {
364 // enable edit
365 EnableImageCtrls();
366 const HuginBase::SrcPanoImage& img = m_pano->getImage(*sel.begin());
367 bool identical_projection=true;
368 HuginBase::SrcPanoImage::Projection proj = img.getProjection();
369 double focallength = HuginBase::SrcPanoImage::calcFocalLength(img.getProjection(), img.getHFOV(),
370 img.getCropFactor(),img.getSize());;
371 double cropFactor=img.getCropFactor();
372 for (HuginBase::UIntSet::const_iterator it = sel.begin(); it != sel.end(); ++it)
373 {
374 const HuginBase::SrcPanoImage& img2 = m_pano->getImage(*it);
375 if(proj!=img2.getProjection())
376 {
377 identical_projection=false;
378 };
379 double focallength2 = HuginBase::SrcPanoImage::calcFocalLength(img2.getProjection(), img2.getHFOV(),
380 img2.getCropFactor(),img2.getSize());
381 if(focallength>0 && fabs(focallength-focallength2)>0.05)
382 {
383 focallength=-1;
384 };
385 if(fabs(cropFactor-img2.getCropFactor())>0.1)
386 {
387 cropFactor=-1;
388 };
389 };
390
391 if(identical_projection)
392 {
393 SelectListValue(m_lenstype, proj);
394 }
395 else
396 {
397 m_lenstype->Select(wxNOT_FOUND);
398 };
399 if(focallength>0)
400 {
401 // use ChangeValue explicit, SetValue would create EVT_TEXT event which collides with our TextKillFocusHandler
402 m_focallength->ChangeValue(hugin_utils::doubleTowxString(focallength,m_degDigits));
403 }
404 else
405 {
406 m_focallength->Clear();
407 };
408 if(cropFactor>0)
409 {
410 m_cropfactor->ChangeValue(hugin_utils::doubleTowxString(cropFactor,m_degDigits));
411 }
412 else
413 {
414 m_cropfactor->Clear();
415 };
416
417 if (sel.size() == 1)
418 {
419 ShowImage(*(sel.begin()));
420 }
421 else
422 {
423 m_smallImgCtrl->SetBitmap(m_empty);
424 m_smallImgCtrl->GetParent()->Layout();
425 m_smallImgCtrl->Refresh();
426 };
427 }
428 }
429
DisableImageCtrls()430 void ImagesPanel::DisableImageCtrls()
431 {
432 // disable controls
433 m_lenstype->Disable();
434 m_focallength->Disable();
435 m_cropfactor->Disable();
436 m_smallImgCtrl->SetBitmap(m_empty);
437 m_smallImgCtrl->GetParent()->Layout();
438 m_smallImgCtrl->Refresh();
439 }
440
EnableImageCtrls()441 void ImagesPanel::EnableImageCtrls()
442 {
443 // enable control if not already enabled
444 m_lenstype->Enable();
445 m_focallength->Enable();
446 m_cropfactor->Enable();
447 }
448
ShowImage(unsigned int imgNr)449 void ImagesPanel::ShowImage(unsigned int imgNr)
450 {
451 m_showImgNr = imgNr;
452 UpdatePreviewImage();
453 }
454
UpdatePreviewImage()455 void ImagesPanel::UpdatePreviewImage()
456 {
457 if (m_showImgNr < 0 || m_showImgNr >= m_pano->getNrOfImages())
458 {
459 return;
460 }
461 ImageCache::EntryPtr cacheEntry = ImageCache::getInstance().getSmallImageIfAvailable(
462 m_pano->getImage(m_showImgNr).getFilename());
463 if (!cacheEntry.get())
464 {
465 // image currently isn't loaded.
466 // Instead of loading and displaying the image now, request it for
467 // later. Then the user can switch between images in the list quickly,
468 // even when not all images previews are in the cache.
469 thumbnail_request = ImageCache::getInstance().requestAsyncSmallImage(
470 m_pano->getImage(m_showImgNr).getFilename());
471 // When the image is ready, try this function again.
472 thumbnail_request->ready.push_back(
473 std::bind(&ImagesPanel::UpdatePreviewImage, this)
474 );
475 } else {
476 // forget any request now the image has loaded.
477 thumbnail_request = ImageCache::RequestPtr();
478 wxImage img = imageCacheEntry2wxImage(cacheEntry);
479
480 double iRatio = img.GetWidth() / (double) img.GetHeight();
481
482 wxSize sz;
483 // estimate image size
484
485 sz = m_smallImgCtrl->GetContainingSizer()->GetSize();
486 double sRatio = (double)sz.GetWidth() / sz.GetHeight();
487 if (iRatio > sRatio) {
488 // image is wider than screen, display landscape
489 sz.SetHeight((int) (sz.GetWidth() / iRatio));
490 } else {
491 // portrait
492 sz.SetWidth((int) (sz.GetHeight() * iRatio));
493 }
494 // Make sure the size is positive:
495 // on a small window, m_smallImgCtrl can have 0 width.
496 sz.IncTo(wxSize(1,1));
497 wxImageResizeQuality resizeQuality = wxIMAGE_QUALITY_NORMAL;
498 if (std::max(img.GetWidth(), img.GetHeight()) > (ULONG_MAX >> 16))
499 {
500 // wxIMAGE_QUALITY_NORMAL resizes the image with ResampleNearest
501 // this algorithm works only if image dimensions are smaller then
502 // ULONG_MAX >> 16 (actual size of unsigned long differ from system
503 // to system)
504 resizeQuality = wxIMAGE_QUALITY_BOX_AVERAGE;
505 };
506 wxImage scaled = img.Scale(sz.GetWidth(),sz.GetHeight(), resizeQuality);
507 // now apply color profile
508 if (!cacheEntry->iccProfile->empty() || huginApp::Get()->HasMonitorProfile())
509 {
510 HuginBase::Color::CorrectImage(scaled, *(cacheEntry->iccProfile), huginApp::Get()->GetMonitorProfile());
511 };
512 m_smallImgCtrl->SetBitmap(wxBitmap(scaled));
513 m_smallImgCtrl->GetParent()->Layout();
514 m_smallImgCtrl->Refresh();
515 }
516 }
517
ReloadCPDetectorSettings()518 void ImagesPanel::ReloadCPDetectorSettings()
519 {
520 cpdetector_config.Read();
521 cpdetector_config.FillControl(m_CPDetectorChoice,true);
522 m_CPDetectorChoice->InvalidateBestSize();
523 m_CPDetectorChoice->GetParent()->Layout();
524 Refresh();
525 };
526
OnLensTypeChanged(wxCommandEvent & e)527 void ImagesPanel::OnLensTypeChanged (wxCommandEvent & e)
528 {
529 size_t var = GetSelectedValue(m_lenstype);
530 HuginBase::UIntSet images = m_images_tree->GetSelectedImages();
531 if(!images.empty())
532 {
533 const HuginBase::SrcPanoImage & img = m_pano->getImage(*(images.begin()));
534 double focal_length = HuginBase::SrcPanoImage::calcFocalLength(img.getProjection(), img.getHFOV(), img.getCropFactor(), img.getSize());
535 std::vector<PanoCommand::PanoCommand*> commands;
536 commands.push_back(new PanoCommand::ChangeImageProjectionCmd(*m_pano, images,(HuginBase::SrcPanoImage::Projection) var));
537 commands.push_back(new PanoCommand::UpdateFocalLengthCmd(*m_pano, images, focal_length));
538 PanoCommand::GlobalCmdHist::getInstance().addCommand(
539 new PanoCommand::CombinedPanoCommand(*m_pano, commands)
540 );
541 // check if fisheye projections is selected
542 if (wxConfig::Get()->Read(wxT("/ShowFisheyeCropHint"), 1l) == 1 &&
543 !(var == HuginBase::BaseSrcPanoImage::RECTILINEAR ||
544 var == HuginBase::BaseSrcPanoImage::PANORAMIC ||
545 var == HuginBase::BaseSrcPanoImage::EQUIRECTANGULAR ||
546 var == HuginBase::BaseSrcPanoImage::FULL_FRAME_FISHEYE))
547 {
548 // if so, show hint about crop and open tab when requested
549 wxDialog dlg;
550 wxXmlResource::Get()->LoadDialog(&dlg, NULL, wxT("fisheye_show_crop_dlg"));
551 if (dlg.ShowModal() == wxID_OK)
552 {
553 MainFrame::Get()->ShowMaskEditor(*(images.begin()), true);
554 };
555 if (XRCCTRL(dlg, "fisheye_crop_dont_ask_checkbox", wxCheckBox)->IsChecked())
556 {
557 wxConfig::Get()->Write(wxT("/ShowFisheyeCropHint"), 0l);
558 };
559 };
560 };
561 };
562
OnFocalLengthChanged(wxCommandEvent & e)563 void ImagesPanel::OnFocalLengthChanged(wxCommandEvent & e)
564 {
565 if (m_pano->getNrOfImages() == 0)
566 {
567 return;
568 };
569
570 wxString text = m_focallength->GetValue();
571 if(text.IsEmpty())
572 {
573 return;
574 };
575 double val;
576 if (!hugin_utils::str2double(text, val))
577 {
578 return;
579 }
580 //no negative values, no zero input please
581 if (val<0.1)
582 {
583 wxBell();
584 return;
585 };
586
587 HuginBase::UIntSet images = m_images_tree->GetSelectedImages();
588 const HuginBase::SrcPanoImage& srcImg = m_pano->getImage(*(images.begin()));
589 if (srcImg.getProjection() == HuginBase::SrcPanoImage::FISHEYE_ORTHOGRAPHIC)
590 {
591 double hfov=srcImg.calcHFOV(srcImg.getProjection(), val, srcImg.getCropFactor(), srcImg.getSize());
592 if(hfov>190)
593 {
594 if(wxMessageBox(
595 wxString::Format(_("You have given a field of view of %.2f degrees.\n But the orthographic projection is limited to a field of view of 180 degress.\nDo you want still use that high value?"), hfov),
596 #ifdef __WXMSW__
597 _("Hugin"),
598 #else
599 wxT(""),
600 #endif
601 wxICON_EXCLAMATION | wxYES_NO)==wxNO)
602 {
603 wxTreeEvent dummy;
604 OnSelectionChanged(dummy);
605 return;
606 };
607 };
608 };
609 PanoCommand::GlobalCmdHist::getInstance().addCommand(
610 new PanoCommand::UpdateFocalLengthCmd(*m_pano, images, val)
611 );
612 }
613
OnCropFactorChanged(wxCommandEvent & e)614 void ImagesPanel::OnCropFactorChanged(wxCommandEvent & e)
615 {
616 if (m_pano->getNrOfImages() == 0)
617 {
618 return;
619 };
620
621 wxString text = m_cropfactor->GetValue();
622 if(text.IsEmpty())
623 {
624 return;
625 };
626 double val;
627 if (!hugin_utils::str2double(text, val))
628 {
629 return;
630 }
631 //no negative values, no zero input please
632 if (val<0.1)
633 {
634 wxBell();
635 return;
636 };
637
638 HuginBase::UIntSet images = m_images_tree->GetSelectedImages();
639 PanoCommand::GlobalCmdHist::getInstance().addCommand(
640 new PanoCommand::UpdateCropFactorCmd(*m_pano,images,val)
641 );
642 }
643
OnMinimumOverlapChanged(wxCommandEvent & e)644 void ImagesPanel::OnMinimumOverlapChanged(wxCommandEvent & e)
645 {
646 wxString text = m_overlap->GetValue();
647 if(text.IsEmpty())
648 {
649 return;
650 };
651 double val;
652 if (!hugin_utils::str2double(text, val))
653 {
654 return;
655 }
656 if(fabs(val)<0.001 || val>1)
657 {
658 wxMessageBox(_("The minimum overlap has to be greater than 0 and smaller than 1."),
659 #ifdef _WIN32
660 _("Hugin"),
661 #else
662 wxT(""),
663 #endif
664 wxOK | wxICON_INFORMATION, this);
665 return;
666 };
667 if (val < 0)
668 {
669 val = -1;
670 };
671 HuginBase::PanoramaOptions opt = m_pano->getOptions();
672 opt.outputStacksMinOverlap=val;
673 PanoCommand::GlobalCmdHist::getInstance().addCommand(
674 new PanoCommand::SetPanoOptionsCmd(*m_pano,opt)
675 );
676 };
677
OnMaxEvDiffChanged(wxCommandEvent & e)678 void ImagesPanel::OnMaxEvDiffChanged(wxCommandEvent& e)
679 {
680 wxString text = m_maxEv->GetValue();
681 if(text.IsEmpty())
682 {
683 return;
684 };
685 double val;
686 if (!hugin_utils::str2double(text, val))
687 {
688 return;
689 }
690 if(val<0)
691 {
692 wxMessageBox(_("The maximum Ev difference has to be greater than 0."),
693 #ifdef _WIN32
694 _("Hugin"),
695 #else
696 wxT(""),
697 #endif
698 wxOK | wxICON_INFORMATION, this);
699 return;
700 };
701 HuginBase::PanoramaOptions opt = m_pano->getOptions();
702 opt.outputLayersExposureDiff=val;
703 PanoCommand::GlobalCmdHist::getInstance().addCommand(
704 new PanoCommand::SetPanoOptionsCmd(*m_pano,opt)
705 );
706 };
707
FillGroupChoice()708 void ImagesPanel::FillGroupChoice()
709 {
710 wxChoice* group=XRCCTRL(*this,"images_group_mode", wxChoice);
711 size_t sel=group->GetSelection();
712 DeleteClientData(group);
713 group->Clear();
714 int* i=new int;
715 *i=ImagesTreeCtrl::GROUP_NONE;
716 group->Append(_("None"), i);
717 i=new int;
718 *i=ImagesTreeCtrl::GROUP_LENS;
719 group->Append(_("Lens"), i);
720 if(m_guiLevel>GUI_SIMPLE)
721 {
722 i=new int;
723 *i=ImagesTreeCtrl::GROUP_STACK;
724 group->Append(_("Stacks"), i);
725 if(m_guiLevel==GUI_EXPERT)
726 {
727 i=new int;
728 *i=ImagesTreeCtrl::GROUP_OUTPUTLAYERS;
729 group->Append(_("Output layers"), i);
730 i=new int;
731 *i=ImagesTreeCtrl::GROUP_OUTPUTSTACK;
732 group->Append(_("Output stacks"), i);
733 };
734 };
735 if((m_guiLevel==GUI_ADVANCED && sel>2) || (m_guiLevel==GUI_SIMPLE && sel>1))
736 {
737 sel=0;
738 };
739 group->SetSelection(sel);
740 wxCommandEvent dummy;
741 OnGroupModeChanged(dummy);
742 };
743
FillOptimizerChoice()744 void ImagesPanel::FillOptimizerChoice()
745 {
746 DeleteClientData(m_optChoice);
747 m_optChoice->Clear();
748 int* i=new int;
749 *i=HuginBase::OPT_PAIR;
750 m_optChoice->Append(_("Positions (incremental, starting from anchor)"), i);
751 i=new int;
752 *i=HuginBase::OPT_POSITION;
753 m_optChoice->Append(_("Positions (y,p,r)"), i);
754 i=new int;
755 *i=(HuginBase::OPT_POSITION | HuginBase::OPT_VIEW);
756 m_optChoice->Append(_("Positions and View (y,p,r,v)"), i);
757 i=new int;
758 *i=(HuginBase::OPT_POSITION | HuginBase::OPT_BARREL);
759 m_optChoice->Append(_("Positions and Barrel Distortion (y,p,r,b)"), i);
760 i=new int;
761 *i=(HuginBase::OPT_POSITION | HuginBase::OPT_VIEW | HuginBase::OPT_BARREL);
762 m_optChoice->Append(_("Positions, View and Barrel (y,p,r,v,b)"), i);
763 i=new int;
764 *i=HuginBase::OPT_ALL;
765 if(m_guiLevel==GUI_EXPERT)
766 {
767 m_optChoice->Append(_("Everything without translation"), i);
768 }
769 else
770 {
771 m_optChoice->Append(_("Everything"), i);
772 };
773 if(m_guiLevel==GUI_EXPERT)
774 {
775 i=new int;
776 *i=(HuginBase::OPT_POSITION | HuginBase::OPT_TRANSLATION);
777 m_optChoice->Append(_("Positions and Translation (y,p,r,x,y,z)"), i);
778 i=new int;
779 *i=(HuginBase::OPT_POSITION | HuginBase::OPT_TRANSLATION | HuginBase::OPT_VIEW);
780 m_optChoice->Append(_("Positions, Translation and View (y,p,r,x,y,z,v)"), i);
781 i=new int;
782 *i=(HuginBase::OPT_POSITION | HuginBase::OPT_TRANSLATION | HuginBase::OPT_BARREL);
783 m_optChoice->Append(_("Positions, Translation and Barrel (y,p,r,x,y,z,b)"), i);
784 i=new int;
785 *i=(HuginBase::OPT_POSITION | HuginBase::OPT_TRANSLATION | HuginBase::OPT_VIEW | HuginBase::OPT_BARREL);
786 m_optChoice->Append(_("Positions, Translation, View and Barrel (y,p,r,x,y,z,v,b)"), i);
787 };
788 i=new int;
789 *i=0;
790 m_optChoice->Append(_("Custom parameters"), i);
791
792 DeleteClientData(m_optPhotoChoice);
793 m_optPhotoChoice->Clear();
794 i=new int;
795 *i=(HuginBase::OPT_EXPOSURE | HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE);
796 m_optPhotoChoice->Append(_("Low dynamic range"), i);
797 i=new int;
798 *i=(HuginBase::OPT_EXPOSURE | HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE | HuginBase::OPT_WHITEBALANCE);
799 m_optPhotoChoice->Append(_("Low dynamic range, variable white balance"), i);
800 if(m_guiLevel>GUI_SIMPLE)
801 {
802 i=new int;
803 *i=(HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE);
804 m_optPhotoChoice->Append(_("High dynamic range, fixed exposure"), i);
805 i=new int;
806 *i=(HuginBase::OPT_WHITEBALANCE | HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE);
807 m_optPhotoChoice->Append(_("High dynamic range, variable white balance, fixed exposure"), i);
808 };
809 i=new int;
810 *i=0;
811 m_optPhotoChoice->Append(_("Custom parameters"), i);
812 m_optChoice->GetParent()->Layout();
813 Refresh();
814 };
815
GetCurrentOptimizerString()816 wxString ImagesPanel::GetCurrentOptimizerString()
817 {
818 return m_optChoice->GetString(m_optChoice->GetSelection());
819 };
820
OnGroupModeChanged(wxCommandEvent & e)821 void ImagesPanel::OnGroupModeChanged(wxCommandEvent & e)
822 {
823 wxChoice* group=XRCCTRL(*this,"images_group_mode", wxChoice);
824 ImagesTreeCtrl::GroupMode mode=ImagesTreeCtrl::GroupMode(*static_cast<int*>(group->GetClientData(group->GetSelection())));
825 m_images_tree->SetGroupMode(mode);
826 XRCCTRL(*this, "images_text_overlap", wxStaticText)->Show(mode==ImagesTreeCtrl::GROUP_OUTPUTSTACK);
827 m_overlap->Show(mode==ImagesTreeCtrl::GROUP_OUTPUTSTACK);
828 m_overlap->Enable(mode==ImagesTreeCtrl::GROUP_OUTPUTSTACK);
829 XRCCTRL(*this, "images_text_maxev", wxStaticText)->Show(mode==ImagesTreeCtrl::GROUP_OUTPUTLAYERS);
830 m_maxEv->Show(mode==ImagesTreeCtrl::GROUP_OUTPUTLAYERS);
831 m_maxEv->Enable(mode==ImagesTreeCtrl::GROUP_OUTPUTLAYERS);
832 Layout();
833 Refresh();
834 };
835
OnDisplayModeChanged(wxCommandEvent & e)836 void ImagesPanel::OnDisplayModeChanged(wxCommandEvent & e)
837 {
838 wxRadioBox* display=XRCCTRL(*this,"images_column_radiobox", wxRadioBox);
839 m_images_tree->SetDisplayMode((ImagesTreeCtrl::DisplayMode)display->GetSelection());
840 };
841
OnOptimizerSwitchChanged(wxCommandEvent & e)842 void ImagesPanel::OnOptimizerSwitchChanged(wxCommandEvent &e)
843 {
844 int optSwitch=*static_cast<int*>(m_optChoice->GetClientData(m_optChoice->GetSelection()));
845 if(optSwitch!=m_pano->getOptimizerSwitch())
846 {
847 PanoCommand::GlobalCmdHist::getInstance().addCommand(
848 new PanoCommand::UpdateOptimizerSwitchCmd(*m_pano,optSwitch)
849 );
850 };
851 };
852
OnPhotometricOptimizerSwitchChanged(wxCommandEvent & e)853 void ImagesPanel::OnPhotometricOptimizerSwitchChanged(wxCommandEvent &e)
854 {
855 int optSwitch=*static_cast<int*>(m_optPhotoChoice->GetClientData(m_optPhotoChoice->GetSelection()));
856 if(optSwitch!=m_pano->getPhotometricOptimizerSwitch())
857 {
858 PanoCommand::GlobalCmdHist::getInstance().addCommand(
859 new PanoCommand::UpdatePhotometricOptimizerSwitchCmd(*m_pano,optSwitch)
860 );
861 };
862 };
863
SetGuiLevel(GuiLevel newGuiLevel)864 void ImagesPanel::SetGuiLevel(GuiLevel newGuiLevel)
865 {
866 m_guiLevel=newGuiLevel;
867 m_images_tree->SetGuiLevel(newGuiLevel);
868 FillGroupChoice();
869 FillOptimizerChoice();
870 wxStaticText* textlabel=XRCCTRL(*this, "images_mode_text", wxStaticText);
871 switch(m_guiLevel)
872 {
873 case GUI_SIMPLE:
874 textlabel->SetLabel(_("Simple interface"));
875 break;
876 case GUI_ADVANCED:
877 textlabel->SetLabel(_("Advanced interface"));
878 break;
879 case GUI_EXPERT:
880 textlabel->SetLabel(_("Expert interface"));
881 break;
882 };
883 textlabel->GetParent()->Layout();
884 textlabel->Refresh();
885 panoramaChanged(*m_pano);
886 };
887
OnOptimizeButton(wxCommandEvent & e)888 void ImagesPanel::OnOptimizeButton(wxCommandEvent &e)
889 {
890 MainFrame::Get()->OnOptimize(e);
891 };
892
OnPhotometricOptimizeButton(wxCommandEvent & e)893 void ImagesPanel::OnPhotometricOptimizeButton(wxCommandEvent &e)
894 {
895 MainFrame::Get()->OnPhotometricOptimize(e);
896 };
897
IMPLEMENT_DYNAMIC_CLASS(ImagesPanel,wxPanel)898 IMPLEMENT_DYNAMIC_CLASS(ImagesPanel, wxPanel)
899
900 ImagesPanelXmlHandler::ImagesPanelXmlHandler()
901 : wxXmlResourceHandler()
902 {
903 AddWindowStyles();
904 }
905
DoCreateResource()906 wxObject *ImagesPanelXmlHandler::DoCreateResource()
907 {
908 XRC_MAKE_INSTANCE(cp, ImagesPanel)
909
910 cp->Create(m_parentAsWindow,
911 GetID(),
912 GetPosition(), GetSize(),
913 GetStyle(wxT("style")),
914 GetName());
915
916 SetupWindow( cp);
917 return cp;
918 }
919
CanHandle(wxXmlNode * node)920 bool ImagesPanelXmlHandler::CanHandle(wxXmlNode *node)
921 {
922 return IsOfClass(node, wxT("ImagesPanel"));
923 }
924
925 IMPLEMENT_DYNAMIC_CLASS(ImagesPanelXmlHandler, wxXmlResourceHandler)
926