/*========================================================================= Program: Visualization Toolkit Module: vtkMergeTables.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /*------------------------------------------------------------------------- Copyright 2008 Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. -------------------------------------------------------------------------*/ #include "vtkMergeTables.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMergeColumns.h" #include "vtkObjectFactory.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkStringArray.h" #include "vtkTable.h" vtkStandardNewMacro(vtkMergeTables); //------------------------------------------------------------------------------ vtkMergeTables::vtkMergeTables() { this->FirstTablePrefix = nullptr; this->SecondTablePrefix = nullptr; this->MergeColumnsByName = true; this->PrefixAllButMerged = false; this->SetFirstTablePrefix("Table1."); this->SetSecondTablePrefix("Table2."); this->SetNumberOfInputPorts(2); this->SetNumberOfOutputPorts(1); } //------------------------------------------------------------------------------ vtkMergeTables::~vtkMergeTables() { this->SetFirstTablePrefix(nullptr); this->SetSecondTablePrefix(nullptr); } //------------------------------------------------------------------------------ int vtkMergeTables::RequestData( vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // Get input tables vtkInformation* table1Info = inputVector[0]->GetInformationObject(0); vtkTable* table1 = vtkTable::SafeDownCast(table1Info->Get(vtkDataObject::DATA_OBJECT())); vtkInformation* table2Info = inputVector[1]->GetInformationObject(0); vtkTable* table2 = vtkTable::SafeDownCast(table2Info->Get(vtkDataObject::DATA_OBJECT())); // Get output table vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkTable* output = vtkTable::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); if (!this->FirstTablePrefix || !this->SecondTablePrefix) { vtkErrorMacro("FirstTablePrefix and/or SecondTablePrefix must be non-null."); return 0; } if (!strcmp(this->FirstTablePrefix, this->SecondTablePrefix)) { vtkErrorMacro("FirstTablePrefix and SecondTablePrefix must be different."); return 0; } // Add columns from table 1 for (int c = 0; c < table1->GetNumberOfColumns(); c++) { vtkAbstractArray* col = table1->GetColumn(c); char* name = col->GetName(); char* newName = name; if (this->PrefixAllButMerged) { int len = static_cast(strlen(name)); int prefixLen = static_cast(strlen(this->FirstTablePrefix)); newName = new char[prefixLen + len + 1]; strcpy(newName, this->FirstTablePrefix); strcat(newName, name); } vtkAbstractArray* newCol = vtkAbstractArray::CreateArray(col->GetDataType()); newCol->DeepCopy(col); newCol->SetName(newName); if (newName != name) { delete[] newName; } // vtkWarningMacro("adding column " << newCol->GetName() << " of size " << // newCol->GetNumberOfTuples()); output->AddColumn(newCol); newCol->Delete(); } // Add empty values for (int r = 0; r < table2->GetNumberOfRows(); r++) { output->InsertNextBlankRow(); } // Add columns from table 2 vtkStringArray* toMerge = vtkStringArray::New(); vtkTable* tempTable = vtkTable::New(); for (int c = 0; c < table2->GetNumberOfColumns(); c++) { vtkAbstractArray* col = table2->GetColumn(c); char* name = col->GetName(); vtkAbstractArray* newCol = vtkAbstractArray::CreateArray(col->GetDataType()); if (table1->GetColumnByName(name) != nullptr) { // We have a naming conflict. // Rename both columns using the prefixes. int len = static_cast(strlen(name)); char* newName1 = new char[len + strlen(this->FirstTablePrefix) + 1]; strcpy(newName1, this->FirstTablePrefix); strcat(newName1, name); if (!this->PrefixAllButMerged) { vtkAbstractArray* col1 = output->GetColumnByName(name); col1->SetName(newName1); } char* newName2 = new char[len + strlen(this->SecondTablePrefix) + 1]; strcpy(newName2, this->SecondTablePrefix); strcat(newName2, name); newCol->SetName(newName2); toMerge->InsertNextValue(newName1); toMerge->InsertNextValue(newName2); toMerge->InsertNextValue(name); delete[] newName1; delete[] newName2; } else { char* newName = name; if (this->PrefixAllButMerged) { int len = static_cast(strlen(name)); int prefixLen = static_cast(strlen(this->SecondTablePrefix)); newName = new char[prefixLen + len + 1]; strcpy(newName, this->SecondTablePrefix); strcat(newName, name); } newCol->SetName(newName); if (newName != name) { delete[] newName; } } tempTable->AddColumn(newCol); newCol->Delete(); } // Add empty values for (int r = 0; r < table1->GetNumberOfRows(); r++) { tempTable->InsertNextBlankRow(); } // Add values from table 2 for (int r = 0; r < table2->GetNumberOfRows(); r++) { for (int c = 0; c < tempTable->GetNumberOfColumns(); c++) { vtkAbstractArray* tempCol = tempTable->GetColumn(c); vtkAbstractArray* col = table2->GetColumn(c); tempCol->InsertNextTuple(r, col); } } // Move the columns from the temp table to the output table for (int c = 0; c < tempTable->GetNumberOfColumns(); c++) { vtkAbstractArray* col = tempTable->GetColumn(c); // vtkWarningMacro("adding column " << col->GetName() << " of size " << // col->GetNumberOfTuples()); output->AddColumn(col); } tempTable->Delete(); // Merge any arrays that have the same name vtkMergeColumns* mergeColumns = vtkMergeColumns::New(); vtkTable* temp = vtkTable::New(); temp->ShallowCopy(output); mergeColumns->SetInputData(temp); if (this->MergeColumnsByName) { for (vtkIdType i = 0; i < toMerge->GetNumberOfValues(); i += 3) { mergeColumns->SetInputArrayToProcess( 0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_ROWS, toMerge->GetValue(i).c_str()); mergeColumns->SetInputArrayToProcess( 1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_ROWS, toMerge->GetValue(i + 1).c_str()); mergeColumns->SetMergedColumnName(toMerge->GetValue(i + 2).c_str()); mergeColumns->Update(); temp->ShallowCopy(mergeColumns->GetOutput()); } } mergeColumns->Delete(); toMerge->Delete(); output->ShallowCopy(temp); temp->Delete(); // Clean up pipeline information int piece = -1; int npieces = -1; if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER())) { piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()); npieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()); } output->GetInformation()->Set(vtkDataObject::DATA_NUMBER_OF_PIECES(), npieces); output->GetInformation()->Set(vtkDataObject::DATA_PIECE_NUMBER(), piece); return 1; } //------------------------------------------------------------------------------ void vtkMergeTables::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "FirstTablePrefix: " << (this->FirstTablePrefix ? this->FirstTablePrefix : "(null)") << endl; os << indent << "SecondTablePrefix: " << (this->SecondTablePrefix ? this->SecondTablePrefix : "(null)") << endl; os << indent << "MergeColumnsByName: " << (this->MergeColumnsByName ? "on" : "off") << endl; os << indent << "PrefixAllButMerged: " << (this->PrefixAllButMerged ? "on" : "off") << endl; }