1
2 /*=========================================================================
3
4 Program: Visualization Toolkit
5 Module: vtkSplitColumnComponents.cxx
6
7 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
8 All rights reserved.
9 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
10
11 This software is distributed WITHOUT ANY WARRANTY; without even
12 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 PURPOSE. See the above copyright notice for more information.
14
15 =========================================================================*/
16 #include "vtkSplitColumnComponents.h"
17
18 #include "vtkAbstractArray.h"
19 #include "vtkDataArrayRange.h"
20 #include "vtkFieldData.h"
21 #include "vtkInformation.h"
22 #include "vtkInformationIntegerKey.h"
23 #include "vtkInformationStringKey.h"
24 #include "vtkInformationVector.h"
25 #include "vtkIntArray.h"
26 #include "vtkObjectFactory.h"
27 #include "vtkStringArray.h"
28 #include "vtkTable.h"
29 #include "vtkVariantArray.h"
30
31 #include <cmath>
32 #include <sstream>
33
34 vtkStandardNewMacro(vtkSplitColumnComponents);
35 vtkInformationKeyMacro(vtkSplitColumnComponents, ORIGINAL_ARRAY_NAME, String);
36 vtkInformationKeyMacro(vtkSplitColumnComponents, ORIGINAL_COMPONENT_NUMBER, Integer);
37 //------------------------------------------------------------------------------
vtkSplitColumnComponents()38 vtkSplitColumnComponents::vtkSplitColumnComponents()
39 : CalculateMagnitudes(true)
40 , NamingMode(vtkSplitColumnComponents::NUMBERS_WITH_PARENS)
41 {
42 this->SetNumberOfInputPorts(1);
43 this->SetNumberOfOutputPorts(1);
44 }
45
46 //------------------------------------------------------------------------------
47 vtkSplitColumnComponents::~vtkSplitColumnComponents() = default;
48
49 //------------------------------------------------------------------------------
RequestData(vtkInformation *,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)50 int vtkSplitColumnComponents::RequestData(
51 vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
52 {
53 // Get input tables
54 vtkInformation* table1Info = inputVector[0]->GetInformationObject(0);
55 vtkTable* table = vtkTable::SafeDownCast(table1Info->Get(vtkDataObject::DATA_OBJECT()));
56
57 // Get output table
58 vtkInformation* outInfo = outputVector->GetInformationObject(0);
59 vtkTable* output = vtkTable::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
60
61 // Add columns from table, split multiple component columns as necessary
62 for (int i = 0; i < table->GetNumberOfColumns(); ++i)
63 {
64 vtkAbstractArray* col = table->GetColumn(i);
65 if (col->GetName() == nullptr)
66 {
67 vtkWarningMacro("Skipping column with no name!");
68 continue;
69 }
70
71 int components = col->GetNumberOfComponents();
72 if (components == 1)
73 {
74 output->AddColumn(col);
75 }
76 else if (components > 1)
77 {
78 // Split the multicomponent column up into individual columns
79 int colSize = col->GetNumberOfTuples();
80 for (int j = 0; j < components; ++j)
81 {
82 const std::string component_label = this->GetComponentLabel(col, j);
83 vtkAbstractArray* newCol = vtkAbstractArray::CreateArray(col->GetDataType());
84 newCol->SetName(component_label.c_str());
85 newCol->SetNumberOfTuples(colSize);
86 // pass component name overrides, if provided.
87 if (col->HasAComponentName())
88 {
89 newCol->SetComponentName(0, col->GetComponentName(j));
90 }
91 // Now copy the components into their new columns
92 if (col->IsA("vtkDataArray"))
93 {
94 // Handle numeric array types
95 vtkDataArray* srcDataArray = vtkDataArray::SafeDownCast(col);
96 vtkDataArray* dstDataArray = vtkDataArray::SafeDownCast(newCol);
97 dstDataArray->CopyComponent(0, srcDataArray, j);
98 }
99 else if (col->GetDataType() == VTK_STRING)
100 {
101 vtkStringArray* srcArray = vtkStringArray::SafeDownCast(col);
102 vtkStringArray* dstArray = vtkStringArray::SafeDownCast(newCol);
103 int numSrcComponents = srcArray->GetNumberOfComponents();
104 for (vtkIdType id = 0; id < srcArray->GetNumberOfTuples(); ++id)
105 {
106 dstArray->SetValue(id, srcArray->GetValue(id * numSrcComponents + j));
107 }
108 }
109 else if (col->GetDataType() == VTK_VARIANT)
110 {
111 vtkVariantArray* srcArray = vtkVariantArray::SafeDownCast(col);
112 vtkVariantArray* dstArray = vtkVariantArray::SafeDownCast(newCol);
113 int numSrcComponents = srcArray->GetNumberOfComponents();
114 for (vtkIdType id = 0; id < srcArray->GetNumberOfTuples(); ++id)
115 {
116 dstArray->SetValue(id, srcArray->GetValue(id * numSrcComponents + j));
117 }
118 }
119 else
120 {
121 vtkErrorMacro("Unsupported array type " << col->GetClassName());
122 }
123 if (auto info = newCol->GetInformation())
124 {
125 info->Set(ORIGINAL_ARRAY_NAME(), col->GetName());
126 info->Set(ORIGINAL_COMPONENT_NUMBER(), j);
127 }
128 output->AddColumn(newCol);
129 newCol->Delete();
130 }
131 // Add a magnitude column and calculate values if requested
132 if (this->CalculateMagnitudes && col->IsA("vtkDataArray"))
133 {
134 std::string component_label = this->GetComponentLabel(col, -1 /* for magnitude */);
135 vtkAbstractArray* newCol = vtkAbstractArray::CreateArray(col->GetDataType());
136 newCol->SetName(component_label.c_str());
137 newCol->SetNumberOfTuples(colSize);
138 // Now calculate the magnitude column
139 vtkDataArray* srcDataArray = vtkDataArray::SafeDownCast(col);
140 vtkDataArray* dstDataArray = vtkDataArray::SafeDownCast(newCol);
141
142 const auto srcRange = vtk::DataArrayTupleRange(srcDataArray);
143 auto dstRange = vtk::DataArrayValueRange<1>(dstDataArray);
144 auto dstIter = dstRange.begin();
145
146 for (const auto tuple : srcRange)
147 {
148 double mag = 0.0;
149 for (const auto component : tuple)
150 {
151 auto x = static_cast<double>(component);
152 mag += x * x;
153 }
154 (*dstIter) = std::sqrt(mag);
155
156 ++dstIter;
157 }
158
159 if (auto info = newCol->GetInformation())
160 {
161 info->Set(ORIGINAL_ARRAY_NAME(), col->GetName());
162 info->Set(ORIGINAL_COMPONENT_NUMBER(), -1); // for magnitude
163 }
164 output->AddColumn(newCol);
165 newCol->Delete();
166 }
167 }
168 }
169 return 1;
170 }
171
172 namespace
173 {
174 //------------------------------------------------------------------------------
vtkDefaultComponentName(int componentNumber,int componentCount)175 std::string vtkDefaultComponentName(int componentNumber, int componentCount)
176 {
177 if (componentCount <= 1)
178 {
179 return "";
180 }
181 else if (componentNumber == -1)
182 {
183 return "Magnitude";
184 }
185 else if (componentCount <= 3 && componentNumber < 3)
186 {
187 const char* titles[] = { "X", "Y", "Z" };
188 return titles[componentNumber];
189 }
190 else if (componentCount == 6)
191 {
192 const char* titles[] = { "XX", "YY", "ZZ", "XY", "YZ", "XZ" };
193 // Assume this is a symmetric matrix.
194 return titles[componentNumber];
195 }
196 else
197 {
198 std::ostringstream buffer;
199 buffer << componentNumber;
200 return buffer.str();
201 }
202 }
vtkGetComponentName(vtkAbstractArray * array,int component_no)203 std::string vtkGetComponentName(vtkAbstractArray* array, int component_no)
204 {
205 const char* name = array->GetComponentName(component_no);
206 if (name)
207 {
208 return name;
209 }
210 return vtkDefaultComponentName(component_no, array->GetNumberOfComponents());
211 }
212 };
213
214 //------------------------------------------------------------------------------
GetComponentLabel(vtkAbstractArray * array,int component_no)215 std::string vtkSplitColumnComponents::GetComponentLabel(vtkAbstractArray* array, int component_no)
216 {
217 std::ostringstream stream;
218 switch (this->NamingMode)
219 {
220 case NUMBERS_WITH_PARENS:
221 stream << array->GetName() << " (";
222 if (component_no == -1)
223 {
224 stream << "Magnitude)";
225 }
226 else
227 {
228 stream << component_no << ")";
229 }
230 break;
231
232 case NUMBERS_WITH_UNDERSCORES:
233 stream << array->GetName() << "_";
234 if (component_no == -1)
235 {
236 stream << "Magnitude";
237 }
238 else
239 {
240 stream << component_no;
241 }
242 break;
243
244 case NAMES_WITH_PARENS:
245 stream << array->GetName() << " (" << vtkGetComponentName(array, component_no).c_str() << ")";
246 break;
247
248 case NAMES_WITH_UNDERSCORES:
249 default:
250 stream << array->GetName() << "_" << vtkGetComponentName(array, component_no).c_str();
251 break;
252 }
253 return stream.str();
254 }
255
256 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)257 void vtkSplitColumnComponents::PrintSelf(ostream& os, vtkIndent indent)
258 {
259 this->Superclass::PrintSelf(os, indent);
260 os << indent << "CalculateMagnitudes: " << this->CalculateMagnitudes << endl;
261 os << indent << "NamingMode: ";
262 switch (this->NamingMode)
263 {
264 case NAMES_WITH_UNDERSCORES:
265 os << "NAMES_WITH_UNDERSCORES" << endl;
266 break;
267 case NAMES_WITH_PARENS:
268 os << "NAMES_WITH_PARENS" << endl;
269 break;
270 case NUMBERS_WITH_UNDERSCORES:
271 os << "NUMBERS_WITH_UNDERSCORES" << endl;
272 break;
273 case NUMBERS_WITH_PARENS:
274 os << "NUMBERS_WITH_PARENS" << endl;
275 break;
276 default:
277 os << "INVALID" << endl;
278 }
279 }
280