/*========================================================================= Program: Visualization Toolkit Module: vtkJoinTables.txx 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. =========================================================================*/ //------------------------------------------------------------------------------ template KeyValues GetCell(KeyColType*, int); //------------------------------------------------------------------------------ template void InsertNext(KeyColType*, KeyValues); //------------------------------------------------------------------------------ template <> inline void InsertNext(vtkDataArray* col, double val) { col->InsertNextTuple(&val); } //------------------------------------------------------------------------------ template <> inline void InsertNext(vtkStringArray* col, vtkStdString val) { col->InsertNextValue(val); } //------------------------------------------------------------------------------ template <> inline double GetCell(vtkDataArray* col, int index) { return col->GetTuple(index)[0]; } //------------------------------------------------------------------------------ template <> inline vtkStdString GetCell(vtkStringArray* col, int index) { return (col->GetValue(index)); } //------------------------------------------------------------------------------ template void vtkJoinTables::MergeColumn(ColType* outputColumn, ColType* Column, KeyColType* outputKeyCol, const char* name, std::map map) { outputColumn->SetName(name); outputColumn->SetNumberOfComponents(Column->GetNumberOfComponents()); // Loop over numeric tuples for (int i = 0; i < outputKeyCol->GetNumberOfValues(); i++) { KeyValues id = GetCell(outputKeyCol, i); if (auto numericColumn = vtkDataArray::SafeDownCast(Column)) { auto outputNumericColumn = vtkDataArray::SafeDownCast(outputColumn); if (map.count(id)) { double* val = numericColumn->GetTuple(map.find(id)->second); outputNumericColumn->InsertNextTuple(val); } else { double val = this->ReplacementValue; outputNumericColumn->InsertNextTuple(&val); } } else if (auto stringColumn = vtkStringArray::SafeDownCast(Column)) { auto outputStringColumn = vtkStringArray::SafeDownCast(outputColumn); if (map.count(id)) { auto val = stringColumn->GetValue(map.find(id)->second); outputStringColumn->InsertNextValue(val); } else { auto val = vtkStdString(""); outputStringColumn->InsertNextValue(val); } } else { vtkWarningMacro("Key column type is unsupported."); } } } //------------------------------------------------------------------------------ template void vtkJoinTables::JoinAlgorithm(vtkTable* left, vtkTable* right, vtkTable* output, KeyColType* leftKeyCol, KeyColType* rightKeyCol, Maps* maps) { /* * 1- First column of the output table will be the key. Start by filling this column with adequate * values according to the join method. */ vtkIdType leftSize = leftKeyCol->GetNumberOfTuples(); vtkIdType rightSize = rightKeyCol->GetNumberOfTuples(); vtkSmartPointer outputKeyCol = leftKeyCol->NewInstance(); outputKeyCol->SetName(this->LeftKey.c_str()); switch (this->Mode) { case INTERSECTION: { for (int i = 0; i < leftSize; i++) { for (int j = 0; j < rightSize; j++) { if (GetCell(leftKeyCol, i) == GetCell(rightKeyCol, j)) { auto val = GetCell(leftKeyCol, i); InsertNext(outputKeyCol, val); maps->left.insert(std::make_pair(val, i)); maps->right.insert(std::make_pair(val, j)); break; } } } break; } case UNION: { for (int i = 0; i < rightSize; i++) { auto val = GetCell(rightKeyCol, i); maps->right.insert(std::make_pair(val, i)); bool existsInLeftKeyCol = false; for (int j = 0; j < leftSize; j++) { if (i == 0) { auto val0 = GetCell(leftKeyCol, j); InsertNext(outputKeyCol, val0); maps->left.insert(std::make_pair(val0, j)); } if (!existsInLeftKeyCol && GetCell(leftKeyCol, j) == GetCell(rightKeyCol, i)) { // Flag the value from the right table when it's a duplicate from the // left table existsInLeftKeyCol = true; } } if (!existsInLeftKeyCol) { // Insert only the values of right that do not exist in left InsertNext(outputKeyCol, val); } } break; } case LEFT: { for (int i = 0; i < leftSize; i++) { auto val = GetCell(leftKeyCol, i); InsertNext(outputKeyCol, val); maps->left.insert(std::make_pair(val, i)); } for (int j = 0; j < rightSize; j++) { auto val = GetCell(rightKeyCol, j); maps->right.insert(std::make_pair(val, j)); } break; } case RIGHT: { for (int i = 0; i < leftSize; i++) { auto val = GetCell(leftKeyCol, i); maps->left.insert(std::make_pair(val, i)); } for (int j = 0; j < rightSize; j++) { auto val = GetCell(rightKeyCol, j); InsertNext(outputKeyCol, val); maps->right.insert(std::make_pair(val, j)); } break; } default: vtkErrorMacro("Unknown Mode"); } output->AddColumn(outputKeyCol); /* * 2- Now fill the rest of the columns. Add the columns from the left table, and then the * columns from the right table. */ // left table and LeftKey for (int lc = 0; lc < left->GetNumberOfColumns(); lc++) { if (std::string(left->GetColumnName(lc)) == this->LeftKey) { // do not copy the original key column continue; } vtkAbstractArray* currentColumn = left->GetColumn(lc); if (auto numericColumn = vtkDataArray::SafeDownCast(currentColumn)) { vtkDataArray* outputColumn = numericColumn->NewInstance(); this->MergeColumn( outputColumn, numericColumn, outputKeyCol, left->GetColumnName(lc), maps->left); output->AddColumn(outputColumn); outputColumn->Delete(); } else if (auto stringColumn = vtkStringArray::SafeDownCast(currentColumn)) { vtkStringArray* outputColumn = stringColumn->NewInstance(); this->MergeColumn( outputColumn, stringColumn, outputKeyCol, left->GetColumnName(lc), maps->left); output->AddColumn(outputColumn); outputColumn->Delete(); } } // right table and RightKey for (int lc = 0; lc < right->GetNumberOfColumns(); lc++) { if (std::string(right->GetColumnName(lc)) == this->RightKey) { // do not copy the original key column continue; } auto currentColumn = right->GetColumn(lc); if (output->GetColumnByName(right->GetColumnName(lc))) { // We have a duplicate column name. Add suffixes. output->GetColumnByName(right->GetColumnName(lc)) ->SetName((std::string(right->GetColumnName(lc)) + "_0").c_str()); currentColumn->SetName((std::string(right->GetColumnName(lc)) + "_1").c_str()); } else { currentColumn->SetName(right->GetColumnName(lc)); } if (auto numericColumn = vtkDataArray::SafeDownCast(currentColumn)) { vtkDataArray* outputColumn = numericColumn->NewInstance(); this->MergeColumn( outputColumn, numericColumn, outputKeyCol, right->GetColumnName(lc), maps->right); output->AddColumn(outputColumn); outputColumn->Delete(); } else if (auto stringColumn = vtkStringArray::SafeDownCast(currentColumn)) { vtkStringArray* outputColumn = stringColumn->NewInstance(); this->MergeColumn( outputColumn, stringColumn, outputKeyCol, right->GetColumnName(lc), maps->right); output->AddColumn(outputColumn); outputColumn->Delete(); } } outputKeyCol->Delete(); }