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"
36 #include "base_wx/wxutils.h"
38 #include "base_wx/wxPanoCommand.h"
40 #include "hugin/config_defaults.h"
41 
42 namespace Papywizard
43 {
44 
47 {
48 public:
49  // read from header
50  double focallength;
51  double cropfactor;
53  // read from shoot section
55  {
56  size_t id;
57  size_t bracket;
58  double yaw, pitch, roll;
59  };
60 
61  std::vector<PapywizardImage> images;
64  {
65  focallength = 0;
66  cropfactor = 1;
68  };
69 
70  bool HasBracketImages() const
71  {
72  for (size_t i = 0; i < images.size(); ++i)
73  {
74  if (images[i].bracket > 1)
75  {
76  return true;
77  };
78  };
79  return false;
80  };
81 };
82 
84 bool ParseHeader(wxXmlNode* root, PapywizardSettings& images)
85 {
86  wxXmlNode* child = root->GetChildren();
87  while (child)
88  {
89  // section <camera>
90  if (child->GetName().CmpNoCase("camera") == 0)
91  {
92  wxXmlNode* camChild = child->GetChildren();
93  while (camChild)
94  {
95  // crop factor is saved as attribute in <sensor>
96  if (camChild->GetName().CmpNoCase("sensor") == 0)
97  {
98  wxString number;
99  if (camChild->GetAttribute("coef", &number))
100  {
101  if (!hugin_utils::stringToDouble(std::string(number.mb_str(wxConvLocal)), images.cropfactor))
102  {
103  return false;
104  };
105  };
106  }
107  camChild = camChild->GetNext();
108  }
109  }
110  // section <lens>
111  if (child->GetName().CmpNoCase("lens") == 0)
112  {
113  // projection as type attribute
114  wxString projection = child->GetAttribute("type", wxEmptyString).Trim().Trim(false);
115  if (!projection.empty())
116  {
117  if (projection.CmpNoCase("rectilinear") == 0)
118  {
120  }
121  else
122  {
123  if (projection.CmpNoCase("fisheye") == 0)
124  {
126  }
127  else
128  {
129  return false;
130  };
131  };
132  };
133  // focal length as own element
134  wxXmlNode* lensChild = child->GetChildren();
135  while (lensChild)
136  {
137  if (lensChild->GetName().CmpNoCase("focal") == 0)
138  {
139  wxString focallength = lensChild->GetNodeContent().Trim().Trim(false);
140  if(!hugin_utils::stringToDouble(std::string(focallength.mb_str(wxConvLocal)), images.focallength))
141  {
142  return false;
143  };
144  }
145  lensChild = lensChild->GetNext();
146  }
147  };
148  child = child->GetNext();
149  };
150  return true;
151 };
152 
154 bool ParseShoot(wxXmlNode* root, PapywizardSettings& images)
155 {
156  wxXmlNode* child = root->GetChildren();
157  size_t id = 1;
158  while (child)
159  {
160  if (child->GetName().CmpNoCase("pict") == 0)
161  {
163  long longVal;
164  wxString s;
165 #ifdef PAPYWIZARD_USE_ID_CHECK
166  // according to the spec the id should be unique
167  // but not all programs write the id in this way
168  // e.g. PCPano is using the same id for each image in a bracket
169  // see https://bugs.launchpad.net/hugin/+bug/1840110
170  // so the check id code is disabled for now
171  // so activate the check again define PAPYWIZARD_USE_ID_CHECK
172  if (!child->GetAttribute("id", &s))
173  {
174  return false;
175  };
176  if (!s.ToLong(&longVal))
177  {
178  return false;
179  };
180  if (longVal < id)
181  {
182  return false;
183  };
184  image.id = longVal;
185 #else
186  // instead simply store a continous id
187  image.id = id;
188 #endif
189  ++id;
190  // read bracket attribute
191  if(!child->GetAttribute("bracket", &s))
192  {
193  return false;
194  };
195  if (!s.ToLong(&longVal))
196  {
197  return false;
198  };
199  image.bracket = longVal;
200  // now parse all position entries
201  wxXmlNode* posChild = child->GetChildren();
202  while (posChild)
203  {
204  if (posChild->GetName().CmpNoCase("position") == 0)
205  {
206  if (!posChild->GetAttribute("yaw", &s))
207  {
208  return false;
209  };
210  if (!hugin_utils::stringToDouble(std::string(s.mb_str(wxConvLocal)), image.yaw))
211  {
212  return false;
213  };
214  if (!posChild->GetAttribute("pitch", &s))
215  {
216  return false;
217  }
218  if (!hugin_utils::stringToDouble(std::string(s.mb_str(wxConvLocal)), image.pitch))
219  {
220  return false;
221  };
222  if (!posChild->GetAttribute("roll", &s))
223  {
224  return false;
225  };
226  if (!hugin_utils::stringToDouble(std::string(s.mb_str(wxConvLocal)), image.roll))
227  {
228  return false;
229  };
230  images.images.push_back(image);
231  // we are ignoring all further entries
232  break;
233  };
234  posChild = posChild->GetNext();
235  };
236  };
237  child = child->GetNext();
238  };
239  return true;
240 };
241 
242 bool ParsePapywizardFile(const wxString& filename, PapywizardSettings& images)
243 {
244  wxXmlDocument xmlFile;
245  if (!xmlFile.Load(filename))
246  {
247  return false;
248  }
249  if (xmlFile.GetRoot()->GetName().CmpNoCase("papywizard") != 0)
250  {
251  // not a papywizard file
252  return false;
253  };
254  // iterate all children
255  wxXmlNode* child = xmlFile.GetRoot()->GetChildren();
256  while (child)
257  {
258  if (child->GetName().CmpNoCase("header") == 0)
259  {
260  if (!ParseHeader(child, images))
261  {
262  return false;
263  };
264  };
265  if (child->GetName().CmpNoCase("shoot") == 0)
266  {
267  if (!ParseShoot(child, images))
268  {
269  return false;
270  };
271  }
272  child = child->GetNext();
273  }
274  return true;
275 };
276 
277 class PapywizardImportDialog: public wxDialog
278 {
279 public:
281  PapywizardImportDialog(wxWindow *parent)
282  {
283  wxXmlResource::Get()->LoadDialog(this, parent, "papywizard_import_dialog");
284 
285  m_linkPos = XRCCTRL(*this, "papywizard_link_positions", wxCheckBox);
286  m_cpfind = XRCCTRL(*this, "papywizard_cpfind", wxCheckBox);
287  m_cpfind->Bind(wxEVT_CHECKBOX, &PapywizardImportDialog::OnCpfindCheck, this);
288  m_cpfindParams = XRCCTRL(*this, "papywizard_cpfind_parameters", wxTextCtrl);
289  m_geocpset = XRCCTRL(*this, "papywizard_geocpset", wxCheckBox);
290  const wxString cpfindParams = wxConfig::Get()->Read("/PapywizardImportCpfind", wxEmptyString);
291  m_cpfindParams->SetValue(cpfindParams);
292  hugin_utils::RestoreFramePosition(this, "PapywizardImportDialog");
293  };
296  {
297  hugin_utils::StoreFramePosition(this, "PapywizardImportDialog");
298  if (m_cpfind->IsChecked())
299  {
300  wxConfig::Get()->Write("/PapywizardImportCpfind", m_cpfindParams->GetValue());
301  };
302  };
303  void EnableStack(const bool hasStacks)
304  {
305  m_linkPos->Enable(hasStacks);
306  m_linkPos->SetValue(hasStacks);
307  };
308  const bool LinkStacks() const
309  {
310  return m_linkPos->IsEnabled() && m_linkPos->IsChecked();
311  };
312  const bool RunCpfind() const
313  {
314  return m_cpfind->IsChecked();
315  };
316  const wxString GetCPFindParam() const
317  {
318  return m_cpfindParams->GetValue();
319  };
320  const bool RunGeocpset() const
321  {
322  return m_geocpset->IsEnabled() && m_geocpset->IsChecked();
323  };
324 protected:
325  void OnCpfindCheck(wxCommandEvent& e)
326  {
327  const bool cpfindActive = m_cpfind->IsChecked();
328  m_cpfindParams->Enable(cpfindActive);
329  m_geocpset->Enable(cpfindActive);
330  };
331 private:
332  wxCheckBox* m_linkPos;
333  wxCheckBox* m_cpfind;
334  wxTextCtrl* m_cpfindParams;
335  wxCheckBox* m_geocpset;
336 };
337 
338 bool ImportPapywizardFile(const wxString& filename, HuginBase::Panorama& pano)
339 {
340  PapywizardSettings papyImages;
341  if (!ParsePapywizardFile(filename, papyImages))
342  {
343  hugin_utils::HuginMessageBox(wxString::Format(_("Could not parse file %s as Papywizard XML file."), filename),
344  _("Hugin"), wxOK | wxICON_ERROR, wxGetActiveWindow());
345  return false;
346  };
347  // check if number of images matches
348  if(papyImages.images.size()!=pano.getNrOfImages())
349  {
350  hugin_utils::HuginMessageBox(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())),
351  _("Hugin"), wxOK | wxICON_ERROR, wxGetActiveWindow());
352  return false;
353  };
354  PapywizardImportDialog dialog(wxGetActiveWindow());
355  dialog.EnableStack(papyImages.HasBracketImages());
356  if(dialog.ShowModal()!=wxID_OK)
357  {
358  return false;
359  };
360  // now we can build all commands
361  std::vector<PanoCommand::PanoCommand *> commands;
362  HuginBase::UIntSet images;
363  fill_set(images, 0, pano.getNrOfImages() - 1);
364  // all images share the same lens
366  commands.push_back(new PanoCommand::ChangeImageProjectionCmd(pano, images, papyImages.projection));
367  if (papyImages.focallength > 0)
368  {
369  commands.push_back(new PanoCommand::UpdateCropFactorCmd(pano, images, papyImages.cropfactor));
370  commands.push_back(new PanoCommand::UpdateFocalLengthCmd(pano, images, papyImages.focallength));
371  };
372  // remove all existing stacks
373  for (size_t i = 1; i < pano.getNrOfImages(); i++)
374  {
375  HuginBase::UIntSet imgs;
376  imgs.insert(i);
378  };
379  // create stacks
380  if (papyImages.HasBracketImages())
381  {
382  size_t stackNr = 0;
383  size_t imgNr = 0;
384  while (imgNr < pano.getNrOfImages())
385  {
386  HuginBase::UIntSet imgs;
387  do
388  {
389  imgs.insert(imgNr);
390  imgNr++;
391  } while (imgNr < pano.getNrOfImages() && papyImages.images[imgNr].bracket != 1);
393  stackNr++;
394  };
395  // unlink position if wished by user
396  if (!dialog.LinkStacks())
397  {
398  std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> variables;
399  variables.insert(HuginBase::ImageVariableGroup::IVE_Yaw);
400  variables.insert(HuginBase::ImageVariableGroup::IVE_Pitch);
401  variables.insert(HuginBase::ImageVariableGroup::IVE_Roll);
402  variables.insert(HuginBase::ImageVariableGroup::IVE_X);
403  variables.insert(HuginBase::ImageVariableGroup::IVE_Y);
404  variables.insert(HuginBase::ImageVariableGroup::IVE_Z);
405  variables.insert(HuginBase::ImageVariableGroup::IVE_TranslationPlaneYaw);
406  variables.insert(HuginBase::ImageVariableGroup::IVE_TranslationPlanePitch);
407  commands.push_back(new PanoCommand::ChangePartImagesLinkingCmd(pano, images, variables, false, HuginBase::StandardImageVariableGroups::getStackVariables()));
408  }
409  };
410  // now set the positions
411  HuginBase::VariableMapVector variables = pano.getVariables();
412  for (size_t i = 0; i < papyImages.images.size(); ++i)
413  {
414  map_get(variables[i], "y").setValue(papyImages.images[i].yaw);
415  map_get(variables[i], "p").setValue(papyImages.images[i].pitch);
416  map_get(variables[i], "r").setValue(papyImages.images[i].roll);
417  map_get(variables[i], "TrX").setValue(0);
418  map_get(variables[i], "TrY").setValue(0);
419  map_get(variables[i], "TrZ").setValue(0);
420  map_get(variables[i], "Tpy").setValue(0);
421  map_get(variables[i], "Tpp").setValue(0);
422  // fov gets updated when focal length is set, this has not yet been happen
423  // so remove fov from list to prevent overwritting with old value, because
424  // variables have not yet been updated yet
425  variables[i].erase("v");
426  };
427  commands.push_back(new PanoCommand::UpdateVariablesCmd(pano, variables));
429 
430  // now create the cp
431  if (dialog.RunCpfind())
432  {
433  //save project into temp directory
434  wxString tempDir = wxConfig::Get()->Read("tempDir", wxEmptyString);
435  if (!tempDir.IsEmpty())
436  {
437  if (tempDir.Last() != wxFileName::GetPathSeparator())
438  {
439  tempDir.Append(wxFileName::GetPathSeparator());
440  }
441  };
442  wxFileName scriptFileName(wxFileName::CreateTempFileName(tempDir + "hp"));
443  const std::string scriptString(scriptFileName.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
444  pano.WritePTOFile(scriptString, hugin_utils::getPathPrefix(scriptString));
445  // build command queue
446  const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
448  const wxString quotedProject(HuginQueue::wxEscapeFilename(scriptFileName.GetFullPath()));
449  commands->push_back(new HuginQueue::NormalCommand(HuginQueue::GetInternalProgram(exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR), "cpfind"),
450  dialog.GetCPFindParam() + " --prealigned -o " + quotedProject + " " + quotedProject, _("Searching for control points...")));
451  if (dialog.RunGeocpset())
452  {
453  commands->push_back(new HuginQueue::NormalCommand(HuginQueue::GetInternalProgram(exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR), "geocpset"),
454  "-o " + quotedProject + " " + quotedProject, _("Connecting overlapping images")));
455  };
456  //execute queue
457  MyExecuteCommandQueue(commands, wxGetActiveWindow(), _("Searching control points"));
458  //read back panofile
460  (const char *)scriptFileName.GetFullPath().mb_str(HUGIN_CONV_FILENAME),
461  (const char *)scriptFileName.GetPath(wxPATH_NATIVE | wxPATH_GET_SEPARATOR).mb_str(HUGIN_CONV_FILENAME),
462  false, false));
463  //delete temporary files
464  wxRemoveFile(scriptFileName.GetFullPath());
465  };
466  return true;
467 }
468 
469 } // namespace Papywizard
470 
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
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
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
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Definition: wxutils.cpp:135
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
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition: wxutils.cpp:176
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)
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Definition: wxutils.cpp:67