Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AssistantExecutor.cpp
Go to the documentation of this file.
1 
8 /* This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This software is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this software. If not, see
20 * <http://www.gnu.org/licenses/>.
21 *
22 */
23 
24 #include "base_wx/platform.h"
25 #include "AssistantExecutor.h"
26 
27 #include <wx/config.h>
28 #include <wx/translation.h>
29 #include <wx/fileconf.h>
30 #include <wx/wfstream.h>
31 #include "hugin_utils/utils.h"
33 #include "base_wx/wxPlatform.h"
34 #include "hugin/config_defaults.h"
35 
36 
37 namespace HuginQueue
38 {
39  CommandQueue* GetAssistantCommandQueue(const HuginBase::Panorama & pano, const wxString& ExePath, const wxString& project)
40  {
41  CommandQueue* commands=new CommandQueue();
42  wxString quotedProject(wxEscapeFilename(project));
43 
44  //read main settings
45  wxConfigBase* config = wxConfigBase::Get();
46  const bool runCeleste = config->Read(wxT("/Celeste/Auto"), HUGIN_CELESTE_AUTO) != 0;
47  double celesteThreshold;
48  config->Read(wxT("/Celeste/Threshold"), &celesteThreshold, HUGIN_CELESTE_THRESHOLD);
49  const bool celesteSmallRadius = config->Read(wxT("/Celeste/Filter"), HUGIN_CELESTE_FILTER) == 0;
50  const bool runLinefind = (pano.getNrOfImages()==1) ? true : (config->Read(wxT("/Assistant/Linefind"), HUGIN_ASS_LINEFIND) != 0);
51  const bool runCPClean = config->Read(wxT("/Assistant/AutoCPClean"), HUGIN_ASS_AUTO_CPCLEAN) != 0;
52  double scale;
53  config->Read(wxT("/Assistant/panoDownsizeFactor"), &scale, HUGIN_ASS_PANO_DOWNSIZE_FACTOR);
54  bool hasUserDefinedOutputIni = (config->Read("/Assistant/UserDefinedOutputOption", 0l) == 1l);
55  if (hasUserDefinedOutputIni)
56  {
57  // user defined output options, read from ini
58  const wxFileName iniFilename(hugin_utils::GetUserAppDataDir(), "output.ini");
59  hasUserDefinedOutputIni = iniFilename.FileExists();
60  };
61 
62  bool runicp = (pano.getNrOfCtrlPoints() == 0);
63  if (!runicp)
64  {
65  //we check, if all images are connected
66  //if not, we run also icpfind
67  HuginGraph::ImageGraph graph(pano);
68  runicp = !graph.IsConnected();
69  };
70  //build commandline for icpfind
71  if (runicp && pano.getNrOfImages() > 1)
72  {
73  //create cp find
74  commands->push_back(new NormalCommand(GetInternalProgram(ExePath, wxT("icpfind")),
75  wxT("-o ") + quotedProject + wxT(" ") + quotedProject, _("Searching for control points...")));
76  //building celeste command
77  if (runCeleste)
78  {
79  wxString args;
80  args << wxT("-t ") << wxStringFromCDouble(celesteThreshold) << wxT(" ");
81  if (celesteSmallRadius)
82  {
83  args.Append(wxT("-r 1 "));
84  }
85  args.Append(wxT("-o ") + quotedProject + wxT(" ") + quotedProject);
86  commands->push_back(new NormalCommand(GetInternalProgram(ExePath, wxT("celeste_standalone")),
87  args, _("Removing control points in clouds...")));
88  };
89  //building cpclean command
90  if (runCPClean)
91  {
92  commands->push_back(new NormalCommand(GetInternalProgram(ExePath, wxT("cpclean")),
93  wxT("-o ") + quotedProject + wxT(" ") + quotedProject, _("Statistically cleaning of control points...")));
94  };
95  };
96  //vertical line detector
97  if (runLinefind)
98  {
99  const HuginBase::CPVector allCP = pano.getCtrlPoints();
100  bool hasVerticalLines = false;
101  if (!allCP.empty())
102  {
103  for (size_t i = 0; i < allCP.size() && !hasVerticalLines; i++)
104  {
105  hasVerticalLines = (allCP[i].mode == HuginBase::ControlPoint::X);
106  };
107  };
108  if (!hasVerticalLines)
109  {
110  commands->push_back(new NormalCommand(GetInternalProgram(ExePath, wxT("linefind")),
111  wxT("--output=") + quotedProject + wxT(" ") + quotedProject, _("Searching for vertical lines...")));
112  };
113  };
114  //now optimise all
115  commands->push_back(new NormalCommand(GetInternalProgram(ExePath, wxT("checkpto")), quotedProject));
116  if (pano.getNrOfImages() == 1)
117  {
118  commands->push_back(new NormalCommand(GetInternalProgram(ExePath, wxT("autooptimiser")),
119  (hasUserDefinedOutputIni ? wxT("-a -o ") : wxT("-a -s -o ")) + quotedProject + wxT(" ") + quotedProject, _("Optimizing...")));
120  }
121  else
122  {
123  commands->push_back(new NormalCommand(GetInternalProgram(ExePath, wxT("autooptimiser")),
124  (hasUserDefinedOutputIni ? wxT("-a -m -l -o ") : wxT("-a -m -l -s -o ")) + quotedProject + wxT(" ") + quotedProject, _("Optimizing...")));
125  };
126  wxString panoModifyArgs;
127  wxString label(_("Searching for best crop..."));
128  if(hasUserDefinedOutputIni)
129  {
130  const wxFileName iniFilename(hugin_utils::GetUserAppDataDir(), "output.ini");
131  panoModifyArgs << wxT("--ini=") << wxEscapeFilename(iniFilename.GetFullPath()) << wxT(" ");
132  label = wxString::Format("Setting options from %s", iniFilename.GetFullName().c_str());
133  }
134  else
135  {
136  // if necessary scale down final pano
137  if (scale <= 1.0)
138  {
139  panoModifyArgs << wxT("--canvas=") << hugin_utils::roundi(scale * 100) << wxT("% ");
140  };
141  panoModifyArgs.Append(wxT("--crop=AUTO "));
142  };
143  panoModifyArgs.Append(wxT("--output=") + quotedProject + wxT(" ") + quotedProject);
144  commands->push_back(new NormalCommand(GetInternalProgram(ExePath, wxT("pano_modify")), panoModifyArgs, label));
145  return commands;
146  }
147 
148  CommandQueue * GetAssistantCommandQueueUserDefined(const HuginBase::Panorama & pano, const wxString & ExePath, const wxString & project, const wxString & assistantSetting, wxArrayString& tempFilesDelete, std::ostream& errStream)
149  {
150  CommandQueue* commands = new CommandQueue;
151  const wxString quotedProject(wxEscapeFilename(project));
152 
153  if (pano.getNrOfImages()==0)
154  {
155  errStream << "ERROR: Project contains no images. Nothing to do." << std::endl;
156  return commands;
157  };
158  const wxString quotedImage0(wxEscapeFilename(wxString(pano.getImage(0).getFilename().c_str(), HUGIN_CONV_FILENAME)));
159  wxFileInputStream input(assistantSetting);
160  if (!input.IsOk())
161  {
162  errStream << "ERROR: Can not open file \"" << assistantSetting.mb_str(wxConvLocal) << "\"." << std::endl;
163  return commands;
164  }
165  wxFileConfig settings(input);
166  long stepCount;
167  settings.Read(wxT("/General/StepCount"), &stepCount, 0);
168  if (stepCount == 0)
169  {
170  errStream << "ERROR: User-setting does not define any assistant steps." << std::endl;
171  return commands;
172  };
173  // create some condition variables
174  const bool hascp = (pano.getNrOfCtrlPoints() > 0);
175  bool isConnected = false;
176  bool hasVerticalLines = false;
177  if (hascp)
178  {
179  //we check, if all images are connected
180  HuginGraph::ImageGraph graph(pano);
181  isConnected = graph.IsConnected();
182  // check, if there are line cp
183  const HuginBase::CPVector allCP = pano.getCtrlPoints();
184  if (!allCP.empty())
185  {
186  for (size_t i = 0; i < allCP.size() && !hasVerticalLines; i++)
187  {
188  hasVerticalLines = (allCP[i].mode == HuginBase::ControlPoint::X);
189  };
190  };
191  };
192  wxString imageListFile;
193 
194  for (size_t i = 0; i < stepCount; ++i)
195  {
196  wxString stepString(wxT("/Step"));
197  stepString << i;
198  if (!settings.HasGroup(stepString))
199  {
200  errStream << "ERROR: Assistant specifies " << stepCount << " steps, but step " << i << " is missing in configuration." << std::endl;
201  CleanQueue(commands);
202  return commands;
203  }
204  settings.SetPath(stepString);
205  // check some conditions
206  const wxString condition = GetSettingString(&settings, "Condition");
207  if (condition.CmpNoCase("no cp") == 0 && hascp)
208  {
209  continue;
210  };
211  if (condition.CmpNoCase("not connected") == 0 && isConnected)
212  {
213  continue;
214  };
215  if (condition.CmpNoCase("no line cp") == 0 && hasVerticalLines)
216  {
217  continue;
218  };
219  if (condition.CmpNoCase("single image") == 0 && pano.getNrOfImages() != 1)
220  {
221  continue;
222  };
223  // read program name
224  const wxString progName = GetSettingString(&settings, wxT("Program"));
225  if (progName.IsEmpty())
226  {
227  errStream << "ERROR: Step " << i << " has no program name specified." << std::endl;
228  CleanQueue(commands);
229  return commands;
230  };
231 #ifdef __WXMAC__
232  // check if program can be found in bundle
233  const wxString prog = GetExternalProgram(wxConfig::Get(), ExePath, progName);
234 #elif defined __WXMSW__
235 
236  const wxString prog = MSWGetProgname(ExePath, progName);
237 #else
238  const wxString prog = progName;
239 #endif
240  wxString args = GetSettingString(&settings, wxT("Arguments"));
241  if (args.IsEmpty())
242  {
243  errStream << "ERROR: Step " << i << " has no arguments given." << std::endl;
244  CleanQueue(commands);
245  return commands;
246  }
247  args.Replace("%project%", quotedProject, true);
248  args.Replace("%image0%", quotedImage0, true);
249  // build image list file if needed
250  if (imageListFile.IsEmpty() && args.Find("%imagelist%") != wxNOT_FOUND)
251  {
252  wxFileName tempImageList(wxFileName::CreateTempFileName(GetConfigTempDir(wxConfig::Get()) + wxT("hi")));
253  imageListFile = tempImageList.GetFullPath();
254  tempFilesDelete.Add(imageListFile);
255  wxFFileOutputStream outputStream(imageListFile);
256  wxTextOutputStream outputFile(outputStream);
257  // write image list file
258  for (auto i = 0; i < pano.getNrOfImages(); ++i)
259  {
260  outputFile << wxString(pano.getImage(i).getFilename().c_str(), HUGIN_CONV_FILENAME) << endl;
261  }
262  outputFile.Flush();
263  };
264  if (!imageListFile.IsEmpty())
265  {
266  args.Replace("%imagelist%", wxEscapeFilename(imageListFile));
267  };
268  const wxString description = GetSettingStringTranslated(&settings, wxT("Description"));
269  commands->push_back(new NormalCommand(prog, args, description));
270  }
271  return commands;
272  };
273 
274 }; // namespace
const wxString GetSettingString(wxConfigBase *setting, const wxString &name, const wxString defaultValue)
read a string from setting and remove all whitespaces
Definition: Executor.cpp:281
normal command for queue, processing is stopped if an error occurred in program
Definition: Executor.h:37
implementation of huginApp Class
const wxString GetConfigTempDir(const wxConfigBase *config)
return the temp dir from the preferences, ensure that it ends with path separator ...
Definition: Executor.cpp:302
int roundi(T x)
Definition: hugin_math.h:73
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
bool IsConnected()
check if all images are connected
Definition: ImageGraph.cpp:128
wxString GetInternalProgram(const wxString &bindir, const wxString &name)
return path and name of external program, which comes bundled with Hugin
Definition: Executor.cpp:129
std::size_t getNrOfCtrlPoints() const
number of control points
Definition: Panorama.h:306
const CPVector & getCtrlPoints() const
get all control point of this Panorama
Definition: Panorama.h:319
CommandQueue * GetAssistantCommandQueue(const HuginBase::Panorama &pano, const wxString &ExePath, const wxString &project)
generates the command queue for running the assistant
Model for a panorama.
Definition: Panorama.h:152
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
#define HUGIN_CELESTE_FILTER
#define HUGIN_CELESTE_THRESHOLD
evaluate x, points are on a vertical line
Definition: ControlPoint.h:47
void CleanQueue(CommandQueue *queue)
clean the queue, delete all entries, but not the queue itself
Definition: Executor.cpp:118
#define HUGIN_ASS_LINEFIND
const wxString GetSettingStringTranslated(wxConfigBase *setting, const wxString &name, const wxString defaultValue)
read a translated string from settings and remove all whitespaces
Definition: Executor.cpp:288
str wxEscapeFilename(const str &arg)
special escaping routine for CommandQueues
Definition: Executor.h:79
std::string GetUserAppDataDir()
returns the directory for user specific Hugin settings, e.g.
Definition: utils.cpp:497
#define HUGIN_ASS_PANO_DOWNSIZE_FACTOR
std::vector< ControlPoint > CPVector
Definition: ControlPoint.h:99
platform/compiler specific stuff.
#define HUGIN_ASS_AUTO_CPCLEAN
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
CommandQueue * GetAssistantCommandQueueUserDefined(const HuginBase::Panorama &pano, const wxString &ExePath, const wxString &project, const wxString &assistantSetting, wxArrayString &tempFilesDelete, std::ostream &errStream)
generates the command queue for running the assistant
wxString GetExternalProgram(wxConfigBase *config, const wxString &bindir, const wxString &name)
return path and name of external program, which can be overwritten by the user
Definition: Executor.cpp:148
std::vector< NormalCommand * > CommandQueue
Definition: Executor.h:61
#define HUGIN_CELESTE_AUTO
wxString wxStringFromCDouble(double val, int precision)
convert double to wxString, it is always using a &#39;.
Definition: Executor.cpp:238
create a CommandQueue for running the assistant using CLI tools
class to work with images graphs created from a HuginBase::Panorama class it creates a graph based on...
Definition: ImageGraph.h:44