1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkMergeTables.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 Copyright 2008 Sandia Corporation.
17 Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
18 the U.S. Government retains certain rights in this software.
19 -------------------------------------------------------------------------*/
20
21 #include "vtkMergeTables.h"
22
23 #include "vtkInformation.h"
24 #include "vtkInformationVector.h"
25 #include "vtkMergeColumns.h"
26 #include "vtkObjectFactory.h"
27 #include "vtkStreamingDemandDrivenPipeline.h"
28 #include "vtkStringArray.h"
29 #include "vtkTable.h"
30
31 vtkStandardNewMacro(vtkMergeTables);
32 //---------------------------------------------------------------------------
vtkMergeTables()33 vtkMergeTables::vtkMergeTables()
34 {
35 this->FirstTablePrefix = 0;
36 this->SecondTablePrefix = 0;
37 this->MergeColumnsByName = true;
38 this->PrefixAllButMerged = false;
39 this->SetFirstTablePrefix("Table1.");
40 this->SetSecondTablePrefix("Table2.");
41 this->SetNumberOfInputPorts(2);
42 this->SetNumberOfOutputPorts(1);
43 }
44
45 //---------------------------------------------------------------------------
~vtkMergeTables()46 vtkMergeTables::~vtkMergeTables()
47 {
48 this->SetFirstTablePrefix(0);
49 this->SetSecondTablePrefix(0);
50 }
51
52 //---------------------------------------------------------------------------
RequestData(vtkInformation *,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)53 int vtkMergeTables::RequestData(
54 vtkInformation*,
55 vtkInformationVector** inputVector,
56 vtkInformationVector* outputVector)
57 {
58 // Get input tables
59 vtkInformation* table1Info = inputVector[0]->GetInformationObject(0);
60 vtkTable* table1 = vtkTable::SafeDownCast(
61 table1Info->Get(vtkDataObject::DATA_OBJECT()));
62 vtkInformation* table2Info = inputVector[1]->GetInformationObject(0);
63 vtkTable* table2 = vtkTable::SafeDownCast(
64 table2Info->Get(vtkDataObject::DATA_OBJECT()));
65
66 // Get output table
67 vtkInformation* outInfo = outputVector->GetInformationObject(0);
68 vtkTable* output = vtkTable::SafeDownCast(
69 outInfo->Get(vtkDataObject::DATA_OBJECT()));
70
71 if (!this->FirstTablePrefix || !this->SecondTablePrefix)
72 {
73 vtkErrorMacro("FirstTablePrefix and/or SecondTablePrefix must be non-null.");
74 return 0;
75 }
76 if (!strcmp(this->FirstTablePrefix, this->SecondTablePrefix))
77 {
78 vtkErrorMacro("FirstTablePrefix and SecondTablePrefix must be different.");
79 return 0;
80 }
81
82 // Add columns from table 1
83 for (int c = 0; c < table1->GetNumberOfColumns(); c++)
84 {
85 vtkAbstractArray* col = table1->GetColumn(c);
86 char* name = col->GetName();
87 char* newName = name;
88 if (this->PrefixAllButMerged)
89 {
90 int len = static_cast<int>(strlen(name));
91 int prefixLen = static_cast<int>(strlen(this->FirstTablePrefix));
92 newName = new char[prefixLen + len + 1];
93 strcpy(newName, this->FirstTablePrefix);
94 strcat(newName, name);
95 }
96 vtkAbstractArray* newCol = vtkAbstractArray::CreateArray(col->GetDataType());
97 newCol->DeepCopy(col);
98 newCol->SetName(newName);
99 if(newName!=name)
100 {
101 delete[] newName;
102 }
103 //vtkWarningMacro("adding column " << newCol->GetName() << " of size " << newCol->GetNumberOfTuples());
104 output->AddColumn(newCol);
105 newCol->Delete();
106 }
107
108 // Add empty values
109 for (int r = 0; r < table2->GetNumberOfRows(); r++)
110 {
111 output->InsertNextBlankRow();
112 }
113
114 // Add columns from table 2
115 vtkStringArray* toMerge = vtkStringArray::New();
116 vtkTable* tempTable = vtkTable::New();
117 for (int c = 0; c < table2->GetNumberOfColumns(); c++)
118 {
119 vtkAbstractArray* col = table2->GetColumn(c);
120 char* name = col->GetName();
121 vtkAbstractArray* newCol = vtkAbstractArray::CreateArray(col->GetDataType());
122 if (table1->GetColumnByName(name) != 0)
123 {
124 // We have a naming conflict.
125 // Rename both columns using the prefixes.
126 int len = static_cast<int>(strlen(name));
127 char* newName1 = new char[len + strlen(this->FirstTablePrefix) + 1];
128 strcpy(newName1, this->FirstTablePrefix);
129 strcat(newName1, name);
130 if (!this->PrefixAllButMerged)
131 {
132 vtkAbstractArray* col1 = output->GetColumnByName(name);
133 col1->SetName(newName1);
134 }
135 char* newName2 = new char[len + strlen(this->SecondTablePrefix) + 1];
136 strcpy(newName2, this->SecondTablePrefix);
137 strcat(newName2, name);
138 newCol->SetName(newName2);
139 toMerge->InsertNextValue(newName1);
140 toMerge->InsertNextValue(newName2);
141 toMerge->InsertNextValue(name);
142 delete[] newName1;
143 delete[] newName2;
144 }
145 else
146 {
147 char* newName = name;
148 if (this->PrefixAllButMerged)
149 {
150 int len = static_cast<int>(strlen(name));
151 int prefixLen = static_cast<int>(strlen(this->SecondTablePrefix));
152 newName = new char[prefixLen + len + 1];
153 strcpy(newName, this->SecondTablePrefix);
154 strcat(newName, name);
155 }
156 newCol->SetName(newName);
157 if(newName!=name)
158 {
159 delete[] newName;
160 }
161 }
162 tempTable->AddColumn(newCol);
163 newCol->Delete();
164 }
165
166 // Add empty values
167 for (int r = 0; r < table1->GetNumberOfRows(); r++)
168 {
169 tempTable->InsertNextBlankRow();
170 }
171
172 // Add values from table 2
173 for (int r = 0; r < table2->GetNumberOfRows(); r++)
174 {
175 for (int c = 0; c < tempTable->GetNumberOfColumns(); c++)
176 {
177 vtkAbstractArray* tempCol = tempTable->GetColumn(c);
178 vtkAbstractArray* col = table2->GetColumn(c);
179 tempCol->InsertNextTuple(r, col);
180 }
181 }
182
183 // Move the columns from the temp table to the output table
184 for (int c = 0; c < tempTable->GetNumberOfColumns(); c++)
185 {
186 vtkAbstractArray* col = tempTable->GetColumn(c);
187 //vtkWarningMacro("adding column " << col->GetName() << " of size " << col->GetNumberOfTuples());
188 output->AddColumn(col);
189 }
190 tempTable->Delete();
191
192 // Merge any arrays that have the same name
193 vtkMergeColumns* mergeColumns = vtkMergeColumns::New();
194 vtkTable* temp = vtkTable::New();
195 temp->ShallowCopy(output);
196 mergeColumns->SetInputData(temp);
197 if (this->MergeColumnsByName)
198 {
199 for (vtkIdType i = 0; i < toMerge->GetNumberOfValues(); i += 3)
200 {
201 mergeColumns->SetInputArrayToProcess(
202 0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_ROWS,
203 toMerge->GetValue(i).c_str());
204 mergeColumns->SetInputArrayToProcess(
205 1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_ROWS,
206 toMerge->GetValue(i+1).c_str());
207 mergeColumns->SetMergedColumnName(toMerge->GetValue(i+2).c_str());
208 mergeColumns->Update();
209 temp->ShallowCopy(mergeColumns->GetOutput());
210 }
211 }
212 mergeColumns->Delete();
213 toMerge->Delete();
214
215 output->ShallowCopy(temp);
216 temp->Delete();
217
218 // Clean up pipeline information
219 int piece = -1;
220 int npieces = -1;
221 if (outInfo->Has(
222 vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()))
223 {
224 piece = outInfo->Get(
225 vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
226 npieces = outInfo->Get(
227 vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
228 }
229 output->GetInformation()->Set(vtkDataObject::DATA_NUMBER_OF_PIECES(), npieces);
230 output->GetInformation()->Set(vtkDataObject::DATA_PIECE_NUMBER(), piece);
231
232 return 1;
233 }
234
235 //---------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)236 void vtkMergeTables::PrintSelf(ostream& os, vtkIndent indent)
237 {
238 this->Superclass::PrintSelf(os, indent);
239 os << indent << "FirstTablePrefix: "
240 << (this->FirstTablePrefix ? this->FirstTablePrefix : "(null)") << endl;
241 os << indent << "SecondTablePrefix: "
242 << (this->SecondTablePrefix ? this->SecondTablePrefix : "(null)") << endl;
243 os << indent << "MergeColumnsByName: "
244 << (this->MergeColumnsByName ? "on" : "off") << endl;
245 os << indent << "PrefixAllButMerged: "
246 << (this->PrefixAllButMerged ? "on" : "off") << endl;
247 }
248