Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PapywizardImport.cpp
Go to the documentation of this file.
1 
9 /* This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public
20 * License along with this software. If not, see
21 * <http://www.gnu.org/licenses/>.
22 *
23 */
24 
25 #include "panoinc_WX.h"
26 #include "PapywizardImport.h"
27 
28 #include "hugin_utils/utils.h"
29 #include <wx/xml/xml.h>
30 #include <wx/msgdlg.h>
31 #include <wx/stdpaths.h>
32 #include "hugin/huginApp.h"
33 #include "base_wx/CommandHistory.h"
34 #include "base_wx/PanoCommand.h"
35 #include "base_wx/platform.h"
37 #include "base_wx/wxPanoCommand.h"
39 #include "hugin/config_defaults.h"
40 
41 namespace Papywizard
42 {
43 
46 {
47 public:
48  // read from header
49  double focallength;
50  double cropfactor;
52  // read from shoot section
54  {
55  size_t id;
56  size_t bracket;
57  double yaw, pitch, roll;
58  };
59 
60  std::vector<PapywizardImage> images;
63  {
64  focallength = 0;
65  cropfactor = 1;
67  };
68 
69  bool HasBracketImages() const
70  {
71  for (size_t i = 0; i < images.size(); ++i)
72  {
73  if (images[i].bracket > 1)
74  {
75  return true;
76  };
77  };
78  return false;
79  };
80 };
81 
83 bool ParseHeader(wxXmlNode* root, PapywizardSettings& images)
84 {
85  wxXmlNode* child = root->GetChildren();
86  while (child)
87  {
88  // section <camera>
89  if (child->GetName().CmpNoCase(wxT("camera")) == 0)
90  {
91  wxXmlNode* camChild = child->GetChildren();
92  while (camChild)
93  {
94  // crop factor is saved as attribute in <sensor>
95  if (camChild->GetName().CmpNoCase(wxT("sensor")) == 0)
96  {
97  wxString number;
98  if (camChild->GetAttribute(wxT("coef"), &number))
99  {
100  if (!hugin_utils::stringToDouble(std::string(number.mb_str(wxConvLocal)), images.cropfactor))
101  {
102  return false;
103  };
104  };
105  }
106  camChild = camChild->GetNext();
107  }
108  }
109  // section <lens>
110  if (child->GetName().CmpNoCase(wxT("lens")) == 0)
111  {
112  // projection as type attribute
113  wxString projection = child->GetAttribute(wxT("type"), wxEmptyString).Trim().Trim(false);
114  if (!projection.empty())
115  {
116  if (projection.CmpNoCase(wxT("rectilinear")) == 0)
117  {
119  }
120  else
121  {
122  if (projection.CmpNoCase(wxT("fisheye")) == 0)
123  {
125  }
126  else
127  {
128  return false;
129  };
130  };
131  };
132  // focal length as own element
133  wxXmlNode* lensChild = child->GetChildren();
134  while (lensChild)
135  {
136  if (lensChild->GetName().CmpNoCase(wxT("focal")) == 0)
137  {
138  wxString focallength = lensChild->GetNodeContent().Trim().Trim(false);
139  if(!hugin_utils::stringToDouble(std::string(focallength.mb_str(wxConvLocal)), images.focallength))
140  {
141  return false;
142  };
143  }
144  lensChild = lensChild->GetNext();
145  }
146  };
147  child = child->GetNext();
148  };
149  return true;
150 };
151 
153 bool ParseShoot(wxXmlNode* root, PapywizardSettings& images)
154 {
155  wxXmlNode* child = root->GetChildren();
156  size_t id = 1;
157  while (child)
158  {
159  if (child->GetName().CmpNoCase(wxT("pict")) == 0)
160  {
162  long longVal;
163  wxString s;
164 #ifdef PAPYWIZARD_USE_ID_CHECK
165  // according to the spec the id should be unique
166  // but not all programs write the id in this way
167  // e.g. PCPano is using the same id for each image in a bracket
168  // see https://bugs.launchpad.net/hugin/+bug/1840110
169  // so the check id code is disabled for now
170  // so activate the check again define PAPYWIZARD_USE_ID_CHECK
171  if (!child->GetAttribute(wxT("id"), &s))
172  {
173  return false;
174  };
175  if (!s.ToLong(&longVal))
176  {
177  return false;
178  };
179  if (longVal < id)
180  {
181  return false;
182  };
183  image.id = longVal;
184 #else
185  // instead simply store a continous id
186  image.id = id;
187 #endif
188  ++id;
189  // read bracket attribute
190  if(!child->GetAttribute(wxT("bracket"), &s))
191  {
192  return false;
193  };
194  if (!s.ToLong(&longVal))
195  {
196  return false;
197  };
198  image.bracket = longVal;
199  // now parse all position entries
200  wxXmlNode* posChild = child->GetChildren();
201  while (posChild)
202  {
203  if (posChild->GetName().CmpNoCase(wxT("position")) == 0)
204  {
205  if (!posChild->GetAttribute(wxT("yaw"), &s))
206  {
207  return false;
208  };
209  if (!hugin_utils::stringToDouble(std::string(s.mb_str(wxConvLocal)), image.yaw))
210  {
211  return false;
212  };
213  if (!posChild->GetAttribute(wxT("pitch"), &s))
214  {
215  return false;
216  }
217  if (!hugin_utils::stringToDouble(std::string(s.mb_str(wxConvLocal)), image.pitch))
218  {
219  return false;
220  };
221  if (!posChild->GetAttribute(wxT("roll"), &s))
222  {
223  return false;
224  };
225  if (!hugin_utils::stringToDouble(std::string(s.mb_str(wxConvLocal)), image.roll))
226  {
227  return false;
228  };
229  images.images.push_back(image);
230  // we are ignoring all further entries
231  break;
232  };
233  posChild = posChild->GetNext();
234  };
235  };
236  child = child->GetNext();
237  };
238  return true;
239 };
240 
241 bool ParsePapywizardFile(const wxString& filename, PapywizardSettings& images)
242 {
243  wxXmlDocument xmlFile;
244  if (!xmlFile.Load(filename))
245  {
246  return false;
247  }
248  if (xmlFile.GetRoot()->GetName().CmpNoCase(wxT("papywizard")) != 0)
249  {
250  // not a papywizard file
251  return false;
252  };
253  // iterate all children
254  wxXmlNode* child = xmlFile.GetRoot()->GetChildren();
255  while (child)
256  {
257  if (child->GetName().CmpNoCase(wxT("header")) == 0)
258  {
259  if (!ParseHeader(child, images))
260  {
261  return false;
262  };
263  };
264  if (child->GetName().CmpNoCase(wxT("shoot")) == 0)
265  {
266  if (!ParseShoot(child, images))
267  {
268  return false;
269  };
270  }
271  child = child->GetNext();
272  }
273  return true;
274 };
275 
276 class PapywizardImportDialog: public wxDialog
277 {
278 public:
280  PapywizardImportDialog(wxWindow *parent)
281  {
282  wxXmlResource::Get()->LoadDialog(this, parent, wxT("papywizard_import_dialog"));
283 #ifdef __WXMSW__
284  wxIconBundle myIcons(huginApp::Get()->GetXRCPath() + wxT("data/hugin.ico"), wxBITMAP_TYPE_ICO);
285  SetIcons(myIcons);
286 #else
287  wxIcon myIcon(huginApp::Get()->GetXRCPath() + wxT("data/hugin.png"), wxBITMAP_TYPE_PNG);
288  SetIcon(myIcon);
289 #endif
290 
291  m_linkPos = XRCCTRL(*this, "papywizard_link_positions", wxCheckBox);
292  m_cpfind = XRCCTRL(*this, "papywizard_cpfind", wxCheckBox);
293  m_cpfindParams = XRCCTRL(*this, "papywizard_cpfind_parameters", wxTextCtrl);
294  m_geocpset = XRCCTRL(*this, "papywizard_geocpset", wxCheckBox);
295  const wxString cpfindParams = wxConfig::Get()->Read(wxT("/PapywizardImportCpfind"), wxEmptyString);
296  m_cpfindParams->SetValue(cpfindParams);
297  RestoreFramePosition(this, wxT("PapywizardImportDialog"));
298  };
301  {
302  StoreFramePosition(this, wxT("PapywizardImportDialog"));
303  if (m_cpfind->IsChecked())
304  {
305  wxConfig::Get()->Write(wxT("/PapywizardImportCpfind"), m_cpfindParams->GetValue());
306  };
307  };
308  void EnableStack(const bool hasStacks)
309  {
310  m_linkPos->Enable(hasStacks);
311  m_linkPos->SetValue(hasStacks);
312  };
313  const bool LinkStacks() const
314  {
315  return m_linkPos->IsEnabled() && m_linkPos->IsChecked();
316  };
317  const bool RunCpfind() const
318  {
319  return m_cpfind->IsChecked();
320  };
321  const wxString GetCPFindParam() const
322  {
323  return m_cpfindParams->GetValue();
324  };
325  const bool RunGeocpset() const
326  {
327  return m_geocpset->IsEnabled() && m_geocpset->IsChecked();
328  };
329 protected:
330  void OnCpfindCheck(wxCommandEvent& e)
331  {
332  const bool cpfindActive = m_cpfind->IsChecked();
333  m_cpfindParams->Enable(cpfindActive);
334  m_geocpset->Enable(cpfindActive);
335  };
336 private:
337  wxCheckBox* m_linkPos;
338  wxCheckBox* m_cpfind;
339  wxTextCtrl* m_cpfindParams;
340  wxCheckBox* m_geocpset;
341  DECLARE_EVENT_TABLE()
342 };
343 
344 BEGIN_EVENT_TABLE(PapywizardImportDialog, wxDialog)
345  EVT_CHECKBOX(XRCID("papywizard_cpfind"), PapywizardImportDialog::OnCpfindCheck)
347 
348 bool ImportPapywizardFile(const wxString& filename, HuginBase::Panorama& pano)
349 {
350  PapywizardSettings papyImages;
351  if (!ParsePapywizardFile(filename, papyImages))
352  {
353  wxMessageBox(wxString::Format(_("Could not parse file %s as Papywizard XML file."), filename.c_str()),
354 #ifdef __WXMSW__
355  _("Hugin"),
356 #else
357  wxT(""),
358 #endif
359  wxOK);
360  return false;
361  };
362  // check if number of images matches
363  if(papyImages.images.size()!=pano.getNrOfImages())
364  {
365  wxMessageBox(wxString::Format(_("The current project does not match with the Papywizard xml file.\nThe Papywizard file \"%s\" contains %lu images, but the Hugin project contains %lu images."), filename.c_str(), static_cast<unsigned long>(papyImages.images.size()), static_cast<unsigned long>(pano.getNrOfImages())),
366 #ifdef __WXMSW__
367  _("Hugin"),
368 #else
369  wxT(""),
370 #endif
371  wxOK);
372  return false;
373  };
374  PapywizardImportDialog dialog(wxGetActiveWindow());
375  dialog.EnableStack(papyImages.HasBracketImages());
376  if(dialog.ShowModal()!=wxID_OK)
377  {
378  return false;
379  };
380  // now we can build all commands
381  std::vector<PanoCommand::PanoCommand *> commands;
382  HuginBase::UIntSet images;
383  fill_set(images, 0, pano.getNrOfImages() - 1);
384  // all images share the same lens
386  commands.push_back(new PanoCommand::ChangeImageProjectionCmd(pano, images, papyImages.projection));
387  if (papyImages.focallength > 0)
388  {
389  commands.push_back(new PanoCommand::UpdateCropFactorCmd(pano, images, papyImages.cropfactor));
390  commands.push_back(new PanoCommand::UpdateFocalLengthCmd(pano, images, papyImages.focallength));
391  };
392  // remove all existing stacks
393  for (size_t i = 1; i < pano.getNrOfImages(); i++)
394  {
395  HuginBase::UIntSet imgs;
396  imgs.insert(i);
398  };
399  // create stacks
400  if (papyImages.HasBracketImages())
401  {
402  size_t stackNr = 0;
403  size_t imgNr = 0;
404  while (imgNr < pano.getNrOfImages())
405  {
406  HuginBase::UIntSet imgs;
407  do
408  {
409  imgs.insert(imgNr);
410  imgNr++;
411  } while (imgNr < pano.getNrOfImages() && papyImages.images[imgNr].bracket != 1);
413  stackNr++;
414  };
415  // unlink position if wished by user
416  if (!dialog.LinkStacks())
417  {
418  std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> variables;
419  variables.insert(HuginBase::ImageVariableGroup::IVE_Yaw);
420  variables.insert(HuginBase::ImageVariableGroup::IVE_Pitch);
421  variables.insert(HuginBase::ImageVariableGroup::IVE_Roll);
422  variables.insert(HuginBase::ImageVariableGroup::IVE_X);
423  variables.insert(HuginBase::ImageVariableGroup::IVE_Y);
424  variables.insert(HuginBase::ImageVariableGroup::IVE_Z);
425  variables.insert(HuginBase::ImageVariableGroup::IVE_TranslationPlaneYaw);
426  variables.insert(HuginBase::ImageVariableGroup::IVE_TranslationPlanePitch);
427  commands.push_back(new PanoCommand::ChangePartImagesLinkingCmd(pano, images, variables, false, HuginBase::StandardImageVariableGroups::getStackVariables()));
428  }
429  };
430  // now set the positions
431  HuginBase::VariableMapVector variables = pano.getVariables();
432  for (size_t i = 0; i < papyImages.images.size(); ++i)
433  {
434  map_get(variables[i], "y").setValue(papyImages.images[i].yaw);
435  map_get(variables[i], "p").setValue(papyImages.images[i].pitch);
436  map_get(variables[i], "r").setValue(papyImages.images[i].roll);
437  map_get(variables[i], "TrX").setValue(0);
438  map_get(variables[i], "TrY").setValue(0);
439  map_get(variables[i], "TrZ").setValue(0);
440  map_get(variables[i], "Tpy").setValue(0);
441  map_get(variables[i], "Tpp").setValue(0);
442  // fov gets updated when focal length is set, this has not yet been happen
443  // so remove fov from list to prevent overwritting with old value, because
444  // variables have not yet been updated yet
445  variables[i].erase("v");
446  };
447  commands.push_back(new PanoCommand::UpdateVariablesCmd(pano, variables));
449 
450  // now create the cp
451  if (dialog.RunCpfind())
452  {
453  //save project into temp directory
454  wxString tempDir = wxConfig::Get()->Read(wxT("tempDir"), wxT(""));
455  if (!tempDir.IsEmpty())
456  {
457  if (tempDir.Last() != wxFileName::GetPathSeparator())
458  {
459  tempDir.Append(wxFileName::GetPathSeparator());
460  }
461  };
462  wxFileName scriptFileName(wxFileName::CreateTempFileName(tempDir + wxT("hp")));
463  const std::string scriptString(scriptFileName.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
464  pano.WritePTOFile(scriptString, hugin_utils::getPathPrefix(scriptString));
465  // build command queue
466  const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
468  const wxString quotedProject(HuginQueue::wxEscapeFilename(scriptFileName.GetFullPath()));
469  commands->push_back(new HuginQueue::NormalCommand(HuginQueue::GetInternalProgram(exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR), wxT("cpfind")),
470  dialog.GetCPFindParam() + wxT(" --prealigned -o ") + quotedProject + wxT(" ") + quotedProject, _("Searching for control points...")));
471  if (dialog.RunGeocpset())
472  {
473  commands->push_back(new HuginQueue::NormalCommand(HuginQueue::GetInternalProgram(exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR), wxT("geocpset")),
474  wxT("-o ") + quotedProject + wxT(" ") + quotedProject, _("Connecting overlapping images")));
475  };
476  //execute queue
477  MyExecuteCommandQueue(commands, wxGetActiveWindow(), _("Searching control points"));
478  //read back panofile
480  (const char *)scriptFileName.GetFullPath().mb_str(HUGIN_CONV_FILENAME),
481  (const char *)scriptFileName.GetPath(wxPATH_NATIVE | wxPATH_GET_SEPARATOR).mb_str(HUGIN_CONV_FILENAME),
482  false, false));
483  //delete temporary files
484  wxRemoveFile(scriptFileName.GetFullPath());
485  };
486  return true;
487 }
488 
489 } // namespace Papywizard
490 
int MyExecuteCommandQueue(HuginQueue::CommandQueue *queue, wxWindow *parent, const wxString &title, const wxString &comment)
execute all commands in queue with redirection of output to frame and allow canceling the queue will ...
bool ImportPapywizardFile(const wxString &filename, HuginBase::Panorama &pano)
import the settings from given filename into pano
normal command for queue, processing is stopped if an error occurred in program
Definition: Executor.h:37
static const std::set< ConstImageVariableGroup::ImageVariableEnum > & getLensVariables()
Get the set of lens image variables.
PapywizardImportDialog(wxWindow *parent)
Constructor, read from xrc ressource.
implementation of huginApp Class
Change the linking of some variables across parts of an ImageVariableGroup containing some specified ...
Definition: PanoCommand.h:524
read settings from papywizard xml file
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
wxString GetInternalProgram(const wxString &bindir, const wxString &name)
return path and name of external program, which comes bundled with Hugin
Definition: Executor.cpp:129
END_EVENT_TABLE()
PapywizardSettings()
constructor, initialize some values
std::vector< PapywizardImage > images
static huginApp * Get()
hack.. kind of a pseudo singleton...
Definition: huginApp.cpp:649
PanoCommand to combine other PanoCommands.
Definition: PanoCommand.h:39
bool ParseShoot(wxXmlNode *root, PapywizardSettings &images)
parse shoot section of papywizard file
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
std::vector< VariableMap > VariableMapVector
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
Definition: utils.cpp:184
HuginBase::SrcPanoImage::Projection projection
Make a new part in a ImageVariableGroup for a set of images, given the variables that make up the gro...
Definition: PanoCommand.h:591
bool ParsePapywizardFile(const wxString &filename, PapywizardSettings &images)
void OnCpfindCheck(wxCommandEvent &e)
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Store window size and position in configfile/registry.
Definition: LensCalApp.cpp:212
Map::mapped_type & map_get(Map &m, const typename Map::key_type &key)
get a map element.
Definition: stl_utils.h:98
Update the focal length.
Definition: PanoCommand.h:476
Switch the part number of an image.
Definition: PanoCommand.h:506
wxwindows specific panorama commands
~PapywizardImportDialog()
destructor, save settings
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Restore window size and position from configfile/registry.
Definition: LensCalApp.cpp:158
static GlobalCmdHist & getInstance()
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
bool stringToDouble(const STR &str_, double &dest)
convert a string to a double, ignore localisation.
Definition: utils.h:114
include file for the hugin project
str wxEscapeFilename(const str &arg)
special escaping routine for CommandQueues
Definition: Executor.h:79
Update the crop factor.
Definition: PanoCommand.h:491
update all variables
Definition: PanoCommand.h:105
void fill_set(_Container &c, typename _Container::key_type begin, typename _Container::key_type end)
Definition: stl_utils.h:81
bool ParseHeader(wxXmlNode *root, PapywizardSettings &images)
parse header of papywizard file
dump the current project and load a new one.
Definition: wxPanoCommand.h:66
class which holds all read settings from a Papywizard xml file
static const std::set< ConstImageVariableGroup::ImageVariableEnum > & getStackVariables()
Get the set of stack image variables.
std::vector< NormalCommand * > CommandQueue
Definition: Executor.h:61
const wxString GetCPFindParam() const
void EnableStack(const bool hasStacks)