// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkCartesianGrid.h" #include "vtkCell.h" #include "vtkCellData.h" #include "vtkCellType.h" #include "vtkConstantArray.h" #include "vtkDataSetAttributes.h" #include "vtkGenericCell.h" #include "vtkInformation.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkStructuredCellArray.h" #include "vtkStructuredPointArray.h" #include "vtkUnsignedCharArray.h" VTK_ABI_NAMESPACE_BEGIN vtkCxxSetSmartPointerMacro(vtkCartesianGrid, StructuredPoints, vtkPoints); //------------------------------------------------------------------------------ namespace { class CellVisibility { public: CellVisibility(vtkCartesianGrid* input) : Input(input) { } bool operator()(const vtkIdType id) { return !Input->IsCellVisible(id); } private: vtkCartesianGrid* Input; }; } // anonymous namespace //------------------------------------------------------------------------------ vtkCartesianGrid::vtkCartesianGrid() { this->Information->Set(vtkDataObject::DATA_EXTENT_TYPE(), VTK_3D_EXTENT); this->Information->Set(vtkDataObject::DATA_EXTENT(), this->Extent, 6); } //------------------------------------------------------------------------------ void vtkCartesianGrid::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "DataDescription: " << this->DataDescription << "\n"; const int* dims = this->Dimensions; os << indent << "Dimensions: (" << dims[0] << ", " << dims[1] << ", " << dims[2] << ")\n"; const int* extent = this->Extent; os << indent << "Extent: (" << extent[0]; for (int idx = 1; idx < 6; ++idx) { os << ", " << extent[idx]; } os << ")\n"; } //------------------------------------------------------------------------------ void vtkCartesianGrid::ShallowCopy(vtkDataObject* dataObject) { vtkCartesianGrid* grid = vtkCartesianGrid::SafeDownCast(dataObject); if (grid) { // set extent sets, extent, dimensions, and data description this->SetExtent(grid->Extent); } // Do superclass this->Superclass::ShallowCopy(dataObject); } //------------------------------------------------------------------------------ void vtkCartesianGrid::DeepCopy(vtkDataObject* dataObject) { vtkCartesianGrid* grid = vtkCartesianGrid::SafeDownCast(dataObject); if (grid) { // set extent sets, extent, dimensions, and data description this->SetExtent(grid->Extent); } // Do superclass this->Superclass::DeepCopy(dataObject); } //------------------------------------------------------------------------------ void vtkCartesianGrid::CopyStructure(vtkDataSet* ds) { vtkCartesianGrid* cg = vtkCartesianGrid::SafeDownCast(ds); this->SetExtent(cg->Extent); } //------------------------------------------------------------------------------ vtkPoints* vtkCartesianGrid::GetPoints() { if (this->StructuredPoints == nullptr) { this->BuildPoints(); } return this->StructuredPoints.Get(); } //------------------------------------------------------------------------------ void vtkCartesianGrid::GetPoint(vtkIdType ptId, double x[3]) { vtkPoints* points = this->GetPoints(); static_cast*>(points->GetData())->GetTypedTuple(ptId, x); } //------------------------------------------------------------------------------ int vtkCartesianGrid::GetCellType(vtkIdType cellId) { // see whether the cell is blanked return this->IsCellVisible(cellId) ? static_cast(this->StructuredCellTypes->GetValue(cellId)) : VTK_EMPTY_CELL; } //------------------------------------------------------------------------------ vtkIdType vtkCartesianGrid::GetCellSize(vtkIdType cellId) { // see whether the cell is blanked return this->IsCellVisible(cellId) ? this->StructuredCells->GetCellSize(cellId) : 0; } //------------------------------------------------------------------------------ void vtkCartesianGrid::GetCellPoints(vtkIdType cellId, vtkIdType& npts, vtkIdType const*& pts, vtkIdList* ptIds) VTK_SIZEHINT(pts, npts) { this->StructuredCells->GetCellAtId(cellId, npts, pts, ptIds); } //------------------------------------------------------------------------------ void vtkCartesianGrid::GetCellPoints(vtkIdType cellId, vtkIdList* ptIds) { this->StructuredCells->GetCellAtId(cellId, ptIds); } //------------------------------------------------------------------------------ vtkIdType vtkCartesianGrid::FindCell(double x[3], vtkCell* vtkNotUsed(cell), vtkGenericCell* vtkNotUsed(gencell), vtkIdType vtkNotUsed(cellId), double tol2, int& subId, double pcoords[3], double* weights) { return this->FindCell(x, nullptr, 0, tol2, subId, pcoords, weights); } //------------------------------------------------------------------------------ vtkCell* vtkCartesianGrid::FindAndGetCell(double x[3], vtkCell* vtkNotUsed(cell), vtkIdType vtkNotUsed(cellId), double tol2, int& subId, double pcoords[3], double* weights) { const vtkIdType cellId = this->FindCell(x, nullptr, 0, tol2, subId, pcoords, nullptr); if (cellId < 0) { return nullptr; } vtkCell* cell = this->GetCell(cellId); cell->InterpolateFunctions(pcoords, weights); return cell; } //------------------------------------------------------------------------------ void vtkCartesianGrid::GetCellNeighbors(vtkIdType cellId, vtkIdList* ptIds, vtkIdList* cellIds) { this->GetCellNeighbors(cellId, ptIds, cellIds, nullptr); } //------------------------------------------------------------------------------ vtkCell* vtkCartesianGrid::GetCell(vtkIdType cellId) { this->GetCell(cellId, this->GenericCell); return this->GenericCell->GetRepresentativeCell(); } //------------------------------------------------------------------------------ vtkCell* vtkCartesianGrid::GetCell(int iMin, int jMin, int kMin) { int ijkMin[3] = { iMin, jMin, kMin }; const auto cellId = vtkStructuredData::ComputeCellId(this->Dimensions, ijkMin); return this->GetCell(cellId); } //------------------------------------------------------------------------------ bool vtkCartesianGrid::HasAnyBlankPoints() { return this->PointData->HasAnyGhostBitSet(vtkDataSetAttributes::HIDDENPOINT); } //------------------------------------------------------------------------------ bool vtkCartesianGrid::HasAnyBlankCells() { int cellBlanking = this->CellData->HasAnyGhostBitSet(vtkDataSetAttributes::HIDDENCELL); return cellBlanking || this->HasAnyBlankPoints(); } //------------------------------------------------------------------------------ void vtkCartesianGrid::Initialize() { this->Superclass::Initialize(); if (this->Information) { this->SetDimensions(0, 0, 0); } } //------------------------------------------------------------------------------ void vtkCartesianGrid::GetCellNeighbors( vtkIdType cellId, vtkIdList* ptIds, vtkIdList* cellIds, int* seedLoc) { int numPtIds = ptIds->GetNumberOfIds(); // Use special methods for speed switch (numPtIds) { case 0: cellIds->Reset(); return; case 1: case 2: case 4: // vertex, edge, face neighbors seedLoc ? vtkStructuredData::GetCellNeighbors( cellId, ptIds, cellIds, this->GetDimensions(), seedLoc) : vtkStructuredData::GetCellNeighbors(cellId, ptIds, cellIds, this->GetDimensions()); break; default: this->Superclass::GetCellNeighbors(cellId, ptIds, cellIds); } // If blanking, remove blanked cells. if (this->GetPointGhostArray() || this->GetCellGhostArray()) { vtkIdType* pCellIds = cellIds->GetPointer(0); vtkIdType* end = std::remove_if(pCellIds, pCellIds + cellIds->GetNumberOfIds(), CellVisibility(this)); cellIds->Resize(std::distance(pCellIds, end)); } } //------------------------------------------------------------------------------ vtkStructuredCellArray* vtkCartesianGrid::GetCells() { return this->StructuredCells; } //------------------------------------------------------------------------------ vtkConstantArray* vtkCartesianGrid::GetCellTypes() { return this->StructuredCellTypes; } //------------------------------------------------------------------------------ vtkConstantArray* vtkCartesianGrid::GetCellTypesArray() { if (!this->LegacyStructuredCellTypes) { this->LegacyStructuredCellTypes = vtkSmartPointer>::New(); this->LegacyStructuredCellTypes->ConstructBackend( static_cast(this->StructuredCellTypes->GetBackend()->Value)); this->LegacyStructuredCellTypes->SetNumberOfComponents(1); this->LegacyStructuredCellTypes->SetNumberOfTuples( this->StructuredCellTypes->GetNumberOfTuples()); } return this->LegacyStructuredCellTypes; } //------------------------------------------------------------------------------ void vtkCartesianGrid::GetCellDims(int cellDims[3]) { for (int i = 0; i < 3; ++i) { cellDims[i] = ((this->Dimensions[i] - 1) < 1) ? 1 : this->Dimensions[i] - 1; } } //------------------------------------------------------------------------------ // Turn off a particular data point. void vtkCartesianGrid::BlankPoint(vtkIdType ptId) { vtkUnsignedCharArray* ghosts = this->GetPointGhostArray(); if (!ghosts) { this->AllocatePointGhostArray(); ghosts = this->GetPointGhostArray(); } ghosts->SetValue(ptId, ghosts->GetValue(ptId) | vtkDataSetAttributes::HIDDENPOINT); assert(!this->IsPointVisible(ptId)); } //------------------------------------------------------------------------------ void vtkCartesianGrid::BlankPoint(int i, int j, int k) { int ijk[3] = { i, j, k }; const int idx = vtkStructuredData::ComputePointId(this->GetDimensions(), ijk); this->BlankPoint(idx); } //------------------------------------------------------------------------------ // Turn on a particular data point. void vtkCartesianGrid::UnBlankPoint(vtkIdType ptId) { vtkUnsignedCharArray* ghosts = this->GetPointGhostArray(); if (!ghosts) { return; } ghosts->SetValue(ptId, ghosts->GetValue(ptId) & ~vtkDataSetAttributes::HIDDENPOINT); } //------------------------------------------------------------------------------ void vtkCartesianGrid::UnBlankPoint(int i, int j, int k) { int ijk[3] = { i, j, k }; const int idx = vtkStructuredData::ComputePointId(this->GetDimensions(), ijk); this->UnBlankPoint(idx); } //------------------------------------------------------------------------------ // Turn off a particular data cell. void vtkCartesianGrid::BlankCell(vtkIdType cellId) { vtkUnsignedCharArray* ghost = this->GetCellGhostArray(); if (!ghost) { this->AllocateCellGhostArray(); ghost = this->GetCellGhostArray(); } ghost->SetValue(cellId, ghost->GetValue(cellId) | vtkDataSetAttributes::HIDDENCELL); assert(!this->IsCellVisible(cellId)); } //------------------------------------------------------------------------------ void vtkCartesianGrid::BlankCell(int i, int j, int k) { int ijk[3] = { i, j, k }; const int idx = vtkStructuredData::ComputeCellId(this->GetDimensions(), ijk); assert("cell id in range:" && ((idx >= 0) && (idx < this->GetNumberOfCells()))); this->BlankCell(idx); } //------------------------------------------------------------------------------ // Turn on a particular data cell. void vtkCartesianGrid::UnBlankCell(vtkIdType cellId) { vtkUnsignedCharArray* ghosts = this->GetCellGhostArray(); if (!ghosts) { return; } ghosts->SetValue(cellId, ghosts->GetValue(cellId) & ~vtkDataSetAttributes::HIDDENCELL); assert(this->IsCellVisible(cellId)); } //------------------------------------------------------------------------------ void vtkCartesianGrid::UnBlankCell(int i, int j, int k) { int ijk[3] = { i, j, k }; const int idx = vtkStructuredData::ComputeCellId(this->GetDimensions(), ijk); assert("cell id in range:" && ((idx >= 0) && (idx < this->GetNumberOfCells()))); this->UnBlankCell(idx); } //------------------------------------------------------------------------------ unsigned char vtkCartesianGrid::IsPointVisible(vtkIdType pointId) { return vtkStructuredData::IsPointVisible(pointId, this->GetPointGhostArray()); } //------------------------------------------------------------------------------ // Return non-zero if the specified cell is visible (i.e., not blanked) unsigned char vtkCartesianGrid::IsCellVisible(vtkIdType cellId) { return vtkStructuredData::IsCellVisible(cellId, this->GetDimensions(), this->GetDataDescription(), this->GetCellGhostArray(), this->GetPointGhostArray()); } //------------------------------------------------------------------------------ int* vtkCartesianGrid::GetDimensions() { this->GetDimensions(this->Dimensions); return this->Dimensions; } //------------------------------------------------------------------------------ void vtkCartesianGrid::GetDimensions(int* dOut) { const int* extent = this->Extent; dOut[0] = extent[1] - extent[0] + 1; dOut[1] = extent[3] - extent[2] + 1; dOut[2] = extent[5] - extent[4] + 1; } #if VTK_ID_TYPE_IMPL != VTK_INT //------------------------------------------------------------------------------ void vtkCartesianGrid::GetDimensions(vtkIdType dims[3]) { // Use vtkIdType to avoid overflow on large images const int* extent = this->Extent; dims[0] = extent[1] - extent[0] + 1; dims[1] = extent[3] - extent[2] + 1; dims[2] = extent[5] - extent[4] + 1; } #endif //------------------------------------------------------------------------------ void vtkCartesianGrid::SetExtent(int x1, int x2, int y1, int y2, int z1, int z2) { int ext[6]; ext[0] = x1; ext[1] = x2; ext[2] = y1; ext[3] = y2; ext[4] = z1; ext[5] = z2; this->SetExtent(ext); } //------------------------------------------------------------------------------ void vtkCartesianGrid::SetExtent(int* extent) { int description; description = vtkStructuredData::SetExtent(extent, this->Extent); if (description < 0) // improperly specified { vtkErrorMacro("Bad Extent, retaining previous values"); return; } if (description == vtkStructuredData::VTK_STRUCTURED_UNCHANGED) { return; } vtkStructuredData::GetDimensionsFromExtent(extent, this->GetDimensions()); this->DataDescription = description; this->BuildImplicitStructures(); this->Modified(); } //------------------------------------------------------------------------------ void vtkCartesianGrid::SetScalarType(int type, vtkInformation* meta_data) { vtkDataObject::SetPointDataActiveScalarInfo(meta_data, type, -1); } //------------------------------------------------------------------------------ int vtkCartesianGrid::GetScalarType() { vtkDataArray* scalars = this->GetPointData()->GetScalars(); if (!scalars) { return VTK_DOUBLE; } return scalars->GetDataType(); } //------------------------------------------------------------------------------ bool vtkCartesianGrid::HasScalarType(vtkInformation* meta_data) { vtkInformation* scalarInfo = vtkDataObject::GetActiveFieldInformation( meta_data, FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS); if (!scalarInfo) { return false; } return scalarInfo->Has(FIELD_ARRAY_TYPE()) != 0; } //------------------------------------------------------------------------------ int vtkCartesianGrid::GetScalarType(vtkInformation* meta_data) { vtkInformation* scalarInfo = vtkDataObject::GetActiveFieldInformation( meta_data, FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS); if (scalarInfo) { return scalarInfo->Get(FIELD_ARRAY_TYPE()); } return VTK_DOUBLE; } //---------------------------------------------------------------------------- void vtkCartesianGrid::SetNumberOfScalarComponents(int num, vtkInformation* meta_data) { vtkDataObject::SetPointDataActiveScalarInfo(meta_data, -1, num); } //---------------------------------------------------------------------------- bool vtkCartesianGrid::HasNumberOfScalarComponents(vtkInformation* meta_data) { vtkInformation* scalarInfo = vtkDataObject::GetActiveFieldInformation( meta_data, FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS); if (!scalarInfo) { return false; } return scalarInfo->Has(FIELD_NUMBER_OF_COMPONENTS()) != 0; } //---------------------------------------------------------------------------- int vtkCartesianGrid::GetNumberOfScalarComponents(vtkInformation* meta_data) { vtkInformation* scalarInfo = vtkDataObject::GetActiveFieldInformation( meta_data, FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS); if (scalarInfo && scalarInfo->Has(FIELD_NUMBER_OF_COMPONENTS())) { return scalarInfo->Get(FIELD_NUMBER_OF_COMPONENTS()); } return 1; } //---------------------------------------------------------------------------- int vtkCartesianGrid::GetNumberOfScalarComponents() { vtkDataArray* scalars = this->GetPointData()->GetScalars(); if (scalars) { return scalars->GetNumberOfComponents(); } return 1; } //------------------------------------------------------------------------------ void vtkCartesianGrid::BuildImplicitStructures() { this->BuildPoints(); this->BuildCells(); this->BuildCellTypes(); } //------------------------------------------------------------------------------ void vtkCartesianGrid::BuildCells() { this->StructuredCells = vtkStructuredData::GetCellArray(this->GetExtent(), true); } //------------------------------------------------------------------------------ void vtkCartesianGrid::BuildCellTypes() { this->StructuredCellTypes = vtkStructuredData::GetCellTypes(this->GetExtent(), true); } //------------------------------------------------------------------------------ // This Method returns an index to a location in the vtkImageData. // Coordinates are in pixel units and are relative to the whole image origin. vtkIdType vtkCartesianGrid::GetTupleIndex(vtkDataArray* array, int coordinate[3]) { vtkIdType incs[3]; vtkIdType idx; if (array == nullptr) { return -1; } const int* extent = this->GetExtent(); // error checking: since most accesses will be from pointer arithmetic. // this should not waste much time. for (idx = 0; idx < 3; ++idx) { if (coordinate[idx] < extent[idx * 2] || coordinate[idx] > extent[idx * 2 + 1]) { vtkErrorMacro(<< "GetPointer: Pixel (" << coordinate[0] << ", " << coordinate[1] << ", " << coordinate[2] << ") not in current extent: (" << extent[0] << ", " << extent[1] << ", " << extent[2] << ", " << extent[3] << ", " << extent[4] << ", " << extent[5] << ")"); return -1; } } // compute the index of the vector. // Array increments incorporate the number of components, which is not how // vtkDataArrays are indexed. Instead, compute the tuple increments. { incs[0] = 1; incs[1] = (extent[1] - extent[0] + 1); incs[2] = incs[1] * (extent[3] - extent[2] + 1); } idx = ((coordinate[0] - extent[0]) * incs[0] + (coordinate[1] - extent[2]) * incs[1] + (coordinate[2] - extent[4]) * incs[2]); // I could check to see if the array has the correct number // of tuples for the extent, but that would be an extra multiply. if (idx < 0 || idx > array->GetMaxId()) { vtkErrorMacro("Coordinate (" << coordinate[0] << ", " << coordinate[1] << ", " << coordinate[2] << ") out side of array (max = " << array->GetMaxId()); return -1; } return idx; } //------------------------------------------------------------------------------- vtkIdType vtkCartesianGrid::GetTupleIndex(vtkDataArray* array, int x, int y, int z) { int temp[3] = { x, y, z }; return this->GetTupleIndex(array, temp); } //------------------------------------------------------------------------------- vtkIdType vtkCartesianGrid::GetTupleIndexForExtent(vtkDataArray* array, int extent[6]) { int tmp[3] = { extent[0], extent[2], extent[4] }; return this->GetTupleIndex(array, tmp); } //------------------------------------------------------------------------------ vtkIdType vtkCartesianGrid::GetValueIndex(vtkDataArray* array, int coordinate[3]) { vtkIdType tupleIndex = this->GetTupleIndex(array, coordinate); return tupleIndex >= 0 ? tupleIndex * array->GetNumberOfComponents() : -1; } //------------------------------------------------------------------------------ vtkIdType vtkCartesianGrid::GetValueIndex(vtkDataArray* array, int x, int y, int z) { int tmp[3] = { x, y, z }; return this->GetValueIndex(array, tmp); } //------------------------------------------------------------------------------ vtkIdType vtkCartesianGrid::GetValueIndexForExtent(vtkDataArray* array, int extent[6]) { int tmp[3] = { extent[0], extent[2], extent[4] }; return this->GetValueIndex(array, tmp); } VTK_ABI_NAMESPACE_END