// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkExplicitStructuredGrid.h" #include "vtkCell.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkCellLinks.h" #include "vtkDataSetAttributes.h" #include "vtkEmptyCell.h" #include "vtkGarbageCollector.h" #include "vtkGenericCell.h" #include "vtkHexahedron.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkStaticCellLinks.h" #include "vtkStructuredData.h" #include "vtkUnsignedCharArray.h" #include VTK_ABI_NAMESPACE_BEGIN static constexpr unsigned char MASKED_CELL_VALUE = vtkDataSetAttributes::HIDDENCELL | vtkDataSetAttributes::REFINEDCELL; static int HEXAHEDRON_POINT_MAP[] = { 0, 1, 3, 2, 4, 5, 7, 6, // 1, 0, 2, 3, 5, 4, 6, 7, // 0, 3, 1, 2, 4, 7, 5, 6, // 3, 0, 2, 1, 7, 4, 6, 5, // 0, 4, 1, 5, 2, 6, 3, 7, // 4, 0, 5, 1, 6, 2, 7, 3 // }; static int SWAP_HEXAHEDRON_POINT_MAP[] = { 0, 1, 5, 4, 3, 2, 6, 7, // 0, 4, 7, 3, 1, 5, 6, 2, // 0, 3, 2, 1, 4, 7, 6, 5 // }; static int MIRROR_HEXAHEDRON_POINT_MAP[] = { 1, 0, 3, 2, 5, 4, 7, 6, // 3, 2, 1, 0, 7, 6, 5, 4, // 4, 5, 6, 7, 0, 1, 2, 3 // }; vtkStandardNewMacro(vtkExplicitStructuredGrid); //------------------------------------------------------------------------------ vtkExplicitStructuredGrid::vtkExplicitStructuredGrid() { this->Cells = vtkSmartPointer::New(); this->Cells->UseFixedSizeDefaultStorage(8); this->FacesConnectivityFlagsArrayName = nullptr; int extent[6] = { 0, -1, 0, -1, 0, -1 }; std::copy(this->Extent, this->Extent + 6, extent); this->Information->Set(vtkDataObject::DATA_EXTENT_TYPE(), VTK_3D_EXTENT); this->Information->Set(vtkDataObject::DATA_EXTENT(), this->Extent, 6); } //------------------------------------------------------------------------------ vtkExplicitStructuredGrid::~vtkExplicitStructuredGrid() { this->SetFacesConnectivityFlagsArrayName(nullptr); this->SetCells(nullptr); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::Initialize() { this->Superclass::Initialize(); if (this->Information) { this->SetDimensions(0, 0, 0); } this->SetCells(nullptr); if (this->Links) { this->Links->Initialize(); } } //------------------------------------------------------------------------------ int vtkExplicitStructuredGrid::GetCellType(vtkIdType cellId) { return this->IsCellVisible(cellId) ? VTK_HEXAHEDRON : VTK_EMPTY_CELL; } //------------------------------------------------------------------------------ vtkIdType vtkExplicitStructuredGrid::GetCellSize(vtkIdType cellId) { return this->IsCellVisible(cellId) ? 8 : 0; } //------------------------------------------------------------------------------ vtkIdType vtkExplicitStructuredGrid::GetNumberOfCells() { return vtkStructuredData::GetNumberOfCells(this->Extent); } //------------------------------------------------------------------------------ vtkCell* vtkExplicitStructuredGrid::GetCell(vtkIdType cellId) { this->GetCell(cellId, this->GenericCell); return this->GenericCell->GetRepresentativeCell(); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::GetCell(vtkIdType cellId, vtkGenericCell* cell) { if (!this->IsCellVisible(cellId)) { cell->SetCellTypeToEmptyCell(); return; } cell->SetCellTypeToHexahedron(); this->Cells->GetCellAtId(cellId, cell->PointIds); this->Points->GetPoints(cell->PointIds, cell->Points); } //------------------------------------------------------------------------------ // Support GetCellBounds() namespace { // anonymous struct ComputeCellBoundsVisitor : public vtkCellArray::DispatchUtilities { // vtkCellArray::Visit entry point: template void operator()(OffsetsT* offsets, ConnectivityT* conn, vtkPoints* points, vtkIdType cellId, double bounds[6]) const { const vtkIdType beginOffset = GetBeginOffset(offsets, cellId); const auto pointIds = GetRange(conn).begin() + beginOffset; vtkBoundingBox::ComputeBounds(points, pointIds, 8, bounds); } }; } // anonymous //------------------------------------------------------------------------------ // Fast implementation of GetCellBounds(). // Bounds are calculated without constructing a cell. void vtkExplicitStructuredGrid::GetCellBounds(vtkIdType cellId, double bounds[6]) { if (!this->Points) { vtkErrorMacro(<< "No data"); return; } this->Cells->Dispatch(ComputeCellBoundsVisitor{}, this->Points, cellId, bounds); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::GetPointCells(vtkIdType ptId, vtkIdList* cellIds) { if (!this->Links) { this->BuildLinks(); } cellIds->Reset(); // Use the correct cell links. Use an explicit cast for performance reasons // (virtuals, and templated functions were tested to be slow -- if you make // changes, please make sure to measure performance impacts). vtkIdType numCells, *cells; if (!this->Editable) { vtkStaticCellLinks* links = static_cast(this->Links.Get()); numCells = links->GetNcells(ptId); cells = links->GetCells(ptId); } else { vtkCellLinks* links = static_cast(this->Links.Get()); numCells = links->GetNcells(ptId); cells = links->GetCells(ptId); } cellIds->SetNumberOfIds(numCells); for (auto i = 0; i < numCells; i++) { cellIds->SetId(i, cells[i]); } } //------------------------------------------------------------------------------ vtkIdType* vtkExplicitStructuredGrid::GetCellPoints(vtkIdType cellId) { vtkIdType unused; const vtkIdType* result; this->Cells->GetCellAtId(cellId, unused, result); return const_cast(result); } //------------------------------------------------------------------------------ // Get the points defining a cell. (See vtkDataSet for more info.) void vtkExplicitStructuredGrid::GetCellPoints(vtkIdType cellId, vtkIdList* ptIds) { ptIds->Reset(); ptIds->SetNumberOfIds(8); vtkIdType* indices = this->GetCellPoints(cellId); for (int i = 0; i < 8; i++) { ptIds->SetId(i, indices[i]); } } //------------------------------------------------------------------------------ // Return a pointer to a list of point ids defining cell. // More efficient than alternative method. void vtkExplicitStructuredGrid::GetCellPoints(vtkIdType cellId, vtkIdType& npts, vtkIdType*& pts) { npts = 8; pts = this->GetCellPoints(cellId); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::GetCellPoints( vtkIdType cellId, vtkIdType& npts, vtkIdType const*& pts, vtkIdList* ptIds) { this->Cells->GetCellAtId(cellId, npts, pts, ptIds); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::GetCellNeighbors( vtkIdType cellId, vtkIdType neighbors[6], int* wholeExtent) { int ci, cj, ck; this->ComputeCellStructuredCoords(cellId, ci, cj, ck, true); int* extent = wholeExtent; if (!wholeExtent) { // If the whole extent have not been defined, use own extent extent = new int[6]; this->GetExtent(extent); } int dims[3]; vtkStructuredData::GetDimensionsFromExtent(extent, dims); dims[0]--; dims[1]--; dims[2]--; for (int faceId = 0; faceId < 6; faceId++) { int c[] = { ci - extent[0], cj - extent[2], ck - extent[4] }; c[faceId / 2] += (faceId % 2) ? 1 : -1; bool invalidCellId = (c[0] < 0 || c[1] < 0 || c[2] < 0 || c[0] >= dims[0] || c[1] >= dims[1] || c[2] >= dims[2]); neighbors[faceId] = invalidCellId ? -1 : (c[0] + c[1] * dims[0] + c[2] * dims[0] * dims[1]); } if (!wholeExtent) { delete[] extent; } } namespace { // Identify the neighbors to the specified cell, where the neighbors // use all the points in the points list (pts). template struct GetCellNeighborsImpl : public vtkCellArray::DispatchUtilities { // vtkCellArray::Visit entry point: template void operator()(OffsetsT* offsets, ConnectivityT* conn, TLinks* links, vtkIdType cellId, vtkIdType nPts, const vtkIdType* pts, vtkIdList* cellIds) const { using ValueType = GetAPIType; // Find the shortest linked list auto minPtId = pts[0]; auto minNumCells = links->GetNcells(minPtId); vtkIdType numCells; for (vtkIdType i = 1; i < nPts; ++i) { const auto& ptId = pts[i]; numCells = links->GetNcells(ptId); if (numCells < minNumCells) { minNumCells = numCells; minPtId = ptId; } } const auto minCells = links->GetCells(minPtId); // Now for each cell, see if it contains all the face points // in the facePts list. If so, then this is not a boundary face. const auto connRange = GetRange(conn); const auto offsetsRange = GetRange(offsets); bool match; vtkIdType j; ValueType k; for (vtkIdType i = 0; i < minNumCells; ++i) { const auto& minCellId = minCells[i]; if (minCellId != cellId) // don't include current cell { // get cell points const ValueType nCellPts = offsetsRange[minCellId + 1] - offsetsRange[minCellId]; const auto cellPts = connRange.begin() + offsetsRange[minCellId]; match = true; for (j = 0; j < nPts && match; ++j) // for all pts in input boundary entity { const auto& ptId = pts[j]; if (ptId != minPtId) // of course minPtId is contained by cell { match = false; for (k = 0; k < nCellPts; ++k) // for all points in candidate cell { if (ptId == cellPts[k]) { match = true; // a match was found break; } } // for all points in current cell } // if not guaranteed match } // for all input points if (match) { cellIds->InsertNextId(minCellId); } } // if not the reference cell } // for each cell in minimum linked list } }; } // end anonymous namespace //---------------------------------------------------------------------------- // Return the cells that use all of the ptIds provided. This is a set // (intersection) operation - it can have significant performance impacts on // certain filters like vtkGeometryFilter. void vtkExplicitStructuredGrid::GetCellNeighbors( vtkIdType cellId, vtkIdList* ptIds, vtkIdList* cellIds) { // Empty the list cellIds->Reset(); // Ensure that a proper neighborhood request is made. const vtkIdType npts = ptIds->GetNumberOfIds(); if (npts <= 0) { return; } const vtkIdType* pts = ptIds->GetPointer(0); // Ensure that links are built. if (!this->Links) { this->BuildLinks(); } // Get the cell links based on the current state. if (!this->Editable) { using CellLinksType = vtkStaticCellLinks; using TGetCellNeighbors = GetCellNeighborsImpl; auto links = static_cast(this->Links.Get()); this->Cells->Dispatch(TGetCellNeighbors{}, links, cellId, npts, pts, cellIds); } else { using CellLinksType = vtkCellLinks; using TGetCellNeighbors = GetCellNeighborsImpl; auto links = static_cast(this->Links.Get()); this->Cells->Dispatch(TGetCellNeighbors{}, links, cellId, npts, pts, cellIds); } } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::InternalCopy(vtkExplicitStructuredGrid* src) { // Internal method used for copying specific members this->SetExtent(src->GetExtent()); this->SetFacesConnectivityFlagsArrayName(src->GetFacesConnectivityFlagsArrayName()); } //------------------------------------------------------------------------------ // Copy the topological structure of an input structured grid. void vtkExplicitStructuredGrid::CopyStructure(vtkDataSet* ds) { vtkExplicitStructuredGrid* grid = vtkExplicitStructuredGrid::SafeDownCast(ds); if (!grid) { vtkErrorMacro("Input dataset is not a " << this->GetClassName()); return; } this->Superclass::CopyStructure(ds); this->InternalCopy(grid); this->SetCells(grid->GetCells()); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::ShallowCopy(vtkDataObject* dataObject) { vtkExplicitStructuredGrid* grid = vtkExplicitStructuredGrid::SafeDownCast(dataObject); if (this == grid) { return; } this->Superclass::ShallowCopy(dataObject); if (grid) { this->InternalCopy(grid); this->SetCells(grid->GetCells()); if (grid->Links) { this->Links = vtkSmartPointer::Take(grid->Links->NewInstance()); this->Links->SetDataSet(this); this->Links->ShallowCopy(grid->Links); } else { this->Links = nullptr; } } } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::DeepCopy(vtkDataObject* dataObject) { auto mkhold = vtkMemkindRAII(this->GetIsInMemkind()); vtkExplicitStructuredGrid* grid = vtkExplicitStructuredGrid::SafeDownCast(dataObject); this->Superclass::DeepCopy(dataObject); if (grid) { this->InternalCopy(grid); if (grid->Cells) { this->Cells = vtkSmartPointer::New(); this->Cells->DeepCopy(grid->Cells); } else { this->Cells = nullptr; } if (grid->Links) { this->Links = vtkSmartPointer::Take(grid->Links->NewInstance()); this->Links->SetDataSet(this); this->Links->DeepCopy(grid->Links); } else { this->Links = nullptr; } } } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::SetDimensions(int i, int j, int k) { this->SetExtent(0, i - 1, 0, j - 1, 0, k - 1); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::SetDimensions(int dim[3]) { this->SetDimensions(dim[0], dim[1], dim[2]); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::SetExtent(int x0, int x1, int y0, int y1, int z0, int z1) { this->Extent[0] = x0; this->Extent[1] = x1; this->Extent[2] = y0; this->Extent[3] = y1; this->Extent[4] = z0; this->Extent[5] = z1; if (this->Links) { this->Links->Initialize(); } vtkIdType expectedCells = (this->Extent[1] - this->Extent[0]) * (this->Extent[3] - this->Extent[2]) * (this->Extent[5] - this->Extent[4]); vtkNew cells; cells->UseFixedSize64BitStorage(8); this->SetCells(cells); // Initialize the cell array if (expectedCells > 0) { cells->AllocateEstimate(expectedCells, 8); vtkIdType ids[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; for (vtkIdType i = 0; i < expectedCells; i++) { cells->InsertNextCell(8, ids); } } } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::SetExtent(int extent[6]) { this->SetExtent(extent[0], extent[1], extent[2], extent[3], extent[4], extent[5]); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::BuildLinks() { // Remove the old links if they are already built if (!this->Points) { return; } // Different types of links depending on whether the data can be edited after // initial creation. if (!this->Links) { if (!this->Editable) { this->Links = vtkSmartPointer::New(); } else { this->Links = vtkSmartPointer::New(); static_cast(this->Links.Get())->Allocate(this->GetNumberOfPoints()); } this->Links->SetDataSet(this); } else if (this->Points->GetMTime() > this->Links->GetMTime()) { this->Links->SetDataSet(this); } this->Links->BuildLinks(); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::GenerateGhostArray(int zeroExt[6], bool vtkNotUsed(cellOnly)) { int extent[6]; this->Information->Get(vtkDataObject::DATA_EXTENT(), extent); this->AllocateCellGhostArray(); this->AllocatePointGhostArray(); bool sameExtent = true; for (int i = 0; i < 6; i++) { if (extent[i] != zeroExt[i]) { sameExtent = false; break; } } if (sameExtent) { return; } vtkUnsignedCharArray* ghostCells = this->GetCellGhostArray(); vtkIdType index = 0; // Loop through the cells in this image. // Cells may be 2d or 1d ... Treat all as 3D if (extent[0] == extent[1]) { ++extent[1]; ++zeroExt[1]; } if (extent[2] == extent[3]) { ++extent[3]; ++zeroExt[3]; } if (extent[4] == extent[5]) { ++extent[5]; ++zeroExt[5]; } // Loop for (int k = extent[4]; k < extent[5]; ++k) { // Determine the Manhattan distances to zero extent. int dk = 0; if (k < zeroExt[4]) { dk = zeroExt[4] - k; } if (k >= zeroExt[5]) { dk = k - zeroExt[5] + 1; } for (int j = extent[2]; j < extent[3]; ++j) { int dj = 0; if (j < zeroExt[2]) { dj = zeroExt[2] - j; } if (j >= zeroExt[3]) { dj = j - zeroExt[3] + 1; } for (int i = extent[0]; i < extent[1]; ++i) { int di = 0; if (i < zeroExt[0]) { di = zeroExt[0] - i; } if (i >= zeroExt[1]) { di = i - zeroExt[1] + 1; } // Compute Manhattan distance. int dist = di; dist = std::max(dj, dist); dist = std::max(dk, dist); unsigned char value = ghostCells->GetValue(index); if (dist > 0) { value |= vtkDataSetAttributes::DUPLICATECELL; } ghostCells->SetValue(index, value); index++; } } } } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::ComputeFacesConnectivityFlagsArray() { vtkIdType nbCells = this->GetNumberOfCells(); const char* name = this->FacesConnectivityFlagsArrayName ? this->FacesConnectivityFlagsArrayName : "ConnectivityFlags"; this->SetFacesConnectivityFlagsArrayName(name); vtkNew connectivity; connectivity->SetName(name); connectivity->SetNumberOfComponents(1); connectivity->SetNumberOfTuples(nbCells); this->GetCellData()->AddArray(connectivity.GetPointer()); for (vtkIdType c = 0; c < nbCells; c++) { vtkIdType* cellPtsIds = this->GetCellPoints(c); unsigned char mask = 0; vtkIdType neighbors[6]; this->GetCellNeighbors(c, neighbors); for (int f = 0, n = 0; f < 6; f++, n += 8) { vtkIdType neighbor = neighbors[f]; if (neighbor >= 0) { vtkIdType* neiCellPtsIds = this->GetCellPoints(neighbor); if (cellPtsIds[HEXAHEDRON_POINT_MAP[n + 0]] == neiCellPtsIds[HEXAHEDRON_POINT_MAP[n + 1]] && cellPtsIds[HEXAHEDRON_POINT_MAP[n + 2]] == neiCellPtsIds[HEXAHEDRON_POINT_MAP[n + 3]] && cellPtsIds[HEXAHEDRON_POINT_MAP[n + 4]] == neiCellPtsIds[HEXAHEDRON_POINT_MAP[n + 5]] && cellPtsIds[HEXAHEDRON_POINT_MAP[n + 6]] == neiCellPtsIds[HEXAHEDRON_POINT_MAP[n + 7]]) { mask |= (1 << f); } } } connectivity->SetValue(c, mask); } } //------------------------------------------------------------------------------ bool vtkExplicitStructuredGrid::HasAnyBlankCells() { return this->CellData->HasAnyGhostBitSet(vtkDataSetAttributes::HIDDENCELL); } //------------------------------------------------------------------------------ // Turn off a particular data cell. void vtkExplicitStructuredGrid::BlankCell(vtkIdType cellId) { vtkUnsignedCharArray* ghosts = this->GetCellGhostArray(); if (!ghosts) { ghosts = this->AllocateCellGhostArray(); } ghosts->SetValue(cellId, ghosts->GetValue(cellId) | vtkDataSetAttributes::HIDDENCELL); assert(!this->IsCellVisible(cellId)); } //------------------------------------------------------------------------------ // Turn on a particular data cell. void vtkExplicitStructuredGrid::UnBlankCell(vtkIdType cellId) { vtkUnsignedCharArray* ghosts = this->GetCellGhostArray(); if (ghosts) { ghosts->SetValue(cellId, ghosts->GetValue(cellId) & ~vtkDataSetAttributes::HIDDENCELL); } } //------------------------------------------------------------------------------ // Return non-zero if the specified cell is visible (i.e., not blanked) unsigned char vtkExplicitStructuredGrid::IsCellVisible(vtkIdType cellId) { vtkUnsignedCharArray* ghosts = this->GetCellGhostArray(); return (ghosts && (ghosts->GetValue(cellId) & MASKED_CELL_VALUE)) ? 0 : 1; } //------------------------------------------------------------------------------ // Return non-zero if the specified cell is a ghost cell unsigned char vtkExplicitStructuredGrid::IsCellGhost(vtkIdType cellId) { vtkUnsignedCharArray* ghosts = this->GetCellGhostArray(); return (ghosts && (ghosts->GetValue(cellId) & vtkDataSetAttributes::DUPLICATECELL)) ? 1 : 0; } //------------------------------------------------------------------------------ bool vtkExplicitStructuredGrid::HasAnyGhostCells() { return this->CellData->HasAnyGhostBitSet(vtkDataSetAttributes::DUPLICATECELL); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::Crop(const int* updateExtent) { this->Crop(this, updateExtent, false); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::Crop( vtkExplicitStructuredGrid* input, const int* updateExtent, bool generateOriginalCellIds) { // The old extent int oldExtent[6]; input->GetExtent(oldExtent); if (updateExtent[1] < updateExtent[0] || updateExtent[3] < updateExtent[2] || updateExtent[5] < updateExtent[4]) { return; } // The new extent int newExtent[6]; for (int i = 0; i < 3; ++i) { newExtent[i * 2] = updateExtent[i * 2]; newExtent[i * 2] = std::max(newExtent[i * 2], oldExtent[i * 2]); newExtent[i * 2 + 1] = updateExtent[i * 2 + 1]; newExtent[i * 2 + 1] = std::min(newExtent[i * 2 + 1], oldExtent[i * 2 + 1]); if (newExtent[i * 2] == newExtent[i * 2 + 1]) { if (newExtent[i * 2 + 1] == oldExtent[i * 2 + 1]) { newExtent[i * 2] -= 1; } else { newExtent[i * 2 + 1] += 1; } } } // If extents already match, then we don't need to do anything. if (oldExtent[0] == newExtent[0] && oldExtent[1] == newExtent[1] && oldExtent[2] == newExtent[2] && oldExtent[3] == newExtent[3] && oldExtent[4] == newExtent[4] && oldExtent[5] == newExtent[5]) { if (this != input) { this->ShallowCopy(input); } if (generateOriginalCellIds) { // CellArray which links the new cells ids with the old ones vtkNew originalCellIds; originalCellIds->SetName("vtkOriginalCellIds"); originalCellIds->SetNumberOfComponents(1); this->GetCellData()->AddArray(originalCellIds.GetPointer()); vtkIdType inSize = this->GetNumberOfCells(); originalCellIds->Allocate(inSize); for (vtkIdType i = 0; i < inSize; i++) { originalCellIds->InsertValue(i, i); } } } else { // Check the points to avoid empty data objects. if (!input->GetPoints()) { return; } // shallow copy points and point data to this ESG this->SetPoints(input->GetPoints()); this->GetPointData()->ShallowCopy(input->GetPointData()); vtkDebugMacro("Cropping Explicit Structured Grid"); // Compute cells extent int oldCellExtent[6], newCellExtent[6]; vtkStructuredData::GetCellExtentFromPointExtent(oldExtent, oldCellExtent); vtkStructuredData::GetCellExtentFromPointExtent(newExtent, newCellExtent); // Allocate necessary objects int outSize = (newCellExtent[1] - newCellExtent[0] + 1) * (newCellExtent[3] - newCellExtent[2] + 1) * (newCellExtent[5] - newCellExtent[4] + 1); this->SetExtent(newExtent); vtkCellData* inCD = input->GetCellData(); vtkCellData* outCD = this->GetCellData(); outCD->CopyAllocate(inCD, outSize, outSize); vtkNew cells; cells->UseFixedSize64BitStorage(8); cells->AllocateEstimate(outSize, 8); // CellArray which links the new cells ids with the old ones vtkNew originalCellIds; if (generateOriginalCellIds) { originalCellIds->SetName("vtkOriginalCellIds"); originalCellIds->SetNumberOfComponents(1); originalCellIds->Allocate(outSize); } // Browse input data and copy cell attributes to output for (int k = newCellExtent[4]; k <= newCellExtent[5]; ++k) { for (int j = newCellExtent[2]; j <= newCellExtent[3]; ++j) { for (int i = newCellExtent[0]; i <= newCellExtent[1]; ++i) { int idx = input->ComputeCellId(i, j, k); vtkNew ptIds; input->GetCellPoints(idx, ptIds); // insert cell and copy cell data vtkIdType nCellId = cells->InsertNextCell(ptIds); outCD->CopyData(inCD, idx, nCellId); if (generateOriginalCellIds) { originalCellIds->InsertValue(nCellId, idx); } } } } if (generateOriginalCellIds) { outCD->AddArray(originalCellIds); originalCellIds->Squeeze(); } cells->Squeeze(); this->SetCells(cells); if (this->GetLinks()) { this->BuildLinks(); } this->ComputeFacesConnectivityFlagsArray(); } } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::ReportReferences(vtkGarbageCollector* collector) { this->Superclass::ReportReferences(collector); vtkGarbageCollectorReport(collector, this->Links, "Links"); } //------------------------------------------------------------------------------ unsigned long vtkExplicitStructuredGrid::GetActualMemorySize() { unsigned long size = this->Superclass::GetActualMemorySize(); if (this->Cells) { size += this->Cells->GetActualMemorySize(); } if (this->Links) { size += this->Links->GetActualMemorySize(); } return size; } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); int dim[3]; this->GetDimensions(dim); os << indent << "Dimensions: (" << dim[0] << ", " << dim[1] << ", " << dim[2] << ")\n"; os << indent << "Extent: (" << this->Extent[0] << ", " << this->Extent[1] << ", " << this->Extent[2] << ", " << this->Extent[3] << ", " << this->Extent[4] << ", " << this->Extent[5] << ")\n"; } //------------------------------------------------------------------------------ // Override this method because of blanking void vtkExplicitStructuredGrid::ComputeScalarRange() { if (this->GetMTime() > this->ScalarRangeComputeTime) { vtkDataArray* ptScalars = this->PointData->GetScalars(); vtkDataArray* cellScalars = this->CellData->GetScalars(); double ptRange[2]; ptRange[0] = VTK_DOUBLE_MAX; ptRange[1] = VTK_DOUBLE_MIN; if (ptScalars) { int num = this->GetNumberOfPoints(); for (int id = 0; id < num; id++) { double s = ptScalars->GetComponent(id, 0); ptRange[0] = std::min(s, ptRange[0]); ptRange[1] = std::max(s, ptRange[1]); } } double cellRange[2]; cellRange[0] = ptRange[0]; cellRange[1] = ptRange[1]; if (cellScalars) { int num = this->GetNumberOfCells(); for (int id = 0; id < num; id++) { double s = cellScalars->GetComponent(id, 0); cellRange[0] = std::min(s, cellRange[0]); cellRange[1] = std::max(s, cellRange[1]); } } this->ScalarRange[0] = (cellRange[0] >= VTK_DOUBLE_MAX ? 0.0 : cellRange[0]); this->ScalarRange[1] = (cellRange[1] <= VTK_DOUBLE_MIN ? 1.0 : cellRange[1]); this->ScalarRangeComputeTime.Modified(); } } //------------------------------------------------------------------------------ vtkExplicitStructuredGrid* vtkExplicitStructuredGrid::GetData(vtkInformation* info) { return info ? vtkExplicitStructuredGrid::SafeDownCast(info->Get(DATA_OBJECT())) : nullptr; } //------------------------------------------------------------------------------ vtkExplicitStructuredGrid* vtkExplicitStructuredGrid::GetData(vtkInformationVector* v, int i) { return vtkExplicitStructuredGrid::GetData(v->GetInformationObject(i)); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::CheckAndReorderFaces() { // Check faces are on the correct axis this->InternalCheckAndReorderFaces(true); // Check if faces are mirrored or not this->InternalCheckAndReorderFaces(false); } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::InternalCheckAndReorderFaces(bool swapFlag) { // Find connected faces int foundFaces[3] = { -1, -1, -1 }; this->FindConnectedFaces(foundFaces); // Compute correcting transformation int* ptsMap; int transformFlag[3] = { 0, 0, 0 }; if (swapFlag) { vtkExplicitStructuredGrid::ComputeSwapFlag(foundFaces, transformFlag); ptsMap = SWAP_HEXAHEDRON_POINT_MAP; } else { vtkExplicitStructuredGrid::ComputeMirrorFlag(foundFaces, transformFlag); ptsMap = MIRROR_HEXAHEDRON_POINT_MAP; } // Reorder cell points accordingly this->ReorderCellsPoints(ptsMap, transformFlag); } //------------------------------------------------------------------------------ int vtkExplicitStructuredGrid::FindConnectedFaces(int foundFaces[3]) { int extent[6]; this->GetExtent(extent); int nFoundFaces = 0; int neiAxisMod[3] = { 0, 0, 0 }; vtkIdType ijkId[3]; vtkIdType id0, neiCellId; vtkIdType* cellPtsIds; vtkIdType* neiCellPtsIds; // Look for continuous connected visible cells for each axis in the whole dataset // And identify connected faces for (ijkId[0] = extent[0]; ijkId[0] < extent[1]; ijkId[0]++) { for (ijkId[1] = extent[2]; ijkId[1] < extent[3]; ijkId[1]++) { for (ijkId[2] = extent[4]; ijkId[2] < extent[5]; ijkId[2]++) { id0 = this->ComputeCellId(ijkId[0], ijkId[1], ijkId[2]); if (this->IsCellVisible(id0)) { for (int axis = 0; axis < 3; axis++) { // A visible cell have been found if (foundFaces[axis] == -1 && ijkId[axis] + 1 < extent[axis * 2 + 1]) { neiAxisMod[axis]++; // find it's neighbour in the current axis neiCellId = this->ComputeCellId( ijkId[0] + neiAxisMod[0], ijkId[1] + neiAxisMod[1], ijkId[2] + neiAxisMod[2]); if (this->IsCellVisible(neiCellId)) { // Find if they are connected and by which faces they are connected cellPtsIds = this->GetCellPoints(id0); neiCellPtsIds = this->GetCellPoints(neiCellId); for (int n = 0; n < 6; n++) { if (cellPtsIds[HEXAHEDRON_POINT_MAP[n * 8 + 0]] == neiCellPtsIds[HEXAHEDRON_POINT_MAP[n * 8 + 1]] && cellPtsIds[HEXAHEDRON_POINT_MAP[n * 8 + 2]] == neiCellPtsIds[HEXAHEDRON_POINT_MAP[n * 8 + 3]] && cellPtsIds[HEXAHEDRON_POINT_MAP[n * 8 + 4]] == neiCellPtsIds[HEXAHEDRON_POINT_MAP[n * 8 + 5]] && cellPtsIds[HEXAHEDRON_POINT_MAP[n * 8 + 6]] == neiCellPtsIds[HEXAHEDRON_POINT_MAP[n * 8 + 7]]) { // Correctly ordered faces would be the following // Axis 0 -> face 1 // Axis 1 -> face 3 // Axis 2 -> face 5 // See vtkHexahedron.h for doc foundFaces[axis] = n; nFoundFaces++; break; } } } neiAxisMod[axis]--; } } } } } } vtkExplicitStructuredGrid::CheckConnectedFaces(nFoundFaces, foundFaces); return nFoundFaces; } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::CheckConnectedFaces(int& nFoundFaces, int foundFaces[3]) { // Check foundFaces coherence and extrapolate to find a missing faces if any switch (nFoundFaces) { case 1: // Only one face have been found, we will probably draw incorrect interior faces for (int axis = 0; axis < 3; axis++) { int foundFace = foundFaces[axis]; // Check if the foundFace point to another axis if (foundFace != -1 && !(foundFace == 2 * axis) && !(foundFace == 2 * axis + 1)) { // A single foundFace which changes face on multiple axis is incoherent and can't be // extrapolated from so we remove it. This means that incorrect interior faces will be // drawn. foundFaces[axis] = -1; nFoundFaces--; } } break; case 2: { // Two faces have been found, we can try to extapolate the last one int missingFaceAxis = -1; for (int axis = 0; axis < 3; axis++) { if (foundFaces[axis] == -1) { // Identify the axis missing a face missingFaceAxis = axis; break; } } int foundFaceAxisSum = 0; int faceSwitch = 1; for (int axis = 0; axis < 3; axis++) { if (axis != missingFaceAxis) { int foundFace = foundFaces[axis]; int foundFaceAxis = static_cast(std::floor((static_cast(foundFace)) / 2.0)); // The sum of the found face axis will always be 3, so compute the sum foundFaceAxisSum += foundFaceAxis; if (!(foundFace == 2 * axis) && !(foundFace == 2 * axis + 1)) { // when switching axis, we still need to know if there is some mirroring // this identify mirroring faceSwitch = foundFace - foundFaceAxis * 2; } } } // Compute the actual missing face foundFaces[missingFaceAxis] = (3 - foundFaceAxisSum) * 2 + faceSwitch; nFoundFaces++; } break; default: break; } } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::ComputeSwapFlag(int foundFaces[3], int swap[3]) { int permuWise = 1; for (int axis = 0; axis < 3; axis++) { int foundFace = foundFaces[axis]; if (foundFace != -1) { int foundFaceAxis = static_cast(std::floor((static_cast(foundFace)) / 2.0)); if (foundFaceAxis != axis) { // Compute the swap swap[3 - foundFaceAxis - axis] = true; if (axis - foundFaceAxis == 1) { // In case of permutation, we need to know in which order the permutation have been done permuWise = 0; } } } } // Manage the permutation case if (swap[0] && swap[1] && swap[2]) { swap[1 + permuWise] = false; } } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::ComputeMirrorFlag(int foundFaces[3], int mirror[3]) { for (int axis = 0; axis < 3; axis++) { int foundFace = foundFaces[axis]; if (foundFace != -1) { if (foundFace % 2 == 0) { mirror[axis] = true; } } } } //------------------------------------------------------------------------------ void vtkExplicitStructuredGrid::ReorderCellsPoints(const int* ptsMap, const int transformFlag[3]) { // Reorder all cells if necessary vtkIdType ids[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; vtkIdType ids2[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; vtkIdType npts, *pts, *ptsTmp, *ptsTmp2; vtkCellArray* cells = this->GetCells(); for (vtkIdType cellId = 0; cellId < this->GetNumberOfCells(); cellId++) { if (this->IsCellVisible(cellId)) { this->GetCellPoints(cellId, npts, pts); for (int ptIdx = 0; ptIdx < 8; ptIdx++) { ids[ptIdx] = pts[ptIdx]; } ptsTmp = ids; ptsTmp2 = ids2; for (int axis = 0; axis < 3; axis++) { if (transformFlag[axis]) { for (int ptIdx = 0; ptIdx < 8; ptIdx++) { ptsTmp2[ptIdx] = ptsTmp[ptsMap[axis * 8 + ptIdx]]; } std::swap(ptsTmp, ptsTmp2); } } cells->ReplaceCellAtId(cellId, 8, ptsTmp); this->GetCellPoints(cellId, npts, pts); } } } VTK_ABI_NAMESPACE_END