// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkReflectionUtilities.h" #include "vtkCellData.h" #include "vtkCellType.h" #include "vtkDataArray.h" #include "vtkDataSet.h" #include "vtkDataSetAttributes.h" #include "vtkFieldData.h" #include "vtkHigherOrderHexahedron.h" #include "vtkHigherOrderQuadrilateral.h" #include "vtkHigherOrderTetra.h" #include "vtkHigherOrderWedge.h" #include "vtkPointData.h" #include VTK_ABI_NAMESPACE_BEGIN //------------------------------------------------------------------------------ void vtkReflectionUtilities::FindReflectableArrays( vtkFieldData* fd, std::vector>& reflectableArrays) { // Find all reflectable arrays for (int iArr = 0; iArr < fd->GetNumberOfArrays(); iArr++) { vtkDataArray* array = vtkDataArray::SafeDownCast(fd->GetAbstractArray(iArr)); if (!array) { continue; } // Only signed arrays are reflectable int dataType = array->GetDataType(); if ((dataType == VTK_CHAR && VTK_TYPE_CHAR_IS_SIGNED) || dataType == VTK_SIGNED_CHAR || dataType == VTK_SHORT || dataType == VTK_INT || dataType == VTK_LONG || dataType == VTK_FLOAT || dataType == VTK_DOUBLE || dataType == VTK_ID_TYPE) { // Only vectors and tensors are reflectable int nComp = array->GetNumberOfComponents(); if (nComp == 3 || nComp == 6 || nComp == 9) { reflectableArrays.emplace_back(iArr, nComp); } } } } //------------------------------------------------------------------------------ void vtkReflectionUtilities::ReflectTuple(double* tuple, int* mirrorDir, int nComp) { for (int j = 0; j < nComp; j++) { tuple[j] *= mirrorDir[j]; } } //------------------------------------------------------------------------------ void vtkReflectionUtilities::ReflectReflectableArrays( std::vector>& reflectableArrays, vtkDataSetAttributes* inData, vtkDataSetAttributes* outData, vtkIdType i, int mirrorDir[3], int mirrorSymmetricTensorDir[6], int mirrorTensorDir[9], vtkIdType id) { // Reflect reflectable arrays for (size_t iReflect = 0; iReflect < reflectableArrays.size(); iReflect++) { vtkDataArray* inArray = nullptr; vtkDataArray* outArray = nullptr; const char* inArrayName = inData->GetArrayName(reflectableArrays[iReflect].first); if (!inArrayName) { inArray = vtkDataArray::SafeDownCast(inData->GetAbstractArray(reflectableArrays[iReflect].first)); outArray = vtkDataArray::SafeDownCast(outData->GetAbstractArray(reflectableArrays[iReflect].first)); } else if (outData->HasArray(inArrayName)) { inArray = vtkDataArray::SafeDownCast(inData->GetAbstractArray(inArrayName)); outArray = vtkDataArray::SafeDownCast(outData->GetAbstractArray(inArrayName)); } else { continue; } if (!outArray) { vtkWarningWithObjectMacro(outData, "An error occured while copying the arrays and the results might be incorrect. Naming " "arrays in the input may fix that issue."); continue; } double tuple[9]; inArray->GetTuple(i, tuple); int nComp = reflectableArrays[iReflect].second; switch (nComp) { case 3: vtkReflectionUtilities::ReflectTuple(tuple, mirrorDir, nComp); break; case 6: vtkReflectionUtilities::ReflectTuple(tuple, mirrorSymmetricTensorDir, nComp); break; case 9: vtkReflectionUtilities::ReflectTuple(tuple, mirrorTensorDir, nComp); break; default: break; } outArray->SetTuple(id, tuple); } } //------------------------------------------------------------------------------ void vtkReflectionUtilities::FindAllReflectableArrays( std::vector>& reflectableArrays, vtkDataSetAttributes* inData, bool reflectAllInputArrays) { if (reflectAllInputArrays) { vtkReflectionUtilities::FindReflectableArrays(inData, reflectableArrays); } else { // Reflect only vectors, normals and tensors vtkDataArray* vectors = inData->GetVectors(); vtkDataArray* normals = inData->GetNormals(); vtkDataArray* tensors = inData->GetTensors(); for (int iArr = 0; iArr < inData->GetNumberOfArrays(); iArr++) { vtkAbstractArray* array = inData->GetAbstractArray(iArr); if (array == vectors || array == normals || array == tensors) { reflectableArrays.emplace_back(iArr, array->GetNumberOfComponents()); } } } } //------------------------------------------------------------------------------ vtkIdType vtkReflectionUtilities::ReflectNon3DCellInternal(vtkDataSet* input, vtkUnstructuredGrid* output, vtkIdType cellId, vtkIdType numInputPoints, bool copyInput) { vtkNew cellPts; input->GetCellPoints(cellId, cellPts); int numCellPts = cellPts->GetNumberOfIds(); std::vector newCellPts(numCellPts); int cellType = input->GetCellType(cellId); switch (cellType) { case VTK_QUADRATIC_EDGE: case VTK_CUBIC_LINE: case VTK_BEZIER_CURVE: case VTK_LAGRANGE_CURVE: { for (int i = 0; i < numCellPts; i++) { newCellPts[i] = cellPts->GetId(i); } break; } case VTK_QUADRATIC_TRIANGLE: { newCellPts[0] = cellPts->GetId(2); newCellPts[1] = cellPts->GetId(1); newCellPts[2] = cellPts->GetId(0); newCellPts[3] = cellPts->GetId(4); newCellPts[4] = cellPts->GetId(3); newCellPts[5] = cellPts->GetId(5); break; } case VTK_PIXEL: { newCellPts[0] = cellPts->GetId(0); newCellPts[2] = cellPts->GetId(1); newCellPts[1] = cellPts->GetId(2); newCellPts[3] = cellPts->GetId(3); break; } case VTK_BEZIER_TRIANGLE: case VTK_LAGRANGE_TRIANGLE: { if (numCellPts == 7) { newCellPts[0] = cellPts->GetId(0); newCellPts[1] = cellPts->GetId(2); newCellPts[2] = cellPts->GetId(1); newCellPts[3] = cellPts->GetId(5); newCellPts[4] = cellPts->GetId(4); newCellPts[5] = cellPts->GetId(3); newCellPts[6] = cellPts->GetId(6); } else { int order = (sqrt(8 * numCellPts + 1) - 3) / 2; int offset = 0; while (order > 0) { newCellPts[offset + 0] = cellPts->GetId(offset + 0); newCellPts[offset + 1] = cellPts->GetId(offset + 2); newCellPts[offset + 2] = cellPts->GetId(offset + 1); const int contourN = 3 * (order - 1); for (int contour = 0; contour < contourN; contour++) { newCellPts[offset + 3 + contour] = cellPts->GetId(offset + 3 + contourN - 1 - contour); } if (order == 3) // This is it, there is a single point in the middle { newCellPts[offset + 3 + contourN] = cellPts->GetId(offset + 3 + contourN); } order -= 3; offset += 3 * order; } } break; } case VTK_QUADRATIC_QUAD: { newCellPts[0] = cellPts->GetId(1); newCellPts[1] = cellPts->GetId(0); newCellPts[2] = cellPts->GetId(3); newCellPts[3] = cellPts->GetId(2); newCellPts[4] = cellPts->GetId(4); newCellPts[5] = cellPts->GetId(7); newCellPts[6] = cellPts->GetId(6); newCellPts[7] = cellPts->GetId(5); break; } case VTK_BIQUADRATIC_QUAD: { newCellPts[0] = cellPts->GetId(1); newCellPts[1] = cellPts->GetId(0); newCellPts[2] = cellPts->GetId(3); newCellPts[3] = cellPts->GetId(2); newCellPts[4] = cellPts->GetId(4); newCellPts[5] = cellPts->GetId(7); newCellPts[6] = cellPts->GetId(6); newCellPts[7] = cellPts->GetId(5); newCellPts[8] = cellPts->GetId(8); break; } case VTK_QUADRATIC_LINEAR_QUAD: { newCellPts[0] = cellPts->GetId(1); newCellPts[1] = cellPts->GetId(0); newCellPts[2] = cellPts->GetId(3); newCellPts[3] = cellPts->GetId(2); newCellPts[4] = cellPts->GetId(4); newCellPts[5] = cellPts->GetId(5); break; } case VTK_BEZIER_QUADRILATERAL: case VTK_LAGRANGE_QUADRILATERAL: { vtkCell* cell = input->GetCell(cellId); vtkHigherOrderQuadrilateral* cellQuad = dynamic_cast(cell); const int* order = cellQuad->GetOrder(); const int iMaxHalf = (order[0] % 2 == 0) ? (order[0] + 2) / 2 : (order[0] + 1) / 2; for (int i = 0; i < iMaxHalf; i++) { const int iReversed = order[0] - i; for (int j = 0; j < order[1] + 1; j++) { const int nodeId = vtkHigherOrderQuadrilateral::PointIndexFromIJK(i, j, order); if (i != iReversed) { const int nodeIdReversed = vtkHigherOrderQuadrilateral::PointIndexFromIJK(iReversed, j, order); newCellPts[nodeIdReversed] = cellPts->GetId(nodeId); newCellPts[nodeId] = cellPts->GetId(nodeIdReversed); } else { newCellPts[nodeId] = cellPts->GetId(nodeId); } } } break; } case VTK_POLY_LINE: for (int j = 0; j != numCellPts; j++) { newCellPts[j] = cellPts->GetId(numCellPts - j - 1); } break; default: { if (input->GetCell(cellId)->IsA("vtkNonLinearCell") || cellType > VTK_POLYHEDRON) { vtkGenericWarningMacro("Cell may be inverted"); } for (int j = 0; j != numCellPts; j++) { // Indexing in this way ensures proper reflection of quad triangulation newCellPts[(numCellPts - j) % numCellPts] = cellPts->GetId(j); } } } // end switch if (copyInput) { for (int j = 0; j < numCellPts; j++) { newCellPts[j] += numInputPoints; } } return output->InsertNextCell(cellType, numCellPts, newCellPts.data()); } //------------------------------------------------------------------------------ void vtkReflectionUtilities::ProcessUnstructuredGrid(vtkDataSet* input, vtkUnstructuredGrid* output, double constant[3], int mirrorDir[3], int mirrorSymmetricTensorDir[6], int mirrorTensorDir[9], bool copyInput, bool reflectAllInputArrays, vtkAlgorithm* algorithm) { vtkPointData* inPD = input->GetPointData(); vtkPointData* outPD = output->GetPointData(); vtkCellData* inCD = input->GetCellData(); vtkCellData* outCD = output->GetCellData(); vtkIdType numPts = input->GetNumberOfPoints(); vtkIdType numCells = input->GetNumberOfCells(); double point[3]; vtkSmartPointer ptIds = vtkSmartPointer::New(); vtkSmartPointer outPoints = vtkSmartPointer::New(); if (copyInput) { outPoints->Allocate(2 * numPts); output->Allocate(numCells * 2); } else { outPoints->Allocate(numPts); output->Allocate(numCells); } outPD->CopyAllOn(); outPD->CopyGlobalIdsOff(); outCD->CopyAllOn(); outCD->CopyGlobalIdsOff(); outPD->CopyAllocate(inPD); outCD->CopyAllocate(inCD); // Copy first points. if (copyInput) { for (vtkIdType i = 0; i < numPts; i++) { input->GetPoint(i, point); outPD->CopyData(inPD, i, outPoints->InsertNextPoint(point)); } } std::vector> reflectableArrays; vtkReflectionUtilities::FindAllReflectableArrays(reflectableArrays, inPD, reflectAllInputArrays); // Copy reflected points. for (vtkIdType i = 0; i < numPts; i++) { if (algorithm->CheckAbort()) { break; } input->GetPoint(i, point); vtkIdType ptId = outPoints->InsertNextPoint(mirrorDir[0] * point[0] + constant[0], mirrorDir[1] * point[1] + constant[1], mirrorDir[2] * point[2] + constant[2]); outPD->CopyData(inPD, i, ptId); vtkReflectionUtilities::ReflectReflectableArrays(reflectableArrays, inPD, outPD, i, mirrorDir, mirrorSymmetricTensorDir, mirrorTensorDir, ptId); } vtkNew cellPts; // Copy original cells. if (copyInput) { for (vtkIdType i = 0; i < numCells; i++) { // special handling for polyhedron cells if (vtkUnstructuredGrid::SafeDownCast(input) && input->GetCellType(i) == VTK_POLYHEDRON) { vtkUnstructuredGrid::SafeDownCast(input)->GetFaceStream(i, ptIds); output->InsertNextCell(VTK_POLYHEDRON, ptIds); } else { input->GetCellPoints(i, ptIds); output->InsertNextCell(input->GetCellType(i), ptIds); } outCD->CopyData(inCD, i, i); } } // Find all reflectable arrays reflectableArrays.clear(); vtkReflectionUtilities::FindAllReflectableArrays(reflectableArrays, inCD, reflectAllInputArrays); // Generate reflected cells. for (vtkIdType i = 0; i < numCells; i++) { if (algorithm->CheckAbort()) { break; } vtkIdType outputCellId = -1; int cellType = input->GetCellType(i); switch (cellType) { case VTK_TRIANGLE_STRIP: { input->GetCellPoints(i, cellPts); int numCellPts = cellPts->GetNumberOfIds(); if (numCellPts % 2 != 0) { vtkReflectionUtilities::ReflectNon3DCellInternal(input, output, i, numPts, copyInput); } else { // Triangle strips with even number of triangles have // to be handled specially. A degenerate triangle is // introduced to reflect all the triangles properly. input->GetCellPoints(i, cellPts); numCellPts++; std::vector newCellPts(numCellPts); vtkIdType pointIdOffset = 0; if (copyInput) { pointIdOffset = numPts; } newCellPts[0] = cellPts->GetId(0) + pointIdOffset; newCellPts[1] = cellPts->GetId(2) + pointIdOffset; newCellPts[2] = cellPts->GetId(1) + pointIdOffset; newCellPts[3] = cellPts->GetId(2) + pointIdOffset; for (int j = 4; j < numCellPts; j++) { newCellPts[j] = cellPts->GetId(j - 1) + pointIdOffset; } outputCellId = output->InsertNextCell(cellType, numCellPts, newCellPts.data()); } break; } case VTK_TETRA: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[4] = { cellPts->GetId(3), cellPts->GetId(1), cellPts->GetId(2), cellPts->GetId(0) }; if (copyInput) { for (int j = 0; j < 4; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 4, newCellPts); break; } case VTK_VOXEL: case VTK_HEXAHEDRON: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[8] = { cellPts->GetId(4), cellPts->GetId(5), cellPts->GetId(6), cellPts->GetId(7), cellPts->GetId(0), cellPts->GetId(1), cellPts->GetId(2), cellPts->GetId(3) }; if (copyInput) { for (int j = 0; j < 8; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 8, newCellPts); break; } case VTK_WEDGE: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[6] = { cellPts->GetId(3), cellPts->GetId(4), cellPts->GetId(5), cellPts->GetId(0), cellPts->GetId(1), cellPts->GetId(2) }; if (copyInput) { for (int j = 0; j < 6; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 6, newCellPts); break; } case VTK_PYRAMID: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[5]; for (int j = 3; j >= 0; j--) { newCellPts[3 - j] = cellPts->GetId(j); if (copyInput) { newCellPts[3 - j] += numPts; } } newCellPts[4] = cellPts->GetId(4); if (copyInput) { newCellPts[4] += numPts; } outputCellId = output->InsertNextCell(cellType, 5, newCellPts); break; } case VTK_PENTAGONAL_PRISM: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[10] = { cellPts->GetId(5), cellPts->GetId(6), cellPts->GetId(7), cellPts->GetId(8), cellPts->GetId(9), cellPts->GetId(0), cellPts->GetId(1), cellPts->GetId(2), cellPts->GetId(3), cellPts->GetId(4) }; if (copyInput) { for (int j = 0; j < 10; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 10, newCellPts); break; } case VTK_HEXAGONAL_PRISM: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[12] = { cellPts->GetId(6), cellPts->GetId(7), cellPts->GetId(8), cellPts->GetId(9), cellPts->GetId(10), cellPts->GetId(11), cellPts->GetId(0), cellPts->GetId(1), cellPts->GetId(2), cellPts->GetId(3), cellPts->GetId(4), cellPts->GetId(5) }; if (copyInput) { for (int j = 0; j < 12; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 12, newCellPts); break; } case VTK_QUADRATIC_TETRA: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[10] = { cellPts->GetId(3), cellPts->GetId(1), cellPts->GetId(2), cellPts->GetId(0), cellPts->GetId(8), cellPts->GetId(5), cellPts->GetId(9), cellPts->GetId(7), cellPts->GetId(4), cellPts->GetId(6) }; if (copyInput) { for (int j = 0; j < 10; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 10, newCellPts); break; } case VTK_QUADRATIC_HEXAHEDRON: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[20] = { cellPts->GetId(4), cellPts->GetId(5), cellPts->GetId(6), cellPts->GetId(7), cellPts->GetId(0), cellPts->GetId(1), cellPts->GetId(2), cellPts->GetId(3), cellPts->GetId(12), cellPts->GetId(13), cellPts->GetId(14), cellPts->GetId(15), cellPts->GetId(8), cellPts->GetId(9), cellPts->GetId(10), cellPts->GetId(11), cellPts->GetId(16), cellPts->GetId(17), cellPts->GetId(18), cellPts->GetId(19) }; if (copyInput) { for (int j = 0; j < 20; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 20, newCellPts); break; } case VTK_QUADRATIC_WEDGE: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[15] = { cellPts->GetId(3), cellPts->GetId(4), cellPts->GetId(5), cellPts->GetId(0), cellPts->GetId(1), cellPts->GetId(2), cellPts->GetId(9), cellPts->GetId(10), cellPts->GetId(11), cellPts->GetId(6), cellPts->GetId(7), cellPts->GetId(8), cellPts->GetId(12), cellPts->GetId(13), cellPts->GetId(14) }; if (copyInput) { for (int j = 0; j < 15; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 15, newCellPts); break; } case VTK_QUADRATIC_PYRAMID: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[13] = { cellPts->GetId(2), cellPts->GetId(1), cellPts->GetId(0), cellPts->GetId(3), cellPts->GetId(4), cellPts->GetId(6), cellPts->GetId(5), cellPts->GetId(8), cellPts->GetId(7), cellPts->GetId(11), cellPts->GetId(10), cellPts->GetId(9), cellPts->GetId(12) }; if (copyInput) { for (int j = 0; j < 13; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 13, newCellPts); break; } case VTK_TRIQUADRATIC_HEXAHEDRON: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[27] = { cellPts->GetId(4), cellPts->GetId(5), cellPts->GetId(6), cellPts->GetId(7), cellPts->GetId(0), cellPts->GetId(1), cellPts->GetId(2), cellPts->GetId(3), cellPts->GetId(12), cellPts->GetId(13), cellPts->GetId(14), cellPts->GetId(15), cellPts->GetId(8), cellPts->GetId(9), cellPts->GetId(10), cellPts->GetId(11), cellPts->GetId(16), cellPts->GetId(17), cellPts->GetId(18), cellPts->GetId(19), cellPts->GetId(20), cellPts->GetId(21), cellPts->GetId(22), cellPts->GetId(23), cellPts->GetId(25), cellPts->GetId(24), cellPts->GetId(26) }; if (copyInput) { for (int j = 0; j < 27; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 27, newCellPts); break; } case VTK_TRIQUADRATIC_PYRAMID: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[19] = { cellPts->GetId(2), cellPts->GetId(1), cellPts->GetId(0), cellPts->GetId(3), cellPts->GetId(4), cellPts->GetId(6), cellPts->GetId(5), cellPts->GetId(8), cellPts->GetId(7), cellPts->GetId(11), cellPts->GetId(10), cellPts->GetId(9), cellPts->GetId(12), cellPts->GetId(13), cellPts->GetId(15), cellPts->GetId(14), cellPts->GetId(17), cellPts->GetId(16), cellPts->GetId(18) }; if (copyInput) { for (int j = 0; j < 19; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 19, newCellPts); break; } case VTK_QUADRATIC_LINEAR_WEDGE: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[12] = { cellPts->GetId(3), cellPts->GetId(4), cellPts->GetId(5), cellPts->GetId(0), cellPts->GetId(1), cellPts->GetId(2), cellPts->GetId(9), cellPts->GetId(10), cellPts->GetId(11), cellPts->GetId(6), cellPts->GetId(7), cellPts->GetId(8) }; if (copyInput) { for (int j = 0; j < 12; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 12, newCellPts); break; } case VTK_BIQUADRATIC_QUADRATIC_WEDGE: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[18] = { cellPts->GetId(3), cellPts->GetId(4), cellPts->GetId(5), cellPts->GetId(0), cellPts->GetId(1), cellPts->GetId(2), cellPts->GetId(9), cellPts->GetId(10), cellPts->GetId(11), cellPts->GetId(6), cellPts->GetId(7), cellPts->GetId(8), cellPts->GetId(12), cellPts->GetId(13), cellPts->GetId(14), cellPts->GetId(15), cellPts->GetId(16), cellPts->GetId(17) }; if (copyInput) { for (int j = 0; j < 18; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 18, newCellPts); break; } case VTK_BIQUADRATIC_QUADRATIC_HEXAHEDRON: { input->GetCellPoints(i, cellPts); vtkIdType newCellPts[24] = { cellPts->GetId(4), cellPts->GetId(5), cellPts->GetId(6), cellPts->GetId(7), cellPts->GetId(0), cellPts->GetId(1), cellPts->GetId(2), cellPts->GetId(3), cellPts->GetId(12), cellPts->GetId(13), cellPts->GetId(14), cellPts->GetId(15), cellPts->GetId(8), cellPts->GetId(9), cellPts->GetId(10), cellPts->GetId(11), cellPts->GetId(16), cellPts->GetId(17), cellPts->GetId(18), cellPts->GetId(19), cellPts->GetId(20), cellPts->GetId(21), cellPts->GetId(22), cellPts->GetId(23) }; if (copyInput) { for (int j = 0; j < 24; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, 24, newCellPts); break; } case VTK_POLYHEDRON: { vtkUnstructuredGrid::SafeDownCast(input)->GetFaceStream(i, cellPts); vtkIdType* idPtr = cellPts->GetPointer(0); int nfaces = static_cast(*idPtr++); for (int j = 0; j < nfaces; j++) { vtkIdType npts = *idPtr++; for (vtkIdType k = 0; k < (npts + 1) / 2; k++) { vtkIdType temp = idPtr[k]; idPtr[k] = idPtr[npts - 1 - k]; idPtr[npts - 1 - k] = temp; } if (copyInput) { for (vtkIdType k = 0; k < npts; k++) { idPtr[k] += numPts; } } idPtr += npts; } outputCellId = output->InsertNextCell(cellType, cellPts); break; } case VTK_BEZIER_HEXAHEDRON: case VTK_LAGRANGE_HEXAHEDRON: { input->GetCellPoints(i, cellPts); const int numCellPts = cellPts->GetNumberOfIds(); std::vector newCellPts(numCellPts); vtkCell* cell = input->GetCell(i); vtkHigherOrderHexahedron* cellHex = dynamic_cast(cell); const int* order = cellHex->GetOrder(); const int kMaxHalf = (order[2] % 2 == 0) ? (order[2] + 2) / 2 : (order[2] + 1) / 2; for (int ii = 0; ii < order[0] + 1; ii++) { for (int jj = 0; jj < order[1] + 1; jj++) { for (int kk = 0; kk < kMaxHalf; kk++) { const int kkReversed = order[2] - kk; const int nodeId = vtkHigherOrderHexahedron::PointIndexFromIJK(ii, jj, kk, order); if (kk != kkReversed) { const int nodeIdReversed = vtkHigherOrderHexahedron::PointIndexFromIJK(ii, jj, kkReversed, order); newCellPts[nodeIdReversed] = cellPts->GetId(nodeId); newCellPts[nodeId] = cellPts->GetId(nodeIdReversed); } else { newCellPts[nodeId] = cellPts->GetId(nodeId); } } } } if (copyInput) { for (int j = 0; j < numCellPts; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, numCellPts, newCellPts.data()); break; } case VTK_BEZIER_WEDGE: case VTK_LAGRANGE_WEDGE: { input->GetCellPoints(i, cellPts); const int numCellPts = cellPts->GetNumberOfIds(); std::vector newCellPts(numCellPts); if (numCellPts == 21) { newCellPts = { cellPts->GetId(3), cellPts->GetId(4), cellPts->GetId(5), cellPts->GetId(0), cellPts->GetId(1), cellPts->GetId(2), cellPts->GetId(9), cellPts->GetId(10), cellPts->GetId(11), cellPts->GetId(6), cellPts->GetId(7), cellPts->GetId(8), cellPts->GetId(12), cellPts->GetId(13), cellPts->GetId(14), cellPts->GetId(16), cellPts->GetId(15), cellPts->GetId(17), cellPts->GetId(18), cellPts->GetId(19), cellPts->GetId(20) }; } else { vtkCell* cell = input->GetCell(i); vtkHigherOrderWedge* cellWedge = dynamic_cast(cell); const int* order = cellWedge->GetOrder(); const int kMaxHalf = (order[2] % 2 == 0) ? (order[2] + 2) / 2 : (order[2] + 1) / 2; for (int ii = 0; ii < order[0] + 1; ii++) { for (int jj = 0; jj < order[0] + 1 - ii; jj++) { for (int kk = 0; kk < kMaxHalf; kk++) { const int kkReversed = order[2] - kk; const int nodeId = vtkHigherOrderWedge::PointIndexFromIJK(ii, jj, kk, order); if (kk != kkReversed) { const int nodeIdReversed = vtkHigherOrderWedge::PointIndexFromIJK(ii, jj, kkReversed, order); newCellPts[nodeIdReversed] = cellPts->GetId(nodeId); newCellPts[nodeId] = cellPts->GetId(nodeIdReversed); } else { newCellPts[nodeId] = cellPts->GetId(nodeId); } } } } } if (copyInput) { for (int j = 0; j < numCellPts; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, numCellPts, newCellPts.data()); break; } case VTK_BEZIER_TETRAHEDRON: case VTK_LAGRANGE_TETRAHEDRON: { input->GetCellPoints(i, cellPts); const int numCellPts = cellPts->GetNumberOfIds(); std::vector newCellPts(numCellPts); if (numCellPts == 15) { newCellPts = { cellPts->GetId(0), cellPts->GetId(2), cellPts->GetId(1), cellPts->GetId(3), cellPts->GetId(6), cellPts->GetId(5), cellPts->GetId(4), cellPts->GetId(7), cellPts->GetId(9), cellPts->GetId(8), cellPts->GetId(10), cellPts->GetId(13), cellPts->GetId(12), cellPts->GetId(11), cellPts->GetId(14) }; } else { const int order = vtkHigherOrderTetra::ComputeOrder(numCellPts); for (int ii = 0; ii < order + 1; ii++) { for (int jj = 0; jj < order + 1 - ii; jj++) { for (int kk = 0; kk < order + 1 - jj; kk++) { for (int ll = 0; ll < order + 1 - kk; ll++) { if ((ii + jj + kk + ll) == order) { const vtkIdType bindex[4]{ ii, jj, kk, ll }; const vtkIdType bindexReversed[4]{ ii, jj, ll, kk }; const vtkIdType nodeId = vtkHigherOrderTetra::Index(bindex, order); const vtkIdType nodeIdReversed = vtkHigherOrderTetra::Index(bindexReversed, order); newCellPts[nodeId] = cellPts->GetId(nodeIdReversed); } } } } } } if (copyInput) { for (int j = 0; j < numCellPts; j++) { newCellPts[j] += numPts; } } outputCellId = output->InsertNextCell(cellType, numCellPts, newCellPts.data()); break; } default: { outputCellId = vtkReflectionUtilities::ReflectNon3DCellInternal(input, output, i, numPts, copyInput); } } outCD->CopyData(inCD, i, outputCellId); vtkReflectionUtilities::ReflectReflectableArrays(reflectableArrays, inCD, outCD, i, mirrorDir, mirrorSymmetricTensorDir, mirrorTensorDir, outputCellId); } output->SetPoints(outPoints); output->CheckAttributes(); } VTK_ABI_NAMESPACE_END