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