PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusConfig.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2  Program: Plus
3  Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4  See License.txt for details.
5 =========================================================Plus=header=end*/
6 
7 #include "PlusConfigure.h"
8 #include "vtkDirectory.h"
9 #include "vtkMatrix4x4.h"
10 #include "vtkIGSIORecursiveCriticalSection.h"
11 #include "vtkXMLUtilities.h"
12 #include "vtksys/SystemTools.hxx"
13 
14 // Needed for proper singleton initialization
15 // The vtkDebugLeaks singleton must be initialized before and
16 // destroyed after the vtkPlusConfig singleton.
17 #include "vtkDebugLeaksManager.h"
18 #include "vtkObjectFactory.h"
19 
20 #if _WIN32
21 #include <stdlib.h>
22 #include <shlobj.h>
23 #elif defined(unix) || defined(__unix__) || defined(__unix)
24 #include "unistd.h"
25 #elif defined(__APPLE__)
26 #include <unistd.h>
27 #include <mach-o/dyld.h>
28 #endif
29 
30 static const char APPLICATION_CONFIGURATION_FILE_NAME[] = "PlusConfig.xml";
31 
32 
33 vtkPlusConfig* vtkPlusConfig::Instance = NULL;
34 
35 //-----------------------------------------------------------------------------
36 class vtkPlusConfigCleanup
37 {
38 public:
39  inline void Use()
40  {
41  }
42 
43  ~vtkPlusConfigCleanup()
44  {
46  {
48  }
49  }
50 };
51 //------ File local content ---------------------------------------------------
52 namespace
53 {
54  // Ensure creation order to prevent crashing during ~vtkPlusConfigCleanup()
55  // ConfigCreationCriticalSection must be destroyed AFTER vtkPlusConfigCleanupGlobal
56  struct StaticVariables
57  {
58  vtkIGSIOSimpleRecursiveCriticalSection ConfigCreationCriticalSection;
59  vtkPlusConfigCleanup vtkPlusConfigCleanupGlobal;
60  };
61  StaticVariables staticVariables;
62 }
63 
64 //-----------------------------------------------------------------------------
66 {
68 }
69 
70 //-----------------------------------------------------------------------------
72 {
73  if (!vtkPlusConfig::Instance)
74  {
75  igsioLockGuard<vtkIGSIOSimpleRecursiveCriticalSection> criticalSectionGuardedLock(&(staticVariables.ConfigCreationCriticalSection));
76 
77  if (vtkPlusConfig::Instance != NULL)
78  {
79  return vtkPlusConfig::Instance;
80  }
81 
82  staticVariables.vtkPlusConfigCleanupGlobal.Use();
83 
84  // Need to call vtkObjectFactory::CreateInstance method because this
85  // registers the class in the vtkDebugLeaks::MemoryTable.
86  // Without this we would get a "Deleting unknown object" VTK warning on application exit
87  // (in debug mode, with debug leak checking enabled).
88  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkPlusConfig");
89  if (ret)
90  {
91  vtkPlusConfig::Instance = static_cast<vtkPlusConfig*>(ret);
92  }
93  else
94  {
95  vtkPlusConfig::Instance = new vtkPlusConfig();
96  }
97  }
98 
99  // return the instance
100  return vtkPlusConfig::Instance;
101 }
102 
103 //-----------------------------------------------------------------------------
105 {
106  if (vtkPlusConfig::Instance == instance)
107  {
108  return;
109  }
110  // preferably this will be NULL
111  if (vtkPlusConfig::Instance)
112  {
113  vtkPlusConfig::Instance->Delete();
114  }
115  vtkPlusConfig::Instance = instance;
116 
117  // user will call ->Delete() after setting instance
118  if (instance != NULL)
119  {
120  instance->Register(NULL);
121  }
122 }
123 
124 //-----------------------------------------------------------------------------
126  : DeviceSetConfigurationData(NULL)
127  , ApplicationConfigurationData(NULL)
128 {
129  // vtkIGSIOAccurateTimer will instantiate the logger singleton to a vtkIGSIOLogger
130  // Need to instantiate the singleton as a vtkPlusLogger
132 
133  this->ApplicationStartTimestamp = vtkIGSIOAccurateTimer::GetInstance()->GetDateAndTimeString();
134 
135  // Retrieve the program directory (where the exe file is located)
137 
138  // Load settings from PlusConfig.xml
140 }
141 
142 //-----------------------------------------------------------------------------
144 {
145  this->SetDeviceSetConfigurationData(NULL);
147 }
148 
149 //-----------------------------------------------------------------------------
151 {
152 #ifdef _WIN32
153  char cProgramPath[2048] = {'\0'};
154  GetModuleFileName(NULL, cProgramPath, 2048);
155  this->ProgramDirectory = vtksys::SystemTools::GetProgramPath(cProgramPath);
156 #elif defined(__linux__)
157  const unsigned int cProgramPathSize = 2048;
158  char cProgramPath[cProgramPathSize] = {'\0'};
159 
160  // linux
161  if (readlink("/proc/self/exe", cProgramPath, cProgramPathSize) != -1)
162  {
163  // linux
164  std::string path = vtksys::SystemTools::CollapseFullPath(cProgramPath);
165  std::string dirName;
166  std::string fileName;
167  vtksys::SystemTools::SplitProgramPath(path.c_str(), dirName, fileName);
168  this->ProgramDirectory = dirName;
169  }
170  else
171  {
172  // non-linux systems
173  // currently simply the working directory is used instead of the executable path
174  // see http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
175  std::string path = vtksys::SystemTools::CollapseFullPath("./");
176  LOG_WARNING("Cannot get program path. PlusConfig.xml will be read from " << path);
177  this->ProgramDirectory = path;
178  }
179 #elif defined(__APPLE__)
180  char cProgramPath[2048];
181  uint32_t size = sizeof(cProgramPath);
182  if (_NSGetExecutablePath(cProgramPath, &size) == 0)
183  {
184  std::string path = vtksys::SystemTools::CollapseFullPath(cProgramPath);
185  std::string dirName;
186  std::string fileName;
187  vtksys::SystemTools::SplitProgramPath(path.c_str(), dirName, fileName);
188  this->ProgramDirectory = dirName;
189  }
190  else
191  {
192  std::string path = vtksys::SystemTools::CollapseFullPath("./");
193  LOG_WARNING("Cannot get program path. PlusConfig.xml will be read from " << path);
194  this->ProgramDirectory = path;
195  }
196 #endif
197 }
198 
199 //-----------------------------------------------------------------------------
200 void vtkPlusConfig::SetOutputDirectory(const std::string& aDir)
201 {
202  this->OutputDirectory = aDir;
203 
204  // Set log file name and path to the output directory
205  std::string logfilename = std::string(this->ApplicationStartTimestamp) + "_PlusLog.txt";
206  vtkPlusLogger::Instance()->SetLogFileName(GetOutputPath(logfilename).c_str());
207 }
208 
209 //-----------------------------------------------------------------------------
210 void vtkPlusConfig::SetImageDirectory(const std::string& aDir)
211 {
212  this->ImageDirectory = aDir;
213 }
214 
215 //-----------------------------------------------------------------------------
217 {
218  this->DeviceSetConfigurationDirectory = aDir;
219 }
220 
221 //-----------------------------------------------------------------------------
222 void vtkPlusConfig::SetDeviceSetConfigurationFileName(const std::string& aFilePath)
223 {
224  this->DeviceSetConfigurationFileName = aFilePath;
225 }
226 
227 //----------------------------------------------------------------------------
228 vtkXMLDataElement* vtkPlusConfig::CreateDeviceSetConfigurationFromFile(const std::string& aConfigFile)
229 {
230  // Read main configuration file
231  std::string configFilePath = aConfigFile;
232  if (!vtksys::SystemTools::FileExists(configFilePath, true))
233  {
234  configFilePath = vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationPath(aConfigFile);
235  if (!vtksys::SystemTools::FileExists(configFilePath, true))
236  {
237  LOG_ERROR("Reading device set configuration file failed: " << aConfigFile << " does not exist in the current directory or in " << vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationDirectory());
238  return NULL;
239  }
240  }
241  vtkXMLDataElement* configRootElement = vtkXMLUtilities::ReadElementFromFile(configFilePath.c_str());
242  if (configRootElement == NULL)
243  {
244  LOG_ERROR("Reading device set configuration file failed: syntax error in " << aConfigFile);
245  return NULL;
246  }
247 
248  // Print configuration file contents for debugging purposes
249  LOG_DEBUG("Device set configuration is read from file: " << aConfigFile);
250  std::ostringstream xmlFileContents;
251  igsioCommon::XML::PrintXML(xmlFileContents, vtkIndent(1), configRootElement);
252  LOG_DEBUG("Device set configuration file contents: " << std::endl << xmlFileContents.str());
253 
254  return configRootElement;
255 }
256 
257 //-----------------------------------------------------------------------------
259 {
260  LOG_TRACE("vtkPlusConfig::LoadApplicationConfiguration");
261 
262  if (this->ProgramDirectory.empty())
263  {
264  LOG_ERROR("Unable to read configuration - program directory has to be set first!");
265  return PLUS_FAIL;
266  }
267  std::string applicationConfigurationFilePath = vtksys::SystemTools::CollapseFullPath(APPLICATION_CONFIGURATION_FILE_NAME, this->ProgramDirectory.c_str());
268 
269  bool saveNeeded = false;
270 
271  // Read configuration
272  vtkSmartPointer<vtkXMLDataElement> applicationConfigurationRoot;
273  if (vtksys::SystemTools::FileExists(applicationConfigurationFilePath.c_str(), true))
274  {
275  applicationConfigurationRoot.TakeReference(vtkXMLUtilities::ReadElementFromFile(applicationConfigurationFilePath.c_str()));
276  }
277  if (applicationConfigurationRoot == NULL)
278  {
279  LOG_DEBUG("Application configuration file is not found at '" << applicationConfigurationFilePath << "' - file will be created with default values");
280  applicationConfigurationRoot = vtkSmartPointer<vtkXMLDataElement>::New();
281  applicationConfigurationRoot->SetName("PlusConfig");
282  saveNeeded = true;
283  }
284 
285  this->SetApplicationConfigurationData(applicationConfigurationRoot);
286 
287  // Verify root element name
288  if (!igsioCommon::IsEqualInsensitive(applicationConfigurationRoot->GetName(), "PlusConfig"))
289  {
290  LOG_ERROR("Invalid application configuration file (root XML element of the file '" << applicationConfigurationFilePath << "' should be 'PlusConfig' instead of '" << applicationConfigurationRoot->GetName() << "')");
291  return PLUS_FAIL;
292  }
293 
294  // Read log level
295  int logLevel = 0;
296  if (applicationConfigurationRoot->GetScalarAttribute("LogLevel", logLevel))
297  {
298  vtkPlusLogger::Instance()->SetLogLevel(logLevel);
299  }
300  else
301  {
302  LOG_INFO("LogLevel attribute is not found - default 'Info' log level will be used");
303  vtkPlusLogger::Instance()->SetLogLevel(vtkPlusLogger::LOG_LEVEL_INFO);
304  saveNeeded = true;
305  }
306 
307  // Read last device set config file
308  const char* lastDeviceSetConfigFile = applicationConfigurationRoot->GetAttribute("LastDeviceSetConfigurationFileName");
309  if ((lastDeviceSetConfigFile != NULL) && (STRCASECMP(lastDeviceSetConfigFile, "") != 0))
310  {
311  this->SetDeviceSetConfigurationFileName(lastDeviceSetConfigFile);
312  }
313  else
314  {
315  LOG_DEBUG("Cannot read last used device set config file until you connect to one first");
316  }
317 
318  // Read device set configuration directory
319  const char* deviceSetDirectory = applicationConfigurationRoot->GetAttribute("DeviceSetConfigurationDirectory");
320  if ((deviceSetDirectory != NULL) && (STRCASECMP(deviceSetDirectory, "") != 0))
321  {
322  this->SetDeviceSetConfigurationDirectory(deviceSetDirectory);
323  }
324  else
325  {
326  LOG_INFO("Device set configuration directory is not set - default '../config' will be used");
327  this->SetDeviceSetConfigurationDirectory("../config");
328  saveNeeded = true;
329  }
330  // Make device set configuration directory
331  if (! vtksys::SystemTools::MakeDirectory(GetDeviceSetConfigurationDirectory().c_str()))
332  {
333  LOG_ERROR("Unable to create device set configuration directory '" << GetDeviceSetConfigurationDirectory() << "'");
334  return PLUS_FAIL;
335  }
336 
337  // Read editor application
338  const char* editorApplicationExecutable = applicationConfigurationRoot->GetAttribute("EditorApplicationExecutable");
339  if ((editorApplicationExecutable != NULL) && (STRCASECMP(editorApplicationExecutable, "") != 0))
340  {
341  this->SetEditorApplicationExecutable(editorApplicationExecutable);
342  }
343  else
344  {
345  LOG_DEBUG("Editor application executable is not set - system default will be used");
346 #if _WIN32
347  // Try to find Notepad++ in Program Files, if not found then use notepad.
348  char pf[MAX_PATH];
349  SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, 0, pf);
350  std::string fullPath = std::string(pf) + "\\Notepad++\\notepad++.exe";
351  std::string application = "notepad.exe";
352  if (vtksys::SystemTools::FileExists(fullPath.c_str()))
353  {
354  application = fullPath;
355  }
356  this->SetEditorApplicationExecutable(application.c_str());
357 #elif defined(unix) || defined(__unix__) || defined(__unix)
358  this->SetEditorApplicationExecutable("gedit");
359 #elif __APPLE__
360  this->SetEditorApplicationExecutable("TextEdit");
361 #endif
362  saveNeeded = true;
363  }
364 
365  // Read output directory
366  const char* outputDirectory = applicationConfigurationRoot->GetAttribute("OutputDirectory");
367  if ((outputDirectory != NULL) && (STRCASECMP(outputDirectory, "") != 0))
368  {
369  this->SetOutputDirectory(outputDirectory);
370  }
371  else
372  {
373  LOG_DEBUG("Output directory is not set - default './Output' will be used");
374  this->SetOutputDirectory("./Output");
375  saveNeeded = true;
376  }
377 
378  // Make device set configuration directory
379  if (! vtksys::SystemTools::MakeDirectory(GetOutputDirectory().c_str()))
380  {
381  LOG_ERROR("Unable to create device set configuration directory '" << GetOutputDirectory() << "'");
382  return PLUS_FAIL;
383  }
384 
385  // Read image directory
386  const char* imageDirectory = applicationConfigurationRoot->GetAttribute("ImageDirectory");
387  if ((imageDirectory != NULL) && (STRCASECMP(imageDirectory, "") != 0))
388  {
389  this->SetImageDirectory(imageDirectory);
390  }
391  else
392  {
393  LOG_INFO("Image directory is not set - default '../data' will be used");
394  this->SetImageDirectory("../data");
395  saveNeeded = true;
396  }
397 
398  // Read model directory
399  const char* modelDirectory = applicationConfigurationRoot->GetAttribute("ModelDirectory");
400  if ((modelDirectory != NULL) && (STRCASECMP(modelDirectory, "") != 0))
401  {
402  this->ModelDirectory = modelDirectory;
403  }
404  else
405  {
406  LOG_INFO("Model directory is not set - default '../config' will be used");
407  this->ModelDirectory = "../config";
408  saveNeeded = true;
409  }
410 
411  // Read scripts directory
412  const char* scriptsDirectory = applicationConfigurationRoot->GetAttribute("ScriptsDirectory");
413  if ((scriptsDirectory != NULL) && (STRCASECMP(scriptsDirectory, "") != 0))
414  {
415  this->ScriptsDirectory = scriptsDirectory;
416  }
417  else
418  {
419  LOG_INFO("Scripts directory is not set - default '../scripts' will be used");
420  this->ScriptsDirectory = "../scripts";
421  saveNeeded = true;
422  }
423 
424  if (saveNeeded)
425  {
427  }
428 
429  return PLUS_SUCCESS;
430 }
431 
432 //------------------------------------------------------------------------------
434 {
435  LOG_TRACE("vtkPlusConfig::WriteApplicationConfiguration");
436 
437  vtkXMLDataElement* applicationConfigurationRoot = this->ApplicationConfigurationData;
438  if (applicationConfigurationRoot == NULL)
439  {
440  // Configuration root does not exist yet, create it now
441  vtkSmartPointer<vtkXMLDataElement> newApplicationConfigurationRoot = vtkSmartPointer<vtkXMLDataElement>::New();
442  newApplicationConfigurationRoot->SetName("PlusConfig");
443  this->SetApplicationConfigurationData(newApplicationConfigurationRoot);
444  applicationConfigurationRoot = newApplicationConfigurationRoot;
445  }
446 
447  // Verify root element name
448  if (STRCASECMP(applicationConfigurationRoot->GetName(), "PlusConfig") != 0)
449  {
450  LOG_ERROR("Invalid application configuration file (root XML element should be 'PlusConfig' found '" << applicationConfigurationRoot->GetName() << "' instead)");
451  return PLUS_FAIL;
452  }
453 
454  // Save date
455  applicationConfigurationRoot->SetAttribute("Date", vtksys::SystemTools::GetCurrentDateTime("%Y.%m.%d %X").c_str());
456 
457  // Save log level
458  applicationConfigurationRoot->SetIntAttribute("LogLevel", vtkPlusLogger::Instance()->GetLogLevel());
459 
460  // Save device set directory
461  applicationConfigurationRoot->SetAttribute("DeviceSetConfigurationDirectory", this->DeviceSetConfigurationDirectory.c_str());
462 
463  // Save last device set config file
464  applicationConfigurationRoot->SetAttribute("LastDeviceSetConfigurationFileName", this->DeviceSetConfigurationFileName.c_str());
465 
466  // Save editor application
467  applicationConfigurationRoot->SetAttribute("EditorApplicationExecutable", this->EditorApplicationExecutable.c_str());
468 
469  // Save output path
470  applicationConfigurationRoot->SetAttribute("OutputDirectory", this->OutputDirectory.c_str());
471 
472  // Save image directory path
473  applicationConfigurationRoot->SetAttribute("ImageDirectory", this->ImageDirectory.c_str());
474 
475  // Save model directory path
476  applicationConfigurationRoot->SetAttribute("ModelDirectory", this->ModelDirectory.c_str());
477 
478  // Save scripts directory path
479  applicationConfigurationRoot->SetAttribute("ScriptsDirectory", this->ScriptsDirectory.c_str());
480 
481  return PLUS_SUCCESS;
482 }
483 
484 //-----------------------------------------------------------------------------
486 {
487  LOG_TRACE("vtkPlusConfig::GetNewDeviceSetConfigurationFileName");
488 
489  std::string resultFileName;
490  if (this->DeviceSetConfigurationFileName.empty())
491  {
492  LOG_WARNING("New configuration file name cannot be assembled due to absence of input configuration file name");
493  resultFileName = "PlusConfiguration";
494  }
495  else
496  {
497  resultFileName = this->DeviceSetConfigurationFileName;
498  resultFileName = resultFileName.substr(0, resultFileName.find(".xml"));
499  resultFileName = resultFileName.substr(resultFileName.find_last_of("/\\") + 1);
500  }
501 
502  // Detect if date is already in the filename and remove it if it is there
503  if (resultFileName.length() > 16)
504  {
505  std::string possibleDate = resultFileName.substr(resultFileName.length() - 15, 15);
506  std::string possibleDay = possibleDate.substr(0, 8);
507  std::string possibleTime = possibleDate.substr(9, 6);
508  if (atoi(possibleDay.c_str()) && atoi(possibleTime.c_str()))
509  {
510  resultFileName = resultFileName.substr(0, resultFileName.length() - 16);
511  }
512  }
513 
514  // Construct new file name with date and time
515  resultFileName.append("_");
516  resultFileName.append(vtksys::SystemTools::GetCurrentDateTime("%Y%m%d_%H%M%S"));
517  resultFileName.append(".xml");
518 
519  return resultFileName;
520 }
521 
522 //------------------------------------------------------------------------------
524 {
525  LOG_TRACE("vtkPlusConfig::SaveApplicationConfigurationToFile");
526 
528  {
529  LOG_ERROR("Failed to save application configuration to XML data!");
530  return PLUS_FAIL;
531  }
532 
533  std::string applicationConfigurationFilePath = vtksys::SystemTools::CollapseFullPath(APPLICATION_CONFIGURATION_FILE_NAME, this->ProgramDirectory.c_str());
534  igsioCommon::XML::PrintXML(applicationConfigurationFilePath.c_str(), this->ApplicationConfigurationData);
535 
536  LOG_DEBUG("Application configuration file '" << applicationConfigurationFilePath << "' saved");
537 
538  return PLUS_SUCCESS;
539 }
540 
541 //----------------------------------------------------------------------------
543 {
544  return vtksys::SystemTools::CollapseFullPath(APPLICATION_CONFIGURATION_FILE_NAME, this->ProgramDirectory.c_str());
545 }
546 
547 //-----------------------------------------------------------------------------
548 PlusStatus vtkPlusConfig::WriteTransformToCoordinateDefinition(const char* aFromCoordinateFrame, const char* aToCoordinateFrame, vtkMatrix4x4* aMatrix, double aError/*=-1*/, const char* aDate/*=NULL*/)
549 {
550  LOG_TRACE("vtkPlusConfig::WriteTransformToCoordinateDefinition(" << aFromCoordinateFrame << ", " << aToCoordinateFrame << ")");
551 
552  if (aFromCoordinateFrame == NULL)
553  {
554  LOG_ERROR("Failed to write transform to CoordinateDefinitions - 'From' coordinate frame name is NULL");
555  return PLUS_FAIL;
556  }
557 
558  if (aToCoordinateFrame == NULL)
559  {
560  LOG_ERROR("Failed to write transform to CoordinateDefinitions - 'To' coordinate frame name is NULL");
561  return PLUS_FAIL;
562  }
563 
564  if (aMatrix == NULL)
565  {
566  LOG_ERROR("Failed to write transform to CoordinateDefinitions - matrix is NULL");
567  return PLUS_FAIL;
568  }
569 
570 
571  vtkXMLDataElement* deviceSetConfigRootElement = GetDeviceSetConfigurationData();
572  if (deviceSetConfigRootElement == NULL)
573  {
574  LOG_ERROR("Failed to write transform to CoordinateDefinitions - config root element is NULL");
575  return PLUS_FAIL;
576  }
577 
578  vtkXMLDataElement* coordinateDefinitions = deviceSetConfigRootElement->FindNestedElementWithName("CoordinateDefinitions");
579  if (coordinateDefinitions == NULL)
580  {
581  vtkSmartPointer<vtkXMLDataElement> newCoordinateDefinitions = vtkSmartPointer<vtkXMLDataElement>::New();
582  newCoordinateDefinitions->SetName("CoordinateDefinitions");
583  deviceSetConfigRootElement->AddNestedElement(newCoordinateDefinitions);
584  coordinateDefinitions = newCoordinateDefinitions;
585  }
586 
587  // Check if we already have this entry in the config file
588  vtkXMLDataElement* transformElement = NULL;
589  int nestedElementIndex(0);
590  while (nestedElementIndex < coordinateDefinitions->GetNumberOfNestedElements() && transformElement == NULL)
591  {
592  vtkXMLDataElement* nestedElement = coordinateDefinitions->GetNestedElement(nestedElementIndex);
593  const char* fromAttribute = nestedElement->GetAttribute("From");
594  const char* toAttribute = nestedElement->GetAttribute("To");
595 
596  if (fromAttribute && toAttribute
597  && STRCASECMP(fromAttribute, aFromCoordinateFrame) == 0
598  && STRCASECMP(toAttribute, aToCoordinateFrame) == 0)
599  {
600  transformElement = nestedElement;
601  }
602  }
603 
604  if (transformElement == NULL)
605  {
606  vtkSmartPointer<vtkXMLDataElement> newElement = vtkSmartPointer<vtkXMLDataElement>::New();
607  newElement->SetName("Transform");
608  newElement->SetAttribute("From", aFromCoordinateFrame);
609  newElement->SetAttribute("To", aToCoordinateFrame);
610  coordinateDefinitions->AddNestedElement(newElement);
611  transformElement = newElement;
612  }
613 
614  double vectorMatrix[16] = {0};
615  vtkMatrix4x4::DeepCopy(vectorMatrix, aMatrix);
616  transformElement->SetVectorAttribute("Matrix", 16, vectorMatrix);
617 
618  if (aError > 0)
619  {
620  transformElement->SetDoubleAttribute("Error", aError);
621  }
622 
623  if (aDate != NULL)
624  {
625  transformElement->SetAttribute("Date", aDate);
626  }
627  else // Add current date if it was not explicitly specified
628  {
629  transformElement->SetAttribute("Date", vtksys::SystemTools::GetCurrentDateTime("%Y.%m.%d %X").c_str());
630  }
631 
632  return PLUS_SUCCESS;
633 }
634 
635 //-----------------------------------------------------------------------------
636 PlusStatus vtkPlusConfig::ReadTransformToCoordinateDefinition(const char* aFromCoordinateFrame, const char* aToCoordinateFrame, vtkMatrix4x4* aMatrix, double* aError/*=NULL*/, std::string* aDate/*=NULL*/)
637 {
638  LOG_TRACE("vtkPlusConfig::ReadTransformToCoordinateDefinition(" << aFromCoordinateFrame << ", " << aToCoordinateFrame << ")");
639 
640  vtkXMLDataElement* configRootElement = GetDeviceSetConfigurationData();
641  return ReadTransformToCoordinateDefinition(configRootElement, aFromCoordinateFrame, aToCoordinateFrame, aMatrix, aError, aDate);
642 }
643 
644 //-----------------------------------------------------------------------------
645 PlusStatus vtkPlusConfig::ReadTransformToCoordinateDefinition(vtkXMLDataElement* aDeviceSetConfigRootElement, const char* aFromCoordinateFrame, const char* aToCoordinateFrame, vtkMatrix4x4* aMatrix, double* aError/*=NULL*/, std::string* aDate/*=NULL*/)
646 {
647  LOG_TRACE("vtkPlusConfig::ReadTransformToCoordinateDefinition(" << aFromCoordinateFrame << ", " << aToCoordinateFrame << ")");
648 
649  if (aDeviceSetConfigRootElement == NULL)
650  {
651  LOG_ERROR("Failed read transform from CoordinateDefinitions - config root element is NULL");
652  return PLUS_FAIL;
653  }
654 
655  if (aFromCoordinateFrame == NULL)
656  {
657  LOG_ERROR("Failed to read transform from CoordinateDefinitions - 'From' coordinate frame name is NULL");
658  return PLUS_FAIL;
659  }
660 
661  if (aToCoordinateFrame == NULL)
662  {
663  LOG_ERROR("Failed to read transform from CoordinateDefinitions - 'To' coordinate frame name is NULL");
664  return PLUS_FAIL;
665  }
666 
667  if (aMatrix == NULL)
668  {
669  LOG_ERROR("Failed to read transform from CoordinateDefinitions - matrix is NULL");
670  return PLUS_FAIL;
671  }
672 
673  vtkXMLDataElement* coordinateDefinitions = aDeviceSetConfigRootElement->FindNestedElementWithName("CoordinateDefinitions");
674  if (coordinateDefinitions == NULL)
675  {
676  LOG_ERROR("Failed read transform from CoordinateDefinitions - CoordinateDefinitions element not found");
677  return PLUS_FAIL;
678  }
679 
680  for (int nestedElementIndex = 0; nestedElementIndex < coordinateDefinitions->GetNumberOfNestedElements(); ++nestedElementIndex)
681  {
682  vtkXMLDataElement* nestedElement = coordinateDefinitions->GetNestedElement(nestedElementIndex);
683  if (STRCASECMP(nestedElement->GetName(), "Transform") != 0)
684  {
685  // Not a transform element, skip it
686  continue;
687  }
688 
689  const char* fromAttribute = nestedElement->GetAttribute("From");
690  const char* toAttribute = nestedElement->GetAttribute("To");
691 
692  if (fromAttribute && toAttribute
693  && STRCASECMP(fromAttribute, aFromCoordinateFrame) == 0
694  && STRCASECMP(toAttribute, aToCoordinateFrame) == 0)
695  {
696  double vectorMatrix[16] = {0};
697  if (nestedElement->GetVectorAttribute("Matrix", 16, vectorMatrix))
698  {
699  aMatrix->DeepCopy(vectorMatrix);
700  }
701  else
702  {
703  LOG_ERROR("Unable to find 'Matrix' attribute of '" << aFromCoordinateFrame << "' to '" << aToCoordinateFrame << "' transform among the CoordinateDefinitions in the configuration file");
704  return PLUS_FAIL;
705  }
706 
707  if (aError != NULL)
708  {
709  double error(0);
710  if (nestedElement->GetScalarAttribute("Error", error))
711  {
712  *aError = error;
713  }
714  else
715  {
716  LOG_WARNING("Unable to find 'Error' attribute of '" << aFromCoordinateFrame << "' to '" << aToCoordinateFrame << "' transform among the CoordinateDefinitions in the configuration file");
717  }
718  }
719 
720  if (aDate != NULL)
721  {
722  const char* date = nestedElement->GetAttribute("Date");
723  if (date != NULL)
724  {
725  *aDate = date;
726  }
727  else
728  {
729  LOG_WARNING("Unable to find 'Date' attribute of '" << aFromCoordinateFrame << "' to '" << aToCoordinateFrame << "' transform among the CoordinateDefinitions in the configuration file");
730  }
731  }
732 
733  return PLUS_SUCCESS;
734  }
735  }
736 
737  LOG_DEBUG("Unable to find from '" << aFromCoordinateFrame << "' to '" << aToCoordinateFrame << "' transform among the CoordinateDefinitions in the configuration file");
738 
739  return PLUS_FAIL;
740 }
741 
742 //-----------------------------------------------------------------------------
743 PlusStatus vtkPlusConfig::ReplaceElementInDeviceSetConfiguration(const char* aElementName, vtkXMLDataElement* aNewRootElement)
744 {
745  LOG_TRACE("vtkPlusConfig::ReplaceElementInDeviceSetConfiguration(" << aElementName << ")");
746 
747  vtkXMLDataElement* deviceSetConfigRootElement = GetDeviceSetConfigurationData();
748  vtkXMLDataElement* orginalElement = deviceSetConfigRootElement->FindNestedElementWithName(aElementName);
749  if (orginalElement != NULL)
750  {
751  deviceSetConfigRootElement->RemoveNestedElement(orginalElement);
752  }
753 
754  vtkXMLDataElement* newElement = aNewRootElement->FindNestedElementWithName(aElementName);
755  if (newElement != NULL)
756  {
757  deviceSetConfigRootElement->AddNestedElement(newElement);
758  }
759  else
760  {
761  // Re-add deleted element if there was one
762  if (orginalElement != NULL)
763  {
764  deviceSetConfigRootElement->AddNestedElement(orginalElement);
765  }
766  LOG_ERROR("No element with the name '" << aElementName << "' can be found in the given XML data element!");
767  return PLUS_FAIL;
768  }
769 
770  return PLUS_SUCCESS;
771 }
772 
773 //-----------------------------------------------------------------------------
774 vtkXMLDataElement* vtkPlusConfig::LookupElementWithNameContainingChildWithNameAndAttribute(vtkXMLDataElement* aConfig, const char* aElementName, const char* aChildName, const char* aChildAttributeName, const char* aChildAttributeValue)
775 {
776  LOG_TRACE("vtkPlusConfig::LookupElementWithNameContainingChildWithNameAndAttribute(" << aElementName << ", " << aChildName << ", " << (aChildAttributeName == NULL ? "" : aChildAttributeName) << ", " << (aChildAttributeValue == NULL ? "" : aChildAttributeValue) << ")");
777 
778  if (aConfig == NULL)
779  {
780  LOG_ERROR("No input XML data element is specified!");
781  return NULL;
782  }
783 
784  vtkXMLDataElement* firstElement = aConfig->LookupElementWithName(aElementName);
785  if (firstElement == NULL)
786  {
787  return NULL;
788  }
789  else
790  {
791  if (aChildAttributeName && aChildAttributeValue)
792  {
793  return firstElement->FindNestedElementWithNameAndAttribute(aChildName, aChildAttributeName, aChildAttributeValue);
794  }
795  else
796  {
797  return firstElement->FindNestedElementWithName(aChildName);
798  }
799  }
800 }
801 
802 //-----------------------------------------------------------------------------
804 {
805  LOG_TRACE("vtkPlusConfig::GetFirstFileFoundInConfigurationDirectory(" << aFileName << ")");
806 
807  if (this->DeviceSetConfigurationDirectory.empty())
808  {
809  std::string configurationDirectory = vtksys::SystemTools::GetFilenamePath(GetDeviceSetConfigurationFileName());
810  return vtkPlusConfig::GetFirstFileFoundInDirectory(aFileName, configurationDirectory.c_str());
811  }
812  else
813  {
814  return GetFirstFileFoundInDirectory(aFileName, this->DeviceSetConfigurationDirectory.c_str());
815  }
816 };
817 
818 //-----------------------------------------------------------------------------
819 std::string vtkPlusConfig::GetFirstFileFoundInDirectory(const char* aFileName, const char* aDirectory)
820 {
821  LOG_TRACE("vtkPlusConfig::GetFirstFileFoundInDirectory(" << aFileName << ", " << aDirectory << ")");
822 
823  std::string result = FindFileRecursivelyInDirectory(aFileName, aDirectory);
824  if (STRCASECMP("", result.c_str()) == 0)
825  {
826  LOG_WARNING("File " << aFileName << " was not found in directory " << aDirectory);
827  }
828 
829  return result;
830 };
831 
832 //-----------------------------------------------------------------------------
833 std::string vtkPlusConfig::FindFileRecursivelyInDirectory(const char* aFileName, const char* aDirectory)
834 {
835  LOG_TRACE("vtkPlusConfig::FindFileRecursivelyInDirectory(" << aFileName << ", " << aDirectory << ")");
836 
837  std::vector<std::string> directoryList;
838  directoryList.push_back(aDirectory);
839 
840  // Search for the file in the input directory first (no system paths allowed)
841  std::string result = vtksys::SystemTools::FindFile(aFileName, directoryList, true);
842  if (STRCASECMP("", result.c_str()))
843  {
844  return result;
845  }
846  else // If not found then call this function recursively for the subdirectories of the input directory
847  {
848  vtkSmartPointer<vtkDirectory> dir = vtkSmartPointer<vtkDirectory>::New();
849  if (dir->Open(aDirectory))
850  {
851  for (int i = 0; i < dir->GetNumberOfFiles(); ++i)
852  {
853  const char* fileOrDirectory = dir->GetFile(i);
854  if ((! dir->FileIsDirectory(fileOrDirectory)) || (STRCASECMP(".", fileOrDirectory) == 0) || (STRCASECMP("..", fileOrDirectory) == 0))
855  {
856  continue;
857  }
858 
859  std::string fullPath(aDirectory);
860  fullPath.append("/");
861  fullPath.append(fileOrDirectory);
862 
863  result = FindFileRecursivelyInDirectory(aFileName, fullPath.c_str());
864  if (STRCASECMP("", result.c_str()))
865  {
866  return result;
867  }
868  }
869  }
870  else
871  {
872  LOG_DEBUG("Directory " << aDirectory << " cannot be opened");
873  return "";
874  }
875  }
876 
877  return "";
878 };
879 
880 //-----------------------------------------------------------------------------
881 PlusStatus vtkPlusConfig::FindImagePath(const std::string& aImagePath, std::string& aFoundAbsolutePath)
882 {
883  LOG_TRACE("vtkPlusConfig::FindImagePath(" << aImagePath << ")");
884 
885  // Check file relative to the image directory
886  aFoundAbsolutePath = GetImagePath(aImagePath);
887  if (vtksys::SystemTools::FileExists(aFoundAbsolutePath.c_str()))
888  {
889  return PLUS_SUCCESS;
890  }
891  LOG_DEBUG("Absolute path not found at: " << aFoundAbsolutePath);
892 
893  // Check file relative to the device set configuration file
894  std::string configurationFileDirectory = vtksys::SystemTools::GetFilenamePath(GetDeviceSetConfigurationFileName());
895  aFoundAbsolutePath = GetAbsolutePath(aImagePath, GetAbsolutePath(configurationFileDirectory, this->ProgramDirectory));
896  if (vtksys::SystemTools::FileExists(aFoundAbsolutePath.c_str()))
897  {
898  return PLUS_SUCCESS;
899  }
900  LOG_DEBUG("Absolute path not found at: " << aFoundAbsolutePath);
901 
902  // Check file relative to the device set configuration directory
903  aFoundAbsolutePath = GetDeviceSetConfigurationPath(aImagePath);
904  if (vtksys::SystemTools::FileExists(aFoundAbsolutePath.c_str()))
905  {
906  return PLUS_SUCCESS;
907  }
908  LOG_DEBUG("Absolute path not found at: " << aFoundAbsolutePath);
909 
910  // Check file relative to the current working directory
911  aFoundAbsolutePath = vtksys::SystemTools::CollapseFullPath(aImagePath.c_str(), vtksys::SystemTools::GetCurrentWorkingDirectory().c_str());
912  if (vtksys::SystemTools::FileExists(aFoundAbsolutePath.c_str()))
913  {
914  return PLUS_SUCCESS;
915  }
916 
917  aFoundAbsolutePath = "";
918  LOG_ERROR("Image with relative path '" << aImagePath << "' cannot be found neither relative to image directory (" << GetImageDirectory() << ")"
919  << " nor relative to device set configuration file directory (" << configurationFileDirectory << ")" << ")"
920  << " nor to device set configuration directory (" << GetDeviceSetConfigurationDirectory() << ")"
921  << " nor the current working directory directory (" << vtksys::SystemTools::GetCurrentWorkingDirectory() << ")");
922  return PLUS_FAIL;
923 }
924 
925 //-----------------------------------------------------------------------------
926 PlusStatus vtkPlusConfig::FindModelPath(const std::string& aModelPath, std::string& aFoundAbsolutePath)
927 {
928  LOG_TRACE("vtkPlusConfig::FindModelPath(" << aModelPath << ")");
929 
930  // Check if the file exists in the specified absolute path
931  if (vtksys::SystemTools::FileExists(aModelPath.c_str()))
932  {
933  // found
934  aFoundAbsolutePath = aModelPath;
935  return PLUS_SUCCESS;
936  }
937  LOG_DEBUG("Absolute path not found at: " << aModelPath);
938 
939  // Check file relative to the device set configuration file
940  std::string configurationFileDirectory = vtksys::SystemTools::GetFilenamePath(GetDeviceSetConfigurationFileName());
941  aFoundAbsolutePath = GetAbsolutePath(aModelPath, GetAbsolutePath(configurationFileDirectory, this->ProgramDirectory));
942  if (vtksys::SystemTools::FileExists(aFoundAbsolutePath.c_str()))
943  {
944  return PLUS_SUCCESS;
945  }
946  LOG_DEBUG("Absolute path not found at: " << aFoundAbsolutePath);
947 
948  // Check recursively in the model directory
949  std::string absoluteModelDirectoryPath = GetModelPath(".");
950  aFoundAbsolutePath = FindFileRecursivelyInDirectory(aModelPath.c_str(), absoluteModelDirectoryPath.c_str());
951  if (!aFoundAbsolutePath.empty())
952  {
953  // found
954  LOG_DEBUG("Absolute path found at: " << aFoundAbsolutePath);
955  return PLUS_SUCCESS;
956  }
957  LOG_DEBUG("Absolute path not found in subdirectories: " << absoluteModelDirectoryPath);
958 
959  // Check file relative to the device set configuration directory
960  aFoundAbsolutePath = GetDeviceSetConfigurationPath(aModelPath);
961  if (vtksys::SystemTools::FileExists(aFoundAbsolutePath.c_str()))
962  {
963  // found
964  LOG_DEBUG("Absolute path found at: " << aFoundAbsolutePath);
965  return PLUS_SUCCESS;
966  }
967  LOG_DEBUG("Absolute path not found at: " << aFoundAbsolutePath);
968 
969  // Check file relative to the current working directory
970  aFoundAbsolutePath = vtksys::SystemTools::CollapseFullPath(aModelPath.c_str(), vtksys::SystemTools::GetCurrentWorkingDirectory().c_str());
971  if (vtksys::SystemTools::FileExists(aFoundAbsolutePath.c_str()))
972  {
973  return PLUS_SUCCESS;
974  }
975 
976  aFoundAbsolutePath = "";
977  LOG_ERROR("Model with relative path '" << aModelPath << "' cannot be found neither within the model directory (" << absoluteModelDirectoryPath << ")"
978  << " nor relative to device set configuration file directory (" << configurationFileDirectory << ")" << ")"
979  << " nor to device set configuration directory (" << GetDeviceSetConfigurationDirectory() << ")"
980  << " nor the current working directory directory (" << vtksys::SystemTools::GetCurrentWorkingDirectory() << ")");
981  return PLUS_FAIL;
982 }
983 
984 //-----------------------------------------------------------------------------
985 std::string vtkPlusConfig::GetAbsolutePath(const std::string& aPath, const std::string& aBasePath)
986 {
987  if (aPath.empty())
988  {
989  // empty
990  return aBasePath;
991  }
992  if (vtksys::SystemTools::FileIsFullPath(aPath.c_str()))
993  {
994  // already absolute
995  return aPath;
996  }
997 
998  // relative to the ProgramDirectory
999  std::string absolutePath = vtksys::SystemTools::CollapseFullPath(aPath.c_str(), aBasePath.c_str());
1000  return absolutePath;
1001 }
1002 
1003 //-----------------------------------------------------------------------------
1004 std::string vtkPlusConfig::GetModelPath(const std::string& subPath)
1005 {
1006  return GetAbsolutePath(subPath, GetAbsolutePath(this->ModelDirectory, this->ProgramDirectory));
1007 }
1008 
1009 //-----------------------------------------------------------------------------
1010 std::string vtkPlusConfig::GetDeviceSetConfigurationPath(const std::string& subPath)
1011 {
1013 }
1014 
1015 //-----------------------------------------------------------------------------
1016 std::string vtkPlusConfig::GetOutputPath(const std::string& subPath)
1017 {
1018  return GetAbsolutePath(subPath, GetAbsolutePath(this->OutputDirectory, this->ProgramDirectory));
1019 }
1020 
1021 //-----------------------------------------------------------------------------
1023 {
1024  return GetOutputPath(".");
1025 }
1026 
1027 //-----------------------------------------------------------------------------
1029 {
1030  return GetDeviceSetConfigurationPath(".");
1031 }
1032 
1033 //-----------------------------------------------------------------------------
1035 {
1036  return GetImagePath(".");
1037 }
1038 
1039 //-----------------------------------------------------------------------------
1040 std::string vtkPlusConfig::GetImagePath(const std::string& subPath)
1041 {
1042  return GetAbsolutePath(subPath, GetAbsolutePath(this->ImageDirectory, this->ProgramDirectory));
1043 }
1044 
1045 //-----------------------------------------------------------------------------
1046 std::string vtkPlusConfig::GetScriptPath(const std::string& subPath)
1047 {
1048  return GetAbsolutePath(subPath, GetAbsolutePath(this->ScriptsDirectory, this->ProgramDirectory));
1049 }
1050 
1051 //-----------------------------------------------------------------------------
1053 {
1055 }
1056 
1057 //-----------------------------------------------------------------------------
1058 void vtkPlusConfig::SetDeviceSetConfigurationData(vtkXMLDataElement* deviceSetConfigurationData)
1059 {
1060  vtkSetObjectBodyMacro(DeviceSetConfigurationData, vtkXMLDataElement, deviceSetConfigurationData);
1061  if (this->DeviceSetConfigurationData != NULL)
1062  {
1063  std::string plusLibVersion = PlusCommon::GetPlusLibVersionString();
1064  this->DeviceSetConfigurationData->SetAttribute("PlusRevision", plusLibVersion.c_str());
1065  }
1066 }
1067 
1068 //-----------------------------------------------------------------------------
1069 std::string vtkPlusConfig::GetPlusExecutablePath(const std::string& executableName)
1070 {
1071  std::string processNameWithExtension = executableName;
1072 #ifdef _WIN32
1073  processNameWithExtension += ".exe";
1074 #endif
1075  return GetAbsolutePath(processNameWithExtension, this->ProgramDirectory);
1076 }
virtual void SetApplicationConfigurationData(vtkXMLDataElement *)
vtkXMLDataElement * CreateDeviceSetConfigurationFromFile(const std::string &aConfigFile)
std::string ApplicationStartTimestamp
std::string GetOutputPath(const std::string &subPath)
vtkXMLDataElement * DeviceSetConfigurationData
std::string GetApplicationConfigurationFilePath() const
std::string GetPlusExecutablePath(const std::string &executableName)
std::string GetDeviceSetConfigurationDirectory()
PlusStatus ReplaceElementInDeviceSetConfiguration(const char *aElementName, vtkXMLDataElement *aNewRootElement)
std::string GetAbsolutePath(const std::string &aPath, const std::string &aBasePath)
std::string GetFirstFileFoundInConfigurationDirectory(const char *aFileName)
std::string GetDeviceSetConfigurationFileName()
igsioStatus PlusStatus
Definition: PlusCommon.h:40
Singleton class providing tools needed for handling the configuration - finding files,...
Definition: vtkPlusConfig.h:24
vtkXMLDataElement * ApplicationConfigurationData
std::string EditorApplicationExecutable
for i
std::string GetImagePath(const std::string &subPath)
static void SetInstance(vtkPlusConfig *instance)
#define PLUS_FAIL
Definition: PlusCommon.h:43
std::string DeviceSetConfigurationFileName
static vtkPlusConfig * GetInstance()
static vtkPlusConfig * New()
void SetImageDirectory(const std::string &aDir)
PlusStatus LoadApplicationConfiguration()
std::string FindFileRecursivelyInDirectory(const char *aFileName, const char *aDirectory)
PlusStatus SaveApplicationConfigurationToFile()
std::string GetImageDirectory()
PlusStatus FindImagePath(const std::string &aImagePath, std::string &aFoundAbsolutePath)
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
void SetProgramDirectory()
void SetDeviceSetConfigurationDirectory(const std::string &aDir)
std::string GetOutputDirectory()
static const char APPLICATION_CONFIGURATION_FILE_NAME[]
PlusStatus ReadTransformToCoordinateDefinition(const char *aFromCoordinateFrame, const char *aToCoordinateFrame, vtkMatrix4x4 *aMatrix, double *aError=NULL, std::string *aDate=NULL)
std::string GetScriptPath(const std::string &subPath)
std::string ModelDirectory
PlusStatus FindModelPath(const std::string &aModelPath, std::string &aFoundAbsolutePath)
std::string GetFirstFileFoundInDirectory(const char *aFileName, const char *aDirectory)
virtual ~vtkPlusConfig()
static vtkIGSIOLogger * Instance()
std::string GetModelPath(const std::string &subPath)
PhidgetGPS_Date * date
Definition: phidget22.h:3617
vtkXMLDataElement * LookupElementWithNameContainingChildWithNameAndAttribute(vtkXMLDataElement *aConfig, const char *aElementName, const char *aChildName, const char *aChildAttributeName, const char *aChildAttributeValue)
virtual vtkXMLDataElement * GetDeviceSetConfigurationData()
std::string OutputDirectory
std::string GetDeviceSetConfigurationPath(const std::string &subPath)
PlusStatus WriteApplicationConfiguration()
PlusStatus WriteTransformToCoordinateDefinition(const char *aFromCoordinateFrame, const char *aToCoordinateFrame, vtkMatrix4x4 *aMatrix, double aError=-1, const char *aDate=NULL)
void SetOutputDirectory(const std::string &aDir)
void SetDeviceSetConfigurationFileName(const std::string &aFilePath)
std::string ProgramDirectory
std::string ScriptsDirectory
std::string DeviceSetConfigurationDirectory
void SetDeviceSetConfigurationData(vtkXMLDataElement *deviceSetConfigurationData)
vtkPlusCommonExport std::string GetPlusLibVersionString()
Definition: PlusCommon.cxx:30
std::string GetNewDeviceSetConfigurationFileName()
std::string ImageDirectory