1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkMINCImageAttributes.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /*=========================================================================
16 
17 Copyright (c) 2006 Atamai, Inc.
18 
19 Use, modification and redistribution of the software, in source or
20 binary forms, are permitted provided that the following terms and
21 conditions are met:
22 
23 1) Redistribution of the source code, in verbatim or modified
24    form, must retain the above copyright notice, this license,
25    the following disclaimer, and any notices that refer to this
26    license and/or the following disclaimer.
27 
28 2) Redistribution in binary form must include the above copyright
29    notice, a copy of this license and the following disclaimer
30    in the documentation or with other materials provided with the
31    distribution.
32 
33 3) Modified copies of the source code must be clearly marked as such,
34    and must not be misrepresented as verbatim copies of the source code.
35 
36 THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS"
37 WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO,
38 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 PURPOSE.  IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY
40 MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE
41 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES
42 (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE
43 OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF
44 THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE
45 POSSIBILITY OF SUCH DAMAGES.
46 
47 =========================================================================*/
48 
49 #include "vtkMINCImageAttributes.h"
50 
51 #include "vtkObjectFactory.h"
52 
53 #include "vtkStringArray.h"
54 #include "vtkCharArray.h"
55 #include "vtkSignedCharArray.h"
56 #include "vtkUnsignedCharArray.h"
57 #include "vtkShortArray.h"
58 #include "vtkIntArray.h"
59 #include "vtkFloatArray.h"
60 #include "vtkDoubleArray.h"
61 #include "vtkIdTypeArray.h"
62 #include "vtkSmartPointer.h"
63 
64 #include "vtkMINC.h"
65 #include "vtk_netcdf.h"
66 
67 #include <cstdlib>
68 #include <cctype>
69 #include <cfloat>
70 #include <string>
71 #include <map>
72 #include <sstream>
73 
74 //-------------------------------------------------------------------------
75 // A container for mapping attribute names to arrays
76 class vtkMINCImageAttributeMap
77 {
78 public:
79   typedef std::map<std::string, vtkSmartPointer<vtkObject> > MapType;
80 
New()81   static vtkMINCImageAttributeMap *New() {
82     return new vtkMINCImageAttributeMap; };
83 
Delete()84   void Delete() {
85     delete this; };
86 
Clear()87   void Clear() {
88     this->Map.clear(); };
89 
AddArray(vtkDataArray * array)90   void AddArray(vtkDataArray *array) {
91     this->AddObject(array->GetName(), array); };
92 
AddArray(vtkStringArray * array)93   void AddArray(vtkStringArray *array) {
94     this->AddObject(array->GetName(), array); };
95 
GetDataArray(const char * name) const96   vtkDataArray *GetDataArray(const char *name) const {
97     return vtkDataArray::SafeDownCast(this->GetObject(name)); };
98 
GetCharArray(const char * name) const99   vtkCharArray *GetCharArray(const char *name) const {
100     return vtkCharArray::SafeDownCast(this->GetObject(name)); };
101 
GetDoubleArray(const char * name) const102   vtkDoubleArray *GetDoubleArray(const char *name) const {
103     return vtkDoubleArray::SafeDownCast(this->GetObject(name)); };
104 
GetStringArray(const char * name) const105   vtkStringArray *GetStringArray(const char *name) const {
106     return vtkStringArray::SafeDownCast(this->GetObject(name)); };
107 
108 protected:
AddObject(const char * name,vtkObject * object)109   void AddObject(const char *name, vtkObject *object) {
110     this->Map[name] = object; };
111 
GetObject(const char * name) const112   vtkObject *GetObject(const char *name) const {
113     MapType::const_iterator iter = this->Map.find(name);
114     if (iter != this->Map.end()) { return iter->second; };
115     return nullptr; };
116 
117 private:
vtkMINCImageAttributeMap()118   vtkMINCImageAttributeMap() : Map() {};
119   ~vtkMINCImageAttributeMap() = default;
120 
121   MapType Map;
122 };
123 
124 //--------------------------------------------------------------------------
125 vtkStandardNewMacro(vtkMINCImageAttributes);
126 
127 vtkCxxSetObjectMacro(vtkMINCImageAttributes,ImageMin,vtkDoubleArray);
128 vtkCxxSetObjectMacro(vtkMINCImageAttributes,ImageMax,vtkDoubleArray);
129 
130 //-------------------------------------------------------------------------
vtkMINCImageAttributes()131 vtkMINCImageAttributes::vtkMINCImageAttributes()
132 {
133   this->DimensionNames = vtkStringArray::New();
134   this->DimensionLengths = vtkIdTypeArray::New();
135 
136   this->VariableNames = vtkStringArray::New();
137 
138   this->AttributeNames = vtkMINCImageAttributeMap::New();
139   // Add global attribute name array
140   vtkStringArray *tmparray = vtkStringArray::New();
141   tmparray->SetName("");
142   this->AttributeNames->AddArray(tmparray);
143   tmparray->Delete();
144 
145   this->AttributeValues = vtkMINCImageAttributeMap::New();
146   this->StringStore = nullptr;
147 
148   this->NumberOfImageMinMaxDimensions = 0;
149   this->ImageMin = nullptr;
150   this->ImageMax = nullptr;
151 
152   this->Name = nullptr;
153   this->DataType = VTK_VOID;
154 
155   this->ValidateAttributes = 1;
156 }
157 
158 //-------------------------------------------------------------------------
~vtkMINCImageAttributes()159 vtkMINCImageAttributes::~vtkMINCImageAttributes()
160 {
161   this->SetName(nullptr);
162 
163   if (this->DimensionNames)
164   {
165     this->DimensionNames->Delete();
166     this->DimensionNames = nullptr;
167   }
168   if (this->DimensionLengths)
169   {
170     this->DimensionLengths->Delete();
171     this->DimensionLengths = nullptr;
172   }
173   if (this->VariableNames)
174   {
175     this->VariableNames->Delete();
176     this->VariableNames = nullptr;
177   }
178   if (this->AttributeNames)
179   {
180     this->AttributeNames->Delete();
181     this->AttributeNames = nullptr;
182   }
183   if (this->AttributeValues)
184   {
185     this->AttributeValues->Delete();
186     this->AttributeValues = nullptr;
187   }
188   if (this->ImageMin)
189   {
190     this->ImageMin->Delete();
191     this->ImageMin = nullptr;
192   }
193   if (this->ImageMax)
194   {
195     this->ImageMax->Delete();
196     this->ImageMax = nullptr;
197   }
198   if (this->StringStore)
199   {
200     this->StringStore->Delete();
201     this->StringStore = nullptr;
202   }
203 }
204 
205 //-------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)206 void vtkMINCImageAttributes::PrintSelf(ostream& os, vtkIndent indent)
207 {
208   this->Superclass::PrintSelf(os,indent);
209 
210   os << indent << "Name: "
211      << (this->Name ? this->Name : "(none)") << "\n";
212   os << indent << "DataType: " << this->DataType << "\n";
213   os << indent << "DimensionNames: " << this->DimensionNames << "\n";
214   os << indent << "DimensionLengths: " << this->DimensionLengths << "\n";
215   os << indent << "VariableNames: " << this->VariableNames << "\n";
216   os << indent << "ImageMin: " << this->ImageMin << "\n";
217   os << indent << "ImageMax: " << this->ImageMax << "\n";
218   os << indent << "NumberOfImageMinMaxDimensions: "
219      << this->NumberOfImageMinMaxDimensions << "\n";
220   os << indent << "ValidateAttributes: "
221      << (this->ValidateAttributes ? "On\n" : "Off\n");
222 }
223 
224 //-------------------------------------------------------------------------
Reset()225 void vtkMINCImageAttributes::Reset()
226 {
227   this->SetName(nullptr);
228   this->SetDataType(VTK_VOID);
229   this->SetImageMin(nullptr);
230   this->SetImageMax(nullptr);
231   this->AttributeValues->Clear();
232   this->AttributeNames->Clear();
233   this->VariableNames->Reset();
234   this->DimensionNames->Reset();
235   this->DimensionLengths->Reset();
236   if (this->StringStore)
237   {
238     this->StringStore->Reset();
239   }
240   this->NumberOfImageMinMaxDimensions = 0;
241 
242   // Add global attribute name array
243   vtkStringArray *tmparray = vtkStringArray::New();
244   tmparray->SetName("");
245   this->AttributeNames->AddArray(tmparray);
246   tmparray->Delete();
247 }
248 
249 //-------------------------------------------------------------------------
250 // Allowed dimension variable names
251 static const char *vtkMINCDimVarNames[] = {
252   MIxspace, MIyspace, MIzspace, MItime,
253   MIxfrequency, MIyfrequency, MIzfrequency, MItfrequency,
254   nullptr
255 };
256 
257 //-------------------------------------------------------------------------
AddDimension(const char * dimension,vtkIdType length)258 void vtkMINCImageAttributes::AddDimension(const char *dimension,
259                                           vtkIdType length)
260 {
261   // Check for duplicates
262   vtkIdType n = this->DimensionNames->GetNumberOfValues();
263   for (vtkIdType i = 0; i < n; i++)
264   {
265     if (strcmp(dimension, this->DimensionNames->GetValue(i)) == 0)
266     {
267       vtkErrorMacro("The dimension " << dimension <<
268                     " has already been created.");
269       return;
270     }
271   }
272 
273   // Ensure the dimension name is valid
274   const char **tryname = nullptr;
275   for (tryname = vtkMINCDimVarNames; *tryname != nullptr; tryname++)
276   {
277     if (strcmp(dimension, *tryname) == 0)
278     {
279       break;
280     }
281   }
282   if (*tryname == nullptr && strcmp(dimension, MIvector_dimension) != 0)
283   {
284     vtkWarningMacro("The dimension name " << dimension <<
285                     " is not recognized.");
286   }
287 
288   this->DimensionNames->InsertNextValue(dimension);
289   this->DimensionLengths->InsertNextTuple1(length);
290 }
291 
292 //-------------------------------------------------------------------------
293 // This method also has to store the resulting string internally.
ConvertDataArrayToString(vtkDataArray * array)294 const char *vtkMINCImageAttributes::ConvertDataArrayToString(
295   vtkDataArray *array)
296 {
297   const char *result = "";
298   vtkIdType n = array->GetNumberOfTuples();
299   if (n == 0)
300   {
301     return result;
302   }
303 
304   int dataType = array->GetDataType();
305   if (dataType == VTK_CHAR)
306   {
307     vtkCharArray *charArray = vtkArrayDownCast<vtkCharArray>(array);
308     if (charArray)
309     {
310       result = charArray->GetPointer(0);
311       // Check to see if string has a terminal null (the null might be
312       // part of the attribute, or stored in the following byte)
313       if ((n > 0 && result[n-1] == '\0') ||
314           (charArray->GetSize() > n && result[n] == '\0'))
315       {
316         return result;
317       }
318     }
319   }
320 
321   std::ostringstream os;
322 
323   for (vtkIdType i = 0; i < n; i++)
324   {
325     double val = array->GetComponent(i, 0);
326     if (dataType == VTK_DOUBLE || dataType == VTK_FLOAT)
327     {
328       // Use NetCDF's usual precision for printing the values
329       char storage[128];
330       if (dataType == VTK_DOUBLE)
331       {
332         snprintf(storage, 128, "%0.15g", val);
333       }
334       else
335       {
336         snprintf(storage, 128, "%0.7g", val);
337       }
338       // Add a decimal if there isn't one, to distinguish from int
339       for (char *cp = storage; *cp != '.'; cp++)
340       {
341         if (*cp == '\0')
342         {
343           *cp++ = '.';
344           *cp = '\0';
345           break;
346         }
347       }
348       os << storage;
349     }
350     else if (dataType == VTK_CHAR)
351     {
352       os.put(static_cast<char>(val));
353     }
354     else
355     {
356       os << val;
357     }
358     if (i < n-1 && dataType != VTK_CHAR)
359     {
360       os << ", ";
361     }
362   }
363 
364   // Store the string
365   std::string str = os.str();
366 
367   if (this->StringStore == nullptr)
368   {
369     this->StringStore = vtkStringArray::New();
370   }
371 
372   // See if the string is already stored
373   vtkIdType m = this->StringStore->GetNumberOfValues();
374   vtkIdType j;
375   for (j = 0; j < m; j++)
376   {
377     result = this->StringStore->GetValue(j);
378     if (strcmp(str.c_str(), result) == 0)
379     {
380       break;
381     }
382   }
383   // If not, add it to the array.
384   if (j == m)
385   {
386     j = this->StringStore->InsertNextValue(str.c_str());
387     result = this->StringStore->GetValue(j);
388   }
389 
390   return result;
391 }
392 
393 //-------------------------------------------------------------------------
PrintFileHeader()394 void vtkMINCImageAttributes::PrintFileHeader()
395 {
396   this->PrintFileHeader(cout);
397 }
398 
399 //-------------------------------------------------------------------------
PrintFileHeader(ostream & os)400 void vtkMINCImageAttributes::PrintFileHeader(ostream &os)
401 {
402   const char *name = "unknown";
403   if (this->Name)
404   {
405     name = this->Name;
406   }
407 
408   // Get the data type
409   const char *imageDataType;
410   switch (this->DataType)
411   {
412     case VTK_CHAR:
413     case VTK_SIGNED_CHAR:
414     case VTK_UNSIGNED_CHAR:
415       imageDataType = "byte";
416       break;
417     case VTK_SHORT:
418     case VTK_UNSIGNED_SHORT:
419       imageDataType = "short";
420       break;
421     case VTK_INT:
422     case VTK_UNSIGNED_INT:
423       imageDataType = "int";
424       break;
425     case VTK_FLOAT:
426       imageDataType = "float";
427       break;
428     case VTK_DOUBLE:
429       imageDataType = "double";
430       break;
431     default:
432       imageDataType = "void";
433   }
434 
435   os << "netcdf " << name << " {\n";
436   os << "dimensions:\n";
437 
438   vtkIdType ndim = 0;
439   if (this->DimensionNames)
440   {
441     ndim = this->DimensionNames->GetNumberOfValues();
442   }
443   for (vtkIdType idim = 0; idim < ndim; idim++)
444   {
445     os << "\t" << this->DimensionNames->GetValue(idim) << " = "
446        << this->DimensionLengths->GetValue(idim) << " ;\n";
447   }
448 
449   os << "variables:\n";
450 
451   vtkIdType nvar = 0;
452   vtkIdType ivar = 0;
453   if (this->VariableNames)
454   {
455     nvar = this->VariableNames->GetNumberOfValues();
456   }
457   for (ivar = 0; ivar < nvar+1; ivar++)
458   {
459     const char *varname = MI_EMPTY_STRING;
460     if (ivar == nvar)
461     {
462       os << "\n// global attributes:\n";
463     }
464     else
465     {
466       varname = this->VariableNames->GetValue(ivar);
467       if (strcmp(varname, MIimage) == 0 ||
468           strcmp(varname, MIimagemax) == 0 ||
469           strcmp(varname, MIimagemin) == 0)
470       {
471         vtkIdType nvardim = this->DimensionNames->GetNumberOfValues();
472         // If this is image-min or image-max, only print the
473         // dimensions for these variables
474         if (varname[5] == '-')
475         {
476           if (this->NumberOfImageMinMaxDimensions < nvardim)
477           {
478             nvardim = this->NumberOfImageMinMaxDimensions;
479           }
480           os << "\tdouble " << varname;
481         }
482         else
483         {
484           os << "\t" << imageDataType << " " << varname;
485         }
486 
487         if (nvardim > 0)
488         {
489           os << "(";
490           for (int ivardim = 0; ivardim < nvardim; ivardim++)
491           {
492             os << this->DimensionNames->GetValue(ivardim);
493             if (ivardim < nvardim - 1)
494             {
495               os << ", ";
496             }
497           }
498           os << ")";
499         }
500         os << " ;\n";
501       }
502       else
503       {
504         os << "\t" << "int " << varname << " ;\n";
505       }
506     }
507     vtkStringArray *attArray =
508       this->AttributeNames->GetStringArray(varname);
509     if (attArray)
510     {
511       vtkIdType natt = attArray->GetNumberOfValues();
512       for (vtkIdType iatt = 0; iatt < natt; iatt++)
513       {
514         const char *attname = attArray->GetValue(iatt);
515         vtkDataArray *array =
516           this->GetAttributeValueAsArray(varname, attname);
517         os << "\t\t" << varname << ":" << attname << " = ";
518         if (array->GetDataType() == VTK_CHAR)
519         {
520           os << "\"";
521           const char *cp = this->ConvertDataArrayToString(array);
522           const char *endcp = cp + strlen(cp);
523           char text[512];
524           text[0] = '\0';
525           while (cp < endcp)
526           {
527             int c = 0;
528             int j;
529             for (j = 0; j < 508 && cp < endcp; j++, cp++)
530             {
531               c = *cp;
532               if (c == '\0' && (cp + 1) == endcp)
533               {
534                 // break if at terminal null
535                 cp++;
536                 break;
537               }
538               if (isprint(c) && c != '\\')
539               {
540                 text[j] = c;
541               }
542               else
543               {
544                 // quote the non-printing characters
545                 switch (c)
546                 {
547                   case '\\':
548                     text[j++] = '\\';
549                     text[j] = '\\';
550                     break;
551                   case '\b':
552                     text[j++] = '\\';
553                     text[j] = '\b';
554                     break;
555                   case '\n':
556                     text[j++] = '\\';
557                     text[j] = 'n';
558                     break;
559                   case '\r':
560                     text[j++] = '\\';
561                     text[j] = 'r';
562                     break;
563                   case '\f':
564                     text[j++] = '\\';
565                     text[j] = 'f';
566                     break;
567                   case '\v':
568                     text[j++] = '\\';
569                     text[j] = 'v';
570                     break;
571                   case '\'':
572                     text[j++] = '\\';
573                     text[j] = '\'';
574                     break;
575                   case '\"':
576                     text[j++] = '\\';
577                     text[j] = '\"';
578                     break;
579                   default:
580                     text[j++] = '\\';
581                     text[j++] = '0' + ((c & 0xc0) >> 6);
582                     text[j++] = '0' + ((c & 0x38) >> 3);
583                     text[j] = '0' + (c & 0x7);
584                     break;
585                 }
586               }
587               if (c == '\n')
588               {
589                 j++;
590                 cp++;
591                 break;
592               }
593             }
594 
595             text[j] = '\0';
596             os << text;
597             text[0] = '\0';
598 
599             // Start a new string after each newline, unless this
600             // newline is the final character.
601             if (c == '\n' && cp < endcp)
602             {
603               os << "\",\n\t\t\t\"";
604             }
605           }
606           os << "\" ;\n";
607         }
608         else
609         {
610           // Use handy conversion method
611           os << this->ConvertDataArrayToString(array) << " ;\n";
612         }
613       }
614     }
615   }
616 
617   os << "data:\n";
618 
619   if (this->VariableNames)
620   {
621     nvar = this->VariableNames->GetNumberOfValues();
622   }
623   for (ivar = 0; ivar < nvar; ivar++)
624   {
625     const char *varname = this->VariableNames->GetValue(ivar);
626 
627     if (strcmp(varname, MIimage) == 0)
628     {
629       continue;
630     }
631 
632     os << "\n " << varname << " = ";
633 
634     if (strcmp(varname, MIimagemin) == 0)
635     {
636       if (this->ImageMin)
637       {
638         os << this->ConvertDataArrayToString(this->ImageMin) << " ;\n";
639       }
640       else
641       {
642         os << "0. ;\n";
643       }
644     }
645     else if (strcmp(varname, MIimagemax) == 0)
646     {
647       if (this->ImageMax)
648       {
649         os << this->ConvertDataArrayToString(this->ImageMax) << " ;\n";
650       }
651       else
652       {
653         os << "1. ;\n";
654       }
655     }
656     else
657     {
658       os << "_ ;\n";
659     }
660   }
661 
662   os << "}\n";
663 }
664 
665 //-------------------------------------------------------------------------
GetAttributeNames(const char * variable)666 vtkStringArray *vtkMINCImageAttributes::GetAttributeNames(
667   const char *variable)
668 {
669   // If variable is null, use empty string to get global attributes
670   if (variable == nullptr)
671   {
672     variable = MI_EMPTY_STRING;
673   }
674 
675   return this->AttributeNames->GetStringArray(variable);
676 }
677 
678 //-------------------------------------------------------------------------
HasAttribute(const char * variable,const char * attribute)679 int vtkMINCImageAttributes::HasAttribute(
680   const char *variable,
681   const char *attribute)
682 {
683   return (this->GetAttributeValueAsArray(variable, attribute) != nullptr);
684 }
685 
686 //-------------------------------------------------------------------------
GetAttributeValueAsArray(const char * variable,const char * attribute)687 vtkDataArray *vtkMINCImageAttributes::GetAttributeValueAsArray(
688   const char *variable,
689   const char *attribute)
690 {
691   std::string path = MI_GRPNAME;
692   if (variable && variable[0] != '\0')
693   {
694     path += MI_GRP_SEP;
695     path += variable;
696   }
697   path += MI_ATT_SEP;
698   path += attribute;
699 
700   return this->AttributeValues->GetDataArray(path.c_str());
701 }
702 
703 //-------------------------------------------------------------------------
GetAttributeValueAsString(const char * variable,const char * attribute)704 const char *vtkMINCImageAttributes::GetAttributeValueAsString(
705   const char *variable,
706   const char *attribute)
707 {
708   vtkDataArray *array =
709     this->GetAttributeValueAsArray(variable, attribute);
710 
711   // Return nullptr if not found
712   if (array == nullptr)
713   {
714     return nullptr;
715   }
716 
717   // Convert any other array to a string.
718   return this->ConvertDataArrayToString(array);
719 }
720 
721 //-------------------------------------------------------------------------
GetAttributeValueAsInt(const char * variable,const char * attribute)722 int vtkMINCImageAttributes::GetAttributeValueAsInt(
723   const char *variable,
724   const char *attribute)
725 {
726   vtkDataArray *array = this->GetAttributeValueAsArray(variable, attribute);
727 
728   if (array == nullptr)
729   {
730     vtkErrorMacro("The attribute " << variable << ":"
731                   << attribute << " was not found.");
732     return 0;
733   }
734 
735   if (array->GetDataType() == VTK_CHAR)
736   {
737     const char *text = this->ConvertDataArrayToString(array);
738     char *endp = const_cast<char *>(text);
739     long result = strtol(text, &endp, 10);
740     // Check for complete conversion
741     if (*endp == '\0' && *text != '\0')
742     {
743       return static_cast<int>(result);
744     }
745   }
746   else if (array->GetNumberOfTuples() == 1)
747   {
748     switch(array->GetDataType())
749     {
750       case VTK_SIGNED_CHAR:
751       case VTK_UNSIGNED_CHAR:
752       case VTK_SHORT:
753       case VTK_INT:
754         return static_cast<int>(array->GetComponent(0,0));
755       default:
756         break;
757     }
758   }
759 
760   vtkErrorMacro("GetAttributeValueAsInt() used on non-integer attribute "
761                 << variable << ":" << attribute <<".");
762   return static_cast<int>(array->GetComponent(0,0));
763 }
764 
765 //-------------------------------------------------------------------------
GetAttributeValueAsDouble(const char * variable,const char * attribute)766 double vtkMINCImageAttributes::GetAttributeValueAsDouble(
767   const char *variable,
768   const char *attribute)
769 {
770   if (variable == nullptr)
771   {
772     variable = MI_EMPTY_STRING;
773   }
774 
775   vtkDataArray *array = this->GetAttributeValueAsArray(variable, attribute);
776 
777   if (array == nullptr)
778   {
779     vtkErrorMacro("The attribute " << variable << ":"
780                   << attribute << " was not found.");
781     return 0;
782   }
783 
784   if (array->GetDataType() == VTK_CHAR)
785   {
786     const char *text = this->ConvertDataArrayToString(array);
787     char *endp = const_cast<char *>(text);
788     double result = strtod(text, &endp);
789     // Check for complete conversion
790     if (*endp == '\0' && *text != '\0')
791     {
792       return result;
793     }
794   }
795   else if (array->GetNumberOfTuples() == 1)
796   {
797     switch(array->GetDataType())
798     {
799       case VTK_SIGNED_CHAR:
800       case VTK_UNSIGNED_CHAR:
801       case VTK_SHORT:
802       case VTK_INT:
803       case VTK_FLOAT:
804       case VTK_DOUBLE:
805         return array->GetComponent(0,0);
806       default:
807         break;
808     }
809   }
810 
811   vtkErrorMacro("GetAttributeValueAsDouble() used on non-real attribute "
812                 << variable << ":" << attribute <<".");
813   return array->GetComponent(0,0);
814 }
815 
816 //-------------------------------------------------------------------------
SetAttributeValueAsArray(const char * variable,const char * attribute,vtkDataArray * array)817 void vtkMINCImageAttributes::SetAttributeValueAsArray(
818   const char *variable,
819   const char *attribute,
820   vtkDataArray *array)
821 {
822   std::string path = MI_GRPNAME;
823   if (variable && variable[0] != '\0')
824   {
825     path += MI_GRP_SEP;
826     path += variable;
827   }
828   path += MI_ATT_SEP;
829   path += attribute;
830 
831   array->SetName(path.c_str());
832   this->AttributeValues->AddArray(array);
833 
834   // Add to variable to VariableNames
835   vtkIdType n = this->VariableNames->GetNumberOfValues();
836   vtkIdType i = 0;
837   for (i = 0; i < n; i++)
838   {
839     if (strcmp(this->VariableNames->GetValue(i), variable) == 0)
840     {
841       break;
842     }
843   }
844   if (i == n && variable[0] != '\0')
845   {
846     this->VariableNames->InsertNextValue(variable);
847   }
848 
849   // Add to attribute to AttributeNames
850   vtkStringArray *attribs = this->AttributeNames->GetStringArray(variable);
851   // Create a new array if necessary
852   if (attribs == nullptr)
853   {
854     attribs = vtkStringArray::New();
855     attribs->SetName(variable);
856     this->AttributeNames->AddArray(attribs);
857     attribs->Delete();
858   }
859 
860   n = attribs->GetNumberOfValues();
861   for (i = 0; i < n; i++)
862   {
863     if (strcmp(attribs->GetValue(i), attribute) == 0)
864     {
865       break;
866     }
867   }
868   if (i == n)
869   {
870     attribs->InsertNextValue(attribute);
871   }
872 
873   if (this->ValidateAttributes)
874   {
875     // Print warning if there is something wrong with the attribute
876     int result = this->ValidateAttribute(variable, attribute, array);
877 
878     if (result > 1)
879     {
880       vtkWarningMacro("Attribute " << variable << ":" << attribute
881                       << " is not a valid attribute.");
882     }
883   }
884 }
885 
886 //-------------------------------------------------------------------------
SetAttributeValueAsString(const char * variable,const char * attribute,const char * value)887 void vtkMINCImageAttributes::SetAttributeValueAsString(
888   const char *variable,
889   const char *attribute,
890   const char *value)
891 {
892   size_t length = strlen(value);
893 
894   vtkCharArray *array = vtkCharArray::New();
895   // Allocate an extra byte to store a null terminator.
896   array->Resize(static_cast<vtkIdType>(length + 1));
897   char *dest = array->WritePointer(0, static_cast<vtkIdType>(length));
898   strcpy(dest, value);
899   this->SetAttributeValueAsArray(variable, attribute, array);
900 
901   array->Delete();
902 }
903 
904 //-------------------------------------------------------------------------
SetAttributeValueAsInt(const char * variable,const char * attribute,int value)905 void vtkMINCImageAttributes::SetAttributeValueAsInt(
906   const char *variable,
907   const char *attribute,
908   int value)
909 {
910   vtkIntArray *array = vtkIntArray::New();
911   array->SetNumberOfValues(1);
912   array->SetValue(0, value);
913 
914   this->SetAttributeValueAsArray(variable, attribute, array);
915 
916   array->Delete();
917 }
918 
919 //-------------------------------------------------------------------------
SetAttributeValueAsDouble(const char * variable,const char * attribute,double value)920 void vtkMINCImageAttributes::SetAttributeValueAsDouble(
921   const char *variable,
922   const char *attribute,
923   double value)
924 {
925   vtkDoubleArray *array = vtkDoubleArray::New();
926   array->SetNumberOfValues(1);
927   array->SetValue(0, value);
928 
929   this->SetAttributeValueAsArray(variable, attribute, array);
930 
931   array->Delete();
932 }
933 
934 //-------------------------------------------------------------------------
935 // These validation methods have three return values:
936 // 0 means that the attribute should be skipped
937 // 1 means that the attribute should be set
938 // 2 means that the attribute wasn't recognized
939 
940 //-------------------------------------------------------------------------
ValidateGlobalAttribute(const char * attname,vtkDataArray * vtkNotUsed (array))941 int vtkMINCImageAttributes::ValidateGlobalAttribute(
942   const char *attname, vtkDataArray *vtkNotUsed(array))
943 {
944   // Global attributes
945   static const char *globalAttributes[] = {
946     MIident,
947     MIhistory,
948     MItitle,
949     nullptr
950   };
951   const int autoGlobalAttributes = 2;
952 
953   int itry = 0;
954   for (itry = 0; globalAttributes[itry] != nullptr; itry++)
955   {
956     if (strcmp(attname, globalAttributes[itry]) == 0)
957     {
958       break;
959     }
960   }
961   if (itry < autoGlobalAttributes)
962   {
963     // Skip to the next attribute
964     return 0;
965   }
966   else if (globalAttributes[itry] == nullptr)
967   {
968     return 2;
969   }
970 
971   return 1;
972 }
973 
974 //-------------------------------------------------------------------------
ValidateGeneralAttribute(const char * varname,const char * attname,vtkDataArray * array)975 int vtkMINCImageAttributes::ValidateGeneralAttribute(
976   const char *varname, const char *attname, vtkDataArray *array)
977 {
978   // Attributes that all MINC variables have
979   static const char *generalAttributes[] = {
980     MIvartype,      // MI_GROUP, MI_DIMENSION, MI_VARATT
981     MIvarid,        // MI_STDVAR
982     MIversion,      // MI_VERSION_1_0
983     MIparent,       // parent variable for this variable
984     MIchildren,     // newline-separated list of child variables
985     MIcomments,     // each variable has specific comments to go with it
986     nullptr
987   };
988   const int autoGeneralAttributes = 5;
989 
990   int dataType = array->GetDataType();
991 
992   // Check to see if the attribute is one that we automatically generate.
993   int itry = 0;
994   for (itry = 0; generalAttributes[itry] != nullptr; itry++)
995   {
996     if (strcmp(attname, generalAttributes[itry]) == 0)
997     {
998       break;
999     }
1000   }
1001   if (itry < autoGeneralAttributes)
1002   {
1003     // Skip to the next attribute
1004     return 0;
1005   }
1006   else if (generalAttributes[itry] != nullptr)
1007   {
1008     if (dataType != VTK_CHAR)
1009     {
1010       vtkWarningMacro("The attribute " << varname << ":"
1011                       << attname << " has the wrong type ("
1012                       << dataType << ").");
1013       return 0;
1014     }
1015   }
1016   else
1017   {
1018     return 2;
1019   }
1020 
1021   return 1;
1022 }
1023 
1024 //-------------------------------------------------------------------------
ValidateDimensionAttribute(const char * varname,const char * attname,vtkDataArray * array)1025 int vtkMINCImageAttributes::ValidateDimensionAttribute(
1026   const char *varname, const char *attname, vtkDataArray *array)
1027 {
1028   // Attributes for dimension variables (vartype = MI_DIMENSION)
1029   static const char *dimensionAttributes[] = {
1030     MIstep,
1031     MIstart,
1032     MIspacing,      // MI_REGULAR ("irregular" not supported)
1033     MIspacetype,    // "native____", "talairach_", "calossal__"
1034     MIalignment,    // MI_CENTRE ("start_", "end___" not supported)
1035     MIunits,        // "mm"
1036     MIdirection_cosines,  // three doubles
1037     nullptr
1038   };
1039   const int autoDimensionAttributes = 3;
1040 
1041   vtkIdType size = (array->GetNumberOfTuples()*
1042                     array->GetNumberOfComponents());
1043   int dataType = array->GetDataType();
1044 
1045   int itry = 0;
1046   for (itry = 0; dimensionAttributes[itry] != nullptr; itry++)
1047   {
1048     if (strcmp(attname, dimensionAttributes[itry]) == 0)
1049     {
1050       break;
1051     }
1052   }
1053   if (itry < autoDimensionAttributes)
1054   {
1055     // Skip to the next attribute
1056     return 0;
1057   }
1058   else if (strcmp(attname, MIdirection_cosines) == 0)
1059   {
1060     if (varname[0] == 'x' || varname[0] == 'y' || varname[0] == 'z')
1061     {
1062       if (dataType != VTK_DOUBLE || size != 3)
1063       {
1064         vtkWarningMacro("The attribute " << varname << ":"
1065                         << attname << " has the wrong type ("
1066                         << dataType << ") or size ("
1067                         << size << ").");
1068         return 0;
1069       }
1070     }
1071     else
1072     {
1073       vtkWarningMacro("Dimension " << varname << " cannot have"
1074                       " a direction_cosines attribute");
1075       return 0;
1076     }
1077   }
1078   else if (dimensionAttributes[itry] != nullptr)
1079   {
1080     if (dataType != VTK_CHAR)
1081     {
1082       vtkWarningMacro("The attribute " << varname << ":"
1083                       << attname << " has the wrong type ("
1084                       << dataType << ").");
1085       return 0;
1086     }
1087   }
1088   else
1089   {
1090     return 2;
1091   }
1092 
1093   return 1;
1094 }
1095 
1096 //-------------------------------------------------------------------------
ValidateImageAttribute(const char * vtkNotUsed (varname),const char * attname,vtkDataArray * vtkNotUsed (array))1097 int vtkMINCImageAttributes::ValidateImageAttribute(
1098   const char *vtkNotUsed(varname), const char *attname,
1099   vtkDataArray *vtkNotUsed(array))
1100 {
1101   // Attributes for the MIimage variable (vartype = MI_GROUP)
1102   static const char *imageAttributes[] = {
1103     MIcomplete,    // MI_TRUE (MI_FALSE means not yet all written)
1104     MIimagemin     // "--->image-min" variable attribute pointer
1105     MIimagemax     // "--->image-max" variable attribute pointer
1106     MIsigntype,     // MI_SIGNED or MI_UNSIGNED
1107     MIvalid_range,  // min and max scalar values as doubles
1108     nullptr
1109   };
1110   const int autoImageAttributes = 5;
1111 
1112   int itry = 0;
1113   for (itry = 0; imageAttributes[itry] != nullptr; itry++)
1114   {
1115     if (strcmp(attname, imageAttributes[itry]) == 0)
1116     {
1117       break;
1118     }
1119   }
1120   if (itry < autoImageAttributes)
1121   {
1122     // Skip to the next attribute
1123     return 0;
1124   }
1125   else if (imageAttributes[itry] == nullptr)
1126   {
1127     return 2;
1128   }
1129 
1130   return 1;
1131 }
1132 
1133 //-------------------------------------------------------------------------
ValidateImageMinMaxAttribute(const char * varname,const char * attname,vtkDataArray * array)1134 int vtkMINCImageAttributes::ValidateImageMinMaxAttribute(
1135   const char *varname, const char *attname, vtkDataArray *array)
1136 {
1137   // Attributes for MIimagemin, MIimagemax (vartype = MI_VARATT)
1138   static const char *imageMinMaxAttributes[] = {
1139      MI_FillValue,  // 0.0 for image-min, 1.0 for image-max
1140      MIunits,       // "normalized", "Hounsfields", etc.
1141      nullptr
1142   };
1143   const int autoImageMinMaxAttributes = 1;
1144 
1145   int itry = 0;
1146   for (itry = 0; imageMinMaxAttributes[itry] != nullptr; itry++)
1147   {
1148     if (strcmp(attname, imageMinMaxAttributes[itry]) == 0)
1149     {
1150       break;
1151     }
1152   }
1153   if (itry < autoImageMinMaxAttributes)
1154   {
1155     // Skip to the next attribute
1156     return 0;
1157   }
1158   else if (imageMinMaxAttributes[itry] != nullptr)
1159   {
1160     int dataType = array->GetDataType();
1161     if (dataType != VTK_CHAR)
1162     {
1163       vtkWarningMacro("The attribute " << varname << ":"
1164                       << attname << " has the wrong type ("
1165                       << dataType << ").");
1166       return 0;
1167     }
1168   }
1169   else
1170   {
1171     return 2;
1172   }
1173 
1174   return 1;
1175 }
1176 
1177 //-------------------------------------------------------------------------
ValidatePatientAttribute(const char * vtkNotUsed (varname),const char * attname,vtkDataArray * vtkNotUsed (array))1178 int vtkMINCImageAttributes::ValidatePatientAttribute(
1179   const char *vtkNotUsed(varname), const char *attname,
1180   vtkDataArray *vtkNotUsed(array))
1181 {
1182   // Attributes for MIpatient variable (vartype = MI_GROUP)
1183   static const char *patientAttributes[] = {
1184     MIfull_name,     // "LASTNAME^FIRSTNAME SECONDNAME"
1185     MIother_names,   // newline-separated string
1186     MIidentification,
1187     MIother_ids,
1188     MIbirthdate,     // "YYYYMMDD"
1189     MIsex,           // "male__", "female", "other_"
1190     MIage,           // "XXXD", "XXXM", or "XXXY" (days, months, years)
1191     MIweight,        // "XXkg", "X.Xkg" (assume kg if no units given)
1192     MIsize,          // "XXXcm" (assume meters if no units given)
1193     MIaddress,       // newline-separated string
1194     MIinsurance_id,
1195     nullptr
1196   };
1197 
1198   int itry = 0;
1199   for (itry = 0; patientAttributes[itry] != nullptr; itry++)
1200   {
1201     if (strcmp(attname, patientAttributes[itry]) == 0)
1202     {
1203       break;
1204     }
1205   }
1206   if (patientAttributes[itry] != nullptr)
1207   {
1208     // Add checks for correct data type?
1209   }
1210   else
1211   {
1212     return 2;
1213   }
1214 
1215   return 1;
1216 }
1217 
1218 //-------------------------------------------------------------------------
ValidateStudyAttribute(const char * vtkNotUsed (varname),const char * attname,vtkDataArray * vtkNotUsed (array))1219 int vtkMINCImageAttributes::ValidateStudyAttribute(
1220   const char *vtkNotUsed(varname), const char *attname,
1221   vtkDataArray *vtkNotUsed(array))
1222 {
1223   // Attributes for MIstudy variable (vartype = MI_GROUP)
1224   static const char *studyAttributes[] = {
1225     MIstudy_id,
1226     MIstart_time,    // "YYYYMMDDHHMMSS.SS"
1227     MIstart_year,    // as int (use start_time instead)
1228     MIstart_month,   // as int (use start_time instead)
1229     MIstart_day,     // as int (use start_time instead)
1230     MIstart_hour,    // as int (use start_time instead)
1231     MIstart_minute,  // as int (use start_time instead)
1232     MIstart_seconds, // as double or int (use start_time instead)
1233     MImodality,      // "PET__", "SPECT", "GAMMA", "MRI__", "MRS__",
1234                      // "MRA__", "CT___", "DSA__", "DR___", "label"
1235     MImanufacturer,
1236     MIdevice_model,
1237     MIinstitution,
1238     MIdepartment,
1239     MIstation_id,
1240     MIreferring_physician,
1241     MIattending_physician,
1242     MIradiologist,
1243     MIoperator,
1244     MIadmitting_diagnosis,
1245     MIprocedure,
1246     nullptr
1247   };
1248 
1249   int itry = 0;
1250   for (itry = 0; studyAttributes[itry] != nullptr; itry++)
1251   {
1252     if (strcmp(attname, studyAttributes[itry]) == 0)
1253     {
1254       break;
1255     }
1256   }
1257   if (studyAttributes[itry] != nullptr)
1258   {
1259     // Add checks for correct data type?
1260   }
1261   else
1262   {
1263     return 2;
1264   }
1265 
1266   return 1;
1267 }
1268 
1269 //-------------------------------------------------------------------------
ValidateAcquisitionAttribute(const char * vtkNotUsed (varname),const char * attname,vtkDataArray * vtkNotUsed (array))1270 int vtkMINCImageAttributes::ValidateAcquisitionAttribute(
1271   const char *vtkNotUsed(varname), const char *attname,
1272   vtkDataArray *vtkNotUsed(array))
1273 {
1274   // Attributes for MIacquisition variable (vartype = MI_GROUP)
1275   static const char *acquisitionAttributes[] = {
1276     MIprotocol,
1277     MIscanning_sequence, // "GR", "SPGR", etc.
1278     MIrepetition_time,   // as double, milliseconds
1279     MIecho_time,         // as double, milliseconds
1280     MIinversion_time,    // as double, milliseconds
1281     MInum_averages,      // as int
1282     MIimaging_frequency, // in Hz, as double
1283     MIimaged_nucleus,    // "H1", "C13", etc. for MRI
1284     MIradionuclide,      // for PET and SPECT
1285     MIradionuclide_halflife,
1286     MIcontrast_agent,
1287     MItracer,
1288     MIinjection_time,
1289     MIinjection_year,
1290     MIinjection_month,
1291     MIinjection_day,
1292     MIinjection_hour,
1293     MIinjection_minute,
1294     MIinjection_seconds,
1295     MIinjection_length,
1296     MIinjection_dose,
1297     MIdose_units,
1298     MIinjection_volume,
1299     MIinjection_route,
1300     nullptr
1301   };
1302 
1303   int itry = 0;
1304   for (itry = 0; acquisitionAttributes[itry] != nullptr; itry++)
1305   {
1306     if (strcmp(attname, acquisitionAttributes[itry]) == 0)
1307     {
1308       break;
1309     }
1310   }
1311   if (acquisitionAttributes[itry] != nullptr)
1312   {
1313     // Add checks for correct data type?
1314   }
1315   else
1316   {
1317     return 2;
1318   }
1319 
1320   return 1;
1321 }
1322 
1323 //-------------------------------------------------------------------------
ValidateAttribute(const char * varname,const char * attname,vtkDataArray * array)1324 int vtkMINCImageAttributes::ValidateAttribute(
1325   const char *varname, const char *attname, vtkDataArray *array)
1326 {
1327   // Standard variable names
1328   static const char *stdVarNames[] = {
1329     MIrootvariable, MIimage, MIimagemin, MIimagemax,
1330     MIpatient, MIstudy, MIacquisition,
1331     nullptr
1332   };
1333 
1334   int result = 1;
1335   int vartype = 0;
1336 
1337   const char **tryname = nullptr;
1338   for (tryname = stdVarNames; *tryname != nullptr; tryname++)
1339   {
1340     if (strcmp(varname, *tryname) == 0)
1341     {
1342       vartype = 1;
1343       break;
1344     }
1345   }
1346   for (tryname = vtkMINCDimVarNames; *tryname != nullptr; tryname++)
1347   {
1348     if (strcmp(varname, *tryname) == 0)
1349     {
1350       vartype = 2;
1351       break;
1352     }
1353   }
1354 
1355   if (strcmp(varname, MI_EMPTY_STRING) == 0)
1356   {
1357     // Check global attributes
1358     result = this->ValidateGlobalAttribute(attname, array);
1359     // Allow users to create their own global attributes
1360     if (result == 2)
1361     {
1362       result = 1;
1363     }
1364   }
1365   else if (vartype != 0)
1366   {
1367     // Check general attributes
1368     result = this->ValidateGeneralAttribute(varname, attname, array);
1369   }
1370   if (result == 2)
1371   {
1372     if (vartype == 2)
1373     {
1374       result = this->ValidateDimensionAttribute(varname, attname, array);
1375     }
1376     else if (strcmp(varname, MIimage) == 0)
1377     {
1378       result = this->ValidateImageAttribute(varname, attname, array);
1379     }
1380     else if (strcmp(varname, MIimagemin) == 0 ||
1381              strcmp(varname, MIimagemax) == 0)
1382     {
1383       result = this->ValidateImageMinMaxAttribute(varname, attname, array);
1384     }
1385     else if (strcmp(varname, MIpatient) == 0)
1386     {
1387       result = this->ValidatePatientAttribute(varname, attname, array);
1388     }
1389     else if (strcmp(varname, MIstudy) == 0)
1390     {
1391       result = this->ValidateStudyAttribute(varname, attname, array);
1392     }
1393     else if (strcmp(varname, MIacquisition) == 0)
1394     {
1395       result = this->ValidateAcquisitionAttribute(varname, attname, array);
1396     }
1397   }
1398 
1399   return result;
1400 }
1401 
1402 //-------------------------------------------------------------------------
FindValidRange(double range[2])1403 void vtkMINCImageAttributes::FindValidRange(double range[2])
1404 {
1405   // Find the valid range. Start with the default.
1406   range[0] = 0.0;
1407   range[1] = 1.0;
1408 
1409   // Look for the valid_range attribute of the data.
1410   vtkDoubleArray *rangearray =
1411     vtkDoubleArray::SafeDownCast(this->GetAttributeValueAsArray(
1412                                    MIimage, MIvalid_range));
1413   if (rangearray)
1414   {
1415     range[0] = rangearray->GetValue(0);
1416     range[1] = rangearray->GetValue(1);
1417     if (range[0] > range[1])
1418     {
1419       double tmpval = range[0];
1420       range[0] = range[1];
1421       range[1] = tmpval;
1422     }
1423 
1424     if (this->DataType == VTK_FLOAT)
1425     {
1426       // use float precision if VTK_FLOAT
1427       range[0] = static_cast<float>(range[0]);
1428       range[1] = static_cast<float>(range[1]);
1429     }
1430   }
1431   else
1432   {
1433     // If there is no valid_range attribute, use maximum range.
1434     switch (this->DataType)
1435     {
1436       case VTK_CHAR:
1437       case VTK_SIGNED_CHAR:
1438         range[0] = VTK_SIGNED_CHAR_MIN;
1439         range[1] = VTK_SIGNED_CHAR_MAX;
1440         break;
1441       case VTK_UNSIGNED_CHAR:
1442         range[0] = VTK_UNSIGNED_CHAR_MIN;
1443         range[1] = VTK_UNSIGNED_CHAR_MAX;
1444         break;
1445       case VTK_SHORT:
1446         range[0] = VTK_SHORT_MIN;
1447         range[1] = VTK_SHORT_MAX;
1448         break;
1449       case VTK_UNSIGNED_SHORT:
1450         range[0] = VTK_UNSIGNED_SHORT_MIN;
1451         range[1] = VTK_UNSIGNED_SHORT_MAX;
1452         break;
1453       case VTK_INT:
1454         range[0] = VTK_INT_MIN;
1455         range[1] = VTK_INT_MAX;
1456         break;
1457       case VTK_UNSIGNED_INT:
1458         range[0] = VTK_UNSIGNED_INT_MIN;
1459         range[1] = VTK_UNSIGNED_INT_MAX;
1460         break;
1461       case VTK_FLOAT:
1462         range[0] = -FLT_MAX;
1463         range[1] = FLT_MAX;
1464         break;
1465       case VTK_DOUBLE:
1466         range[0] = -DBL_MAX;
1467         range[1] = DBL_MAX;
1468         break;
1469     }
1470   }
1471 
1472   // If the valid_range is set to the full float range, replace
1473   // with the image range.
1474   if ((this->DataType == VTK_FLOAT && range[1] == FLT_MAX) ||
1475       (this->DataType == VTK_DOUBLE && range[1] == DBL_MAX))
1476   {
1477     if (this->ImageMin && this->ImageMax &&
1478         this->ImageMin->GetNumberOfTuples() > 0 &&
1479         this->ImageMax->GetNumberOfTuples() > 0)
1480     {
1481       range[0] = this->ImageMin->GetRange()[0];
1482       range[1] = this->ImageMax->GetRange()[1];
1483     }
1484     else
1485     {
1486       range[0] = 0.0;
1487       range[1] = 1.0;
1488     }
1489   }
1490 }
1491 
1492 //-------------------------------------------------------------------------
FindImageRange(double range[2])1493 void vtkMINCImageAttributes::FindImageRange(double range[2])
1494 {
1495   // Initialize to the default values
1496   range[0] = 0.0;
1497   range[1] = 1.0;
1498 
1499   // If image-min and image-max variables exist, use them.
1500   // Otherwise, use the valid_range of the data instead.
1501   if (this->ImageMin && this->ImageMax &&
1502       this->ImageMin->GetNumberOfTuples() > 0 &&
1503       this->ImageMax->GetNumberOfTuples() > 0)
1504   {
1505     range[0] = this->ImageMin->GetRange()[0];
1506     range[1] = this->ImageMax->GetRange()[1];
1507   }
1508   else
1509   {
1510     this->FindValidRange(range);
1511   }
1512 }
1513 
1514 //-------------------------------------------------------------------------
ShallowCopy(vtkMINCImageAttributes * source)1515 void vtkMINCImageAttributes::ShallowCopy(vtkMINCImageAttributes *source)
1516 {
1517   this->SetName(source->GetName());
1518   this->SetDataType(source->GetDataType());
1519 
1520   this->SetImageMin(source->GetImageMin());
1521   this->SetImageMax(source->GetImageMax());
1522   this->SetNumberOfImageMinMaxDimensions(
1523     source->GetNumberOfImageMinMaxDimensions());
1524 
1525   this->DimensionNames->DeepCopy(source->GetDimensionNames());
1526   this->DimensionLengths->DeepCopy(source->GetDimensionLengths());
1527 
1528   this->VariableNames->Reset();
1529   this->AttributeValues->Clear();
1530   this->AttributeNames->Clear();
1531 
1532   vtkStringArray *varnames = source->GetVariableNames();
1533   vtkIdType nvar = varnames->GetNumberOfValues();
1534   for (vtkIdType ivar = 0; ivar <= nvar; ivar++)
1535   {
1536     // set varname to empty last time around to get global attributes
1537     const char *varname = MI_EMPTY_STRING;
1538     if (ivar < nvar)
1539     {
1540       varname = varnames->GetValue(ivar);
1541     }
1542     vtkStringArray *attnames = source->GetAttributeNames(varname);
1543     vtkIdType natt = attnames->GetNumberOfValues();
1544     for (vtkIdType iatt = 0; iatt < natt; iatt++)
1545     {
1546       const char *attname = attnames->GetValue(iatt);
1547       this->SetAttributeValueAsArray(
1548         varname, attname, source->GetAttributeValueAsArray(varname, attname));
1549     }
1550   }
1551 
1552   if (this->StringStore)
1553   {
1554     this->StringStore->Reset();
1555   }
1556 }
1557