1
// -*- c-basic-offset: 4 -*-
3
/** @file FindPanoDialog.cpp
5
* @brief implementation of FindPanoDialog class
11
/* This is free software; you can redistribute it and/or
12
* modify it under the terms of the GNU General Public
13
* License as published by the Free Software Foundation; either
14
* version 2 of the License, or (at your option) any later version.
16
* This software is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19
* Lesser General Public License for more details.
21
* You should have received a copy of the GNU General Public
22
* License along with this software; if not, write to the Free Software
23
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
#include "FindPanoDialog.h"
28
#include "common/wxPlatform.h"
30
#include "PTBatcherGUI.h"
32
BEGIN_EVENT_TABLE(FindPanoDialog,wxDialog)
33
EVT_BUTTON(XRCID("find_pano_close"), FindPanoDialog::OnButtonClose)
34
EVT_BUTTON(XRCID("find_pano_select_dir"), FindPanoDialog::OnButtonChoose)
35
EVT_BUTTON(XRCID("find_pano_start_stop"), FindPanoDialog::OnButtonStart)
36
EVT_BUTTON(XRCID("find_pano_add_queue"), FindPanoDialog::OnButtonSend)
37
EVT_CLOSE(FindPanoDialog::OnClose)
40
FindPanoDialog::FindPanoDialog(BatchFrame *batchframe, wxString xrcPrefix)
42
// load our children. some children might need special
43
// initialization. this will be done later.
44
wxXmlResource::Get()->LoadDialog(this,batchframe,wxT("find_pano_dialog"));
47
wxIcon myIcon(xrcPrefix+ wxT("data/ptbatcher.ico"),wxBITMAP_TYPE_ICO);
49
wxIcon myIcon(xrcPrefix + wxT("data/ptbatcher.png"),wxBITMAP_TYPE_PNG);
52
m_batchframe=batchframe;
56
m_button_start=XRCCTRL(*this,"find_pano_start_stop",wxButton);
57
m_button_choose=XRCCTRL(*this,"find_pano_select_dir",wxButton);
58
m_button_send=XRCCTRL(*this,"find_pano_add_queue",wxButton);
59
m_button_close=XRCCTRL(*this,"find_pano_close",wxButton);
60
m_textctrl_dir=XRCCTRL(*this,"find_pano_dir",wxTextCtrl);
61
m_cb_subdir=XRCCTRL(*this,"find_pano_subdir",wxCheckBox);
62
m_statustext=XRCCTRL(*this,"find_pano_label",wxStaticText);
63
m_list_pano=XRCCTRL(*this,"find_pano_list",wxCheckListBox);
64
m_cb_naming=XRCCTRL(*this,"find_pano_naming",wxChoice);
67
wxConfigBase * config = wxConfigBase::Get();
68
// restore position and size
70
wxDisplaySize(&dx,&dy);
71
bool maximized = config->Read(wxT("/FindPanoDialog/maximized"), 0l) != 0;
79
int w = config->Read(wxT("/FindPanoDialog/width"),-1l);
80
int h = config->Read(wxT("/FindPanoDialog/height"),-1l);
83
this->SetClientSize(w,h);
90
int x = config->Read(wxT("/FindPanoDialog/positionX"),-1l);
91
int y = config->Read(wxT("/FindPanoDialog/positionY"),-1l);
92
if ( y >= 0 && x >= 0 && x < dx && y < dy)
101
wxString path=config->Read(wxT("/FindPanoDialog/actualPath"),wxEmptyString);
103
m_textctrl_dir->SetValue(path);
105
config->Read(wxT("/FindPanoDialog/includeSubDirs"),&val,false);
106
m_cb_subdir->SetValue(val);
107
long i=config->Read(wxT("/FindPanoDialog/Naming"),0l);
108
m_cb_naming->SetSelection(i);
109
m_button_send->Disable();
112
FindPanoDialog::~FindPanoDialog()
114
wxConfigBase* config=wxConfigBase::Get();
115
if(!this->IsMaximized())
117
wxSize sz = this->GetClientSize();
118
config->Write(wxT("/FindPanoDialog/width"), sz.GetWidth());
119
config->Write(wxT("/FindPanoDialog/height"), sz.GetHeight());
120
wxPoint ps = this->GetPosition();
121
config->Write(wxT("/FindPanoDialog/positionX"), ps.x);
122
config->Write(wxT("/FindPanoDialog/positionY"), ps.y);
123
config->Write(wxT("/FindPanoDialog/maximized"), 0);
127
config->Write(wxT("/FindPanoDialog/maximized"), 1l);
129
config->Write(wxT("/FindPanoDialog/actualPath"),m_textctrl_dir->GetValue());
130
config->Write(wxT("/FindPanoDialog/includeSubDirs"),m_cb_subdir->GetValue());
131
config->Write(wxT("/FindPanoDialog/Naming"),m_cb_naming->GetSelection());
135
void FindPanoDialog::CleanUpPanolist()
139
for(unsigned int i=0;i<m_panos.size();i++)
141
m_panos[i].Cleanup();
147
//prevent closing window when running detection
148
void FindPanoDialog::OnClose(wxCloseEvent &e)
150
if(e.CanVeto() && m_isRunning)
161
void FindPanoDialog::OnButtonClose(wxCommandEvent &e)
165
if(wxMessageBox(_("The list contains possibly unprocessed panoramas.\nIf you close the dialog, you will lose them.\nContinue anyway?"),
166
_("Question"),wxYES_NO|wxICON_QUESTION,this)==wxNO)
174
void FindPanoDialog::OnButtonChoose(wxCommandEvent &e)
176
wxDirDialog dlg(this, _("Specify a directory to search for projects in"),
177
m_textctrl_dir->GetValue(), wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
178
if (dlg.ShowModal()==wxID_OK)
180
m_textctrl_dir->SetValue(dlg.GetPath());
184
void FindPanoDialog::OnButtonStart(wxCommandEvent &e)
190
m_button_start->SetLabel(_("Accepted"));
195
m_start_dir=m_textctrl_dir->GetValue();
196
if(wxDir::Exists(m_start_dir))
198
if(m_panos.Count()>0)
200
if(wxMessageBox(_("The list contains still not yet processed panoramas.\nIf you continue, they will be disregarded.\nDo you still want to continue?"),
201
_("Question"),wxYES_NO|wxICON_QUESTION,this)==wxNO)
208
//deactivate TIFF warning message boxes
209
m_oldtiffwarning=TIFFSetWarningHandler(NULL);
210
m_button_start->SetLabel(_("Stop"));
212
m_list_pano->Clear();
213
EnableButtons(false);
214
SearchInDir(m_start_dir,m_cb_subdir->GetValue());
218
wxMessageBox(wxString::Format(_("Directory %s does not exist.\nPlease give an existing directory."),m_start_dir.c_str()),
219
_("Warning"),wxOK | wxICON_EXCLAMATION,this);
224
void FindPanoDialog::OnButtonSend(wxCommandEvent &e)
226
if(m_panos.size()==0)
229
for(unsigned int i=0;i<m_list_pano->GetCount();i++)
231
if(m_list_pano->IsChecked(i))
238
wxMessageBox(_("You have selected no possible panorama.\nPlease select at least one panorama and try again."),_("Warning"),wxOK|wxICON_EXCLAMATION,this);
242
for(unsigned int i=0;i<m_list_pano->GetCount();i++)
244
if(m_list_pano->IsChecked(i))
246
wxString filename=m_panos[i].GeneratePanorama((PossiblePano::NamingConvention)(m_cb_naming->GetSelection()));
247
if(!filename.IsEmpty())
249
m_batchframe->AddToList(filename,Project::DETECTING);
259
wxMessageBox(_("Not all project files could be written successful.\nMaybe you have no write permission for these directories or your hard disc is full."),_("Error"),wxOK,this);
264
void FindPanoDialog::EnableButtons(const bool state)
266
m_textctrl_dir->Enable(state);
267
m_button_choose->Enable(state);
268
m_cb_subdir->Enable(state);
269
m_cb_naming->Enable(state);
270
m_button_close->Enable(state);
271
m_button_send->Enable(state);
274
void FindPanoDialog::SearchInDir(wxString dirstring, bool includeSubdir)
276
wxDir dir(dirstring);
277
PossiblePanoArray newPanos;
278
wxTimeSpan max_diff(0,0,30,0); //max. 30 s difference between images
280
bool cont=dir.GetFirst(&filename,wxEmptyString,wxDIR_FILES|wxDIR_HIDDEN);
281
while(cont && !m_stopped)
283
m_statustext->SetLabel(wxString::Format(_("Reading file %s"),filename.c_str()));
284
wxFileName file(dir.GetName(),filename);
286
wxString ext=file.GetExt();
287
if(ext.CmpNoCase(wxT("jpg"))==0 || ext.CmpNoCase(wxT("jpeg"))==0 ||
288
ext.CmpNoCase(wxT("tif"))==0 || ext.CmpNoCase(wxT("tiff"))==0)
290
std::string filenamestr(file.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
291
SrcPanoImage *img=new SrcPanoImage(filenamestr);
292
if(img->hasEXIFread())
295
for(unsigned int i=0;i<newPanos.size() && !m_stopped && !found;i++)
297
//compare with all other image groups
298
if(newPanos[i].BelongsTo(img,max_diff))
300
newPanos[i].AddSrcPanoImage(img);
305
wxGetApp().Yield(true);
310
PossiblePano *newPano=new PossiblePano();
311
newPano->AddSrcPanoImage(img);
312
newPanos.Add(newPano);
317
//could not read exif infos, disregard this image
322
//allow processing events
323
wxGetApp().Yield(true);
324
cont=dir.GetNext(&filename);
326
if(!m_stopped && newPanos.size()>0)
328
for(size_t i=0;i<newPanos.size();i++)
330
if(newPanos[i].GetImageCount()>1)
332
m_panos.Add(newPanos[i]);
333
int newItem=m_list_pano->Append(m_panos[m_panos.size()-1].GetItemString(m_start_dir));
334
m_list_pano->Check(newItem,true);
338
newPanos[i].Cleanup();
343
if(includeSubdir && !m_stopped)
345
//now we go into all directories
346
cont=dir.GetFirst(&filename,wxEmptyString,wxDIR_DIRS);
347
while(cont && !m_stopped)
349
SearchInDir(dir.GetName()+wxFileName::GetPathSeparator()+filename,includeSubdir);
350
cont=dir.GetNext(&filename);
353
if(m_start_dir.Cmp(dirstring)==0)
357
m_button_start->SetLabel(_("Start"));
359
//enable send button if at least one panorama found
360
m_button_send->Enable(m_panos.Count()>0);
361
if(m_panos.Count()>0)
363
m_statustext->SetLabel(wxString::Format(_("Found %d possible panoramas."),m_panos.Count()));
367
m_statustext->SetLabel(_("No possible panoramas found."));
369
TIFFSetWarningHandler(m_oldtiffwarning);
373
void PossiblePano::Cleanup()
375
if(m_images.size()>0)
377
for(ImageSet::reverse_iterator it=m_images.rbegin();it!=m_images.rend();it++)
384
bool PossiblePano::BelongsTo(SrcPanoImage *img, const wxTimeSpan max_time_diff)
386
if(m_make.compare(img->getExifMake())!=0)
388
if(m_camera.compare(img->getExifModel())!=0)
390
if(fabs(m_focallength-img->getExifFocalLength())>0.01)
392
if(m_size!=img->getSize())
394
const wxDateTime dt=GetDateTime(img);
395
if(!dt.IsBetween(m_dt_start,m_dt_end))
397
if(!dt.IsEqualUpTo(m_dt_start,max_time_diff))
399
if(!dt.IsEqualUpTo(m_dt_end,max_time_diff))
408
wxDateTime PossiblePano::GetDateTime(const SrcPanoImage* img)
410
struct tm exifdatetime;
411
if(img->getExifDateTime(&exifdatetime)==0)
413
return wxDateTime(exifdatetime);
417
wxFileName file(wxString(img->getFilename().c_str(),HUGIN_CONV_FILENAME));
418
return file.GetModificationTime();
422
void PossiblePano::AddSrcPanoImage(HuginBase::SrcPanoImage *img)
424
if(m_images.size()==0)
426
//fill all values from first image
427
m_make=img->getExifMake();
428
m_camera=img->getExifModel();
429
m_focallength=img->getExifFocalLength();
430
m_size=img->getSize();
431
m_dt_start=GetDateTime(img);
436
wxDateTime dt=GetDateTime(img);
437
if(dt.IsEarlierThan(m_dt_start))
441
if(dt.IsLaterThan(m_dt_end))
446
m_images.insert(img);
449
const wxString PossiblePano::GetFilestring(const wxString BasePath, const bool stripExtension) const
451
ImageSet::const_iterator it=m_images.begin();
452
wxFileName f1(wxString((*it)->getFilename().c_str(),HUGIN_CONV_FILENAME));
453
f1.MakeRelativeTo(BasePath);
454
ImageSet::const_reverse_iterator rit=m_images.rbegin();
455
wxFileName f2(wxString((*rit)->getFilename().c_str(),HUGIN_CONV_FILENAME));
458
return f1.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR)+f1.GetName()+wxT("-")+f2.GetName();
462
return f1.GetFullPath()+wxT(" - ")+f2.GetFullName();
466
const wxString PossiblePano::GetItemString(const wxString BasePath) const
468
return wxString::Format(_("%d images: %s"),m_images.size(),GetFilestring(BasePath).c_str());
471
bool PossiblePano::GetNewProjectFilename(NamingConvention nc,const wxString basePath, wxFileName &projectFile)
475
projectFile.SetPath(basePath);
476
projectFile.SetName(wxT("pano"));
477
projectFile.SetExt(wxT("pto"));
478
if(!projectFile.IsDirWritable())
485
mask=wxT("panorama%d");
487
case NAMING_FIRST_LAST:
488
mask=GetFilestring(basePath,true);
489
projectFile.SetName(mask);
490
if(!projectFile.FileExists())
494
mask=mask+wxT("_%d");
498
wxArrayString folders=projectFile.GetDirs();
499
if(folders.GetCount()==0)
504
projectFile.SetName(mask);
505
if(!projectFile.FileExists())
509
mask=mask+wxT("_%d");
513
mask=wxT("panorama%d");
516
projectFile.SetName(wxString::Format(mask,i));
517
while(projectFile.FileExists())
520
projectFile.SetName(wxString::Format(mask,i));
521
//security fall through
530
wxString PossiblePano::GeneratePanorama(NamingConvention nc)
532
if(m_images.size()==0)
534
return wxEmptyString;
536
ImageSet::const_iterator it=m_images.begin();
537
wxFileName firstFile(wxString((*it)->getFilename().c_str(),HUGIN_CONV_FILENAME));
538
firstFile.MakeAbsolute();
539
wxFileName projectFile;
540
if(!GetNewProjectFilename(nc,firstFile.GetPath(),projectFile))
542
return wxEmptyString;
545
HuginBase::Panorama pano;
546
for(ImageSet::iterator it=m_images.begin();it!=m_images.end();it++)
548
pano.addImage(*(*it));
550
//assign all images the same lens number
551
HuginBase::StandardImageVariableGroups variable_groups(pano);
552
HuginBase::ImageVariableGroup & lenses = variable_groups.getLenses();
553
if(pano.getNrOfImages()>1)
555
for(unsigned int i=1;i<pano.getNrOfImages();i++)
557
SrcPanoImage img=pano.getSrcImage(i);
558
double ev=img.getExposureValue();
559
lenses.switchParts(i,lenses.getPartNumber(0));
560
lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_ExposureValue, i);
561
img.setExposureValue(ev);
562
lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceRed, i);
563
lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceBlue, i);
564
img.setWhiteBalanceRed(1);
565
img.setWhiteBalanceBlue(1);
566
pano.setSrcImage(i, img);
569
//set default exposure value
570
PanoramaOptions opts = pano.getOptions();
571
opts.outputExposureValue = pano.getImage(0).getExposureValue();
572
pano.setOptions(opts);
574
std::ofstream script(projectFile.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
575
script.exceptions ( std::ofstream::eofbit | std::ofstream::failbit | std::ofstream::badbit );
578
return wxEmptyString;
581
fill_set(all, 0, pano.getNrOfImages()-1);
584
std::string Pathprefix(projectFile.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR).mb_str(HUGIN_CONV_FILENAME));
585
pano.printPanoramaScript(script, pano.getOptimizeVector(), pano.getOptions(), all, false, Pathprefix);
587
catch (std::exception & e)
589
return wxEmptyString;
592
return projectFile.GetFullPath();
595
#include <wx/arrimpl.cpp>
596
WX_DEFINE_OBJARRAY(PossiblePanoArray);