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 
284  m_linkPos = XRCCTRL(*this, "papywizard_link_positions", wxCheckBox);
285  m_cpfind = XRCCTRL(*this, "papywizard_cpfind", wxCheckBox);
286  m_cpfind->Bind(wxEVT_CHECKBOX, &PapywizardImportDialog::OnCpfindCheck, this);
287  m_cpfindParams = XRCCTRL(*this, "papywizard_cpfind_parameters", wxTextCtrl);
288  m_geocpset = XRCCTRL(*this, "papywizard_geocpset", wxCheckBox);
289  const wxString cpfindParams = wxConfig::Get()->Read(wxT("/PapywizardImportCpfind"), wxEmptyString);
290  m_cpfindParams->SetValue(cpfindParams);
291  RestoreFramePosition(this, wxT("PapywizardImportDialog"));
292  };
295  {
296  StoreFramePosition(this, wxT("PapywizardImportDialog"));
297  if (m_cpfind->IsChecked())
298  {
299  wxConfig::Get()->Write(wxT("/PapywizardImportCpfind"), m_cpfindParams->GetValue());
300  };
301  };
302  void EnableStack(const bool hasStacks)
303  {
304  m_linkPos->Enable(hasStacks);
305  m_linkPos->SetValue(hasStacks);
306  };
307  const bool LinkStacks() const
308  {
309  return m_linkPos->IsEnabled() && m_linkPos->IsChecked();
310  };
311  const bool RunCpfind() const
312  {
313  return m_cpfind->IsChecked();
314  };
315  const wxString GetCPFindParam() const
316  {
317  return m_cpfindParams->GetValue();
318  };
319  const bool RunGeocpset() const
320  {
321  return m_geocpset->IsEnabled() && m_geocpset->IsChecked();
322  };
323 protected:
324  void OnCpfindCheck(wxCommandEvent& e)
325  {
326  const bool cpfindActive = m_cpfind->IsChecked();
327  m_cpfindParams->Enable(cpfindActive);
328  m_geocpset->Enable(cpfindActive);
329  };
330 private:
331  wxCheckBox* m_linkPos;
332  wxCheckBox* m_cpfind;
333  wxTextCtrl* m_cpfindParams;
334  wxCheckBox* m_geocpset;
335 };
336 
337 bool ImportPapywizardFile(const wxString& filename, HuginBase::Panorama& pano)
338 {
339  PapywizardSettings papyImages;
340  if (!ParsePapywizardFile(filename, papyImages))
341  {
342  wxMessageBox(wxString::Format(_("Could not parse file %s as Papywizard XML file."), filename.c_str()),
343 #ifdef __WXMSW__
344  _("Hugin"),
345 #else
346  wxT(""),
347 #endif
348  wxOK);
349  return false;
350  };
351  // check if number of images matches
352  if(papyImages.images.size()!=pano.getNrOfImages())
353  {
354  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())),
355 #ifdef __WXMSW__
356  _("Hugin"),
357 #else
358  wxT(""),
359 #endif
360  wxOK);
361  return false;
362  };
363  PapywizardImportDialog dialog(wxGetActiveWindow());
364  dialog.EnableStack(papyImages.HasBracketImages());
365  if(dialog.ShowModal()!=wxID_OK)
366  {
367  return false;
368  };
369  // now we can build all commands
370  std::vector<PanoCommand::PanoCommand *> commands;
371  HuginBase::UIntSet images;
372  fill_set(images, 0, pano.getNrOfImages() - 1);
373  // all images share the same lens
375  commands.push_back(new PanoCommand::ChangeImageProjectionCmd(pano, images, papyImages.projection));
376  if (papyImages.focallength > 0)
377  {
378  commands.push_back(new PanoCommand::UpdateCropFactorCmd(pano, images, papyImages.cropfactor));
379  commands.push_back(new PanoCommand::UpdateFocalLengthCmd(pano, images, papyImages.focallength));
380  };
381  // remove all existing stacks
382  for (size_t i = 1; i < pano.getNrOfImages(); i++)
383  {
384  HuginBase::UIntSet imgs;
385  imgs.insert(i);
387  };
388  // create stacks
389  if (papyImages.HasBracketImages())
390  {
391  size_t stackNr = 0;
392  size_t imgNr = 0;
393  while (imgNr < pano.getNrOfImages())
394  {
395  HuginBase::UIntSet imgs;
396  do
397  {
398  imgs.insert(imgNr);
399  imgNr++;
400  } while (imgNr < pano.getNrOfImages() && papyImages.images[imgNr].bracket != 1);
402  stackNr++;
403  };
404  // unlink position if wished by user
405  if (!dialog.LinkStacks())
406  {
407  std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> variables;
408  variables.insert(HuginBase::ImageVariableGroup::IVE_Yaw);
409  variables.insert(HuginBase::ImageVariableGroup::IVE_Pitch);
410  variables.insert(HuginBase::ImageVariableGroup::IVE_Roll);
411  variables.insert(HuginBase::ImageVariableGroup::IVE_X);
412  variables.insert(HuginBase::ImageVariableGroup::IVE_Y);
413  variables.insert(HuginBase::ImageVariableGroup::IVE_Z);
414  variables.insert(HuginBase::ImageVariableGroup::IVE_TranslationPlaneYaw);
415  variables.insert(HuginBase::ImageVariableGroup::IVE_TranslationPlanePitch);
416  commands.push_back(new PanoCommand::ChangePartImagesLinkingCmd(pano, images, variables, false, HuginBase::StandardImageVariableGroups::getStackVariables()));
417  }
418  };
419  // now set the positions
420  HuginBase::VariableMapVector variables = pano.getVariables();
421  for (size_t i = 0; i < papyImages.images.size(); ++i)
422  {
423  map_get(variables[i], "y").setValue(papyImages.images[i].yaw);
424  map_get(variables[i], "p").setValue(papyImages.images[i].pitch);
425  map_get(variables[i], "r").setValue(papyImages.images[i].roll);
426  map_get(variables[i], "TrX").setValue(0);
427  map_get(variables[i], "TrY").setValue(0);
428  map_get(variables[i], "TrZ").setValue(0);
429  map_get(variables[i], "Tpy").setValue(0);
430  map_get(variables[i], "Tpp").setValue(0);
431  // fov gets updated when focal length is set, this has not yet been happen
432  // so remove fov from list to prevent overwritting with old value, because
433  // variables have not yet been updated yet
434  variables[i].erase("v");
435  };
436  commands.push_back(new PanoCommand::UpdateVariablesCmd(pano, variables));
438 
439  // now create the cp
440  if (dialog.RunCpfind())
441  {
442  //save project into temp directory
443  wxString tempDir = wxConfig::Get()->Read(wxT("tempDir"), wxT(""));
444  if (!tempDir.IsEmpty())
445  {
446  if (tempDir.Last() != wxFileName::GetPathSeparator())
447  {
448  tempDir.Append(wxFileName::GetPathSeparator());
449  }
450  };
451  wxFileName scriptFileName(wxFileName::CreateTempFileName(tempDir + wxT("hp")));
452  const std::string scriptString(scriptFileName.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
453  pano.WritePTOFile(scriptString, hugin_utils::getPathPrefix(scriptString));
454  // build command queue
455  const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
457  const wxString quotedProject(HuginQueue::wxEscapeFilename(scriptFileName.GetFullPath()));
458  commands->push_back(new HuginQueue::NormalCommand(HuginQueue::GetInternalProgram(exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR), wxT("cpfind")),
459  dialog.GetCPFindParam() + wxT(" --prealigned -o ") + quotedProject + wxT(" ") + quotedProject, _("Searching for control points...")));
460  if (dialog.RunGeocpset())
461  {
462  commands->push_back(new HuginQueue::NormalCommand(HuginQueue::GetInternalProgram(exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR), wxT("geocpset")),
463  wxT("-o ") + quotedProject + wxT(" ") + quotedProject, _("Connecting overlapping images")));
464  };
465  //execute queue
466  MyExecuteCommandQueue(commands, wxGetActiveWindow(), _("Searching control points"));
467  //read back panofile
469  (const char *)scriptFileName.GetFullPath().mb_str(HUGIN_CONV_FILENAME),
470  (const char *)scriptFileName.GetPath(wxPATH_NATIVE | wxPATH_GET_SEPARATOR).mb_str(HUGIN_CONV_FILENAME),
471  false, false));
472  //delete temporary files
473  wxRemoveFile(scriptFileName.GetFullPath());
474  };
475  return true;
476 }
477 
478 } // namespace Papywizard
479 
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
PapywizardSettings()
constructor, initialize some values
std::vector< PapywizardImage > images
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
Model for a panorama.
Definition: Panorama.h:152
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
Definition: utils.cpp:184
HuginBase::SrcPanoImage::Projection projection
VariableMapVector getVariables() const
get variables of this panorama
Definition: Panorama.cpp:118
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)
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Store window size and position in configfile/registry.
Definition: LensCalApp.cpp:210
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:156
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
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
Definition: Panorama.cpp:2059
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)