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