// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkCellLinks.h" #include "vtkCellArray.h" #include "vtkDataSet.h" #include "vtkGenericCell.h" #include "vtkObjectFactory.h" #include "vtkPolyData.h" #include "vtkSMPTools.h" #include VTK_ABI_NAMESPACE_BEGIN //------------------------------------------------------------------------------ vtkStandardNewMacro(vtkCellLinks); //------------------------------------------------------------------------------ vtkCellLinks::vtkCellLinks() : ArraySharedPtr(nullptr) , Array(nullptr) , Size(0) , MaxId(-1) , Extend(1000) , NumberOfPoints(0) , NumberOfCells(0) { this->Type = vtkAbstractCellLinks::CELL_LINKS; } //------------------------------------------------------------------------------ vtkCellLinks::~vtkCellLinks() { this->Initialize(); } //------------------------------------------------------------------------------ void vtkCellLinks::Initialize() { if (this->Array != nullptr) { if (this->ArraySharedPtr.use_count() == 1) { for (vtkIdType i = 0; i <= this->MaxId; i++) { delete[] this->Array[i].cells; } } // this->ArraySharedPtr will be reset by the destructor this->Array = nullptr; } this->Size = 0; this->NumberOfPoints = 0; this->NumberOfCells = 0; this->Modified(); } //------------------------------------------------------------------------------ void vtkCellLinks::Allocate(vtkIdType sz, vtkIdType ext) { this->Initialize(); this->Size = sz; // NOLINTNEXTLINE(modernize-make-shared) this->ArraySharedPtr.reset(new Link[sz](), std::default_delete()); this->Array = this->ArraySharedPtr.get(); this->Extend = ext; this->MaxId = -1; this->Modified(); } //---------------------------------------------------------------------------- // Allocate memory for the list of lists of cell ids. void vtkCellLinks::AllocateLinks(vtkIdType n) { vtkSMPTools::For(0, n, [&](vtkIdType beginPtId, vtkIdType endPtId) { for (vtkIdType ptId = beginPtId; ptId < endPtId; ++ptId) { this->Array[ptId].cells = new vtkIdType[this->Array[ptId].ncells]; } }); } //------------------------------------------------------------------------------ // Reclaim any unused memory. void vtkCellLinks::Squeeze() { this->Resize(this->MaxId + 1); } //------------------------------------------------------------------------------ void vtkCellLinks::Reset() { this->MaxId = -1; this->Modified(); } //------------------------------------------------------------------------------ // // Private function does "reallocate" // vtkCellLinks::Link* vtkCellLinks::Resize(vtkIdType sz) { vtkIdType newSize; if (sz >= this->Size) { newSize = this->Size + sz; } else { newSize = sz; } // NOLINTNEXTLINE(modernize-make-shared) std::shared_ptr newArraySharedPtr(new Link[newSize], std::default_delete()); Link* newArray = newArraySharedPtr.get(); for (vtkIdType i = 0; i < sz && i < this->Size; i++) { newArray[i] = this->Array[i]; } for (vtkIdType i = this->Size; i < newSize; i++) { newArray[i] = Link(); } this->Size = newSize; this->ArraySharedPtr = newArraySharedPtr; this->Array = this->ArraySharedPtr.get(); return this->Array; } //------------------------------------------------------------------------------ // Build the link list array. void vtkCellLinks::BuildLinks() { // don't rebuild if build time is newer than modified and dataset modified time if (this->Array && this->BuildTime > this->MTime && this->BuildTime > this->DataSet->GetMTime()) { return; } vtkIdType numPts = this->NumberOfPoints = this->DataSet->GetNumberOfPoints(); vtkIdType numCells = this->NumberOfCells = this->DataSet->GetNumberOfCells(); int j; vtkIdType cellId; if (this->Array == nullptr) { this->Allocate(numPts); } // This is checked to capture changes in the size of the allocation else if (this->DataSet->GetMTime() > this->BuildTime && this->DataSet->GetMTime() > this->MTime) { this->Allocate(numPts); } // Use fast path if polydata vtkIdType npts; const vtkIdType* pts; vtkNew tempIds; // traverse data to determine number of uses of each point for (cellId = 0; cellId < numCells; cellId++) { this->DataSet->GetCellPoints(cellId, npts, pts, tempIds); for (j = 0; j < npts; j++) { this->IncrementLinkCount(pts[j]); } } // fill out lists with number of references to cells std::vector linkLoc(numPts, 0); // now allocate storage for the links this->AllocateLinks(numPts); // fill out lists with cell ids for (cellId = 0; cellId < numCells; cellId++) { this->DataSet->GetCellPoints(cellId, npts, pts, tempIds); for (j = 0; j < npts; j++) { this->InsertCellReference(pts[j], (linkLoc[pts[j]])++, cellId); } } this->MaxId = numPts - 1; this->BuildTime.Modified(); } //------------------------------------------------------------------------------ // Insert a new point into the cell-links data structure. The size parameter // is the initial size of the list. vtkIdType vtkCellLinks::InsertNextPoint(int numLinks) { if (++this->MaxId >= this->Size) { this->Resize(this->MaxId + 1); } this->Array[this->MaxId].cells = new vtkIdType[numLinks]; return this->MaxId; } //------------------------------------------------------------------------------ // Mark cells with one or more points whose degree lies in the range indicated. void vtkCellLinks::SelectCells(vtkIdType minMaxDegree[2], unsigned char* cellSelection) { std::fill_n(cellSelection, this->NumberOfCells, 0); vtkSMPTools::For(0, this->NumberOfPoints, [this, minMaxDegree, cellSelection](vtkIdType ptId, vtkIdType endPtId) { for (; ptId < endPtId; ++ptId) { vtkIdType degree = this->GetNcells(0); if (degree >= minMaxDegree[0] && degree < minMaxDegree[1]) { vtkIdType* cells = this->GetCells(ptId); for (auto i = 0; i < degree; ++i) { cellSelection[cells[i]] = 1; } } } // for all points in this batch }); // end lambda } //------------------------------------------------------------------------------ unsigned long vtkCellLinks::GetActualMemorySize() { vtkIdType size = 0; vtkIdType ptId; for (ptId = 0; ptId < (this->MaxId + 1); ptId++) { size += this->GetNcells(ptId); } size *= sizeof(int*); // references to cells size += (this->MaxId + 1) * sizeof(Link); // list of cell lists return static_cast(std::ceil(size / 1024.0)); // kibibytes } //------------------------------------------------------------------------------ void vtkCellLinks::DeepCopy(vtkAbstractCellLinks* src) { auto cellLinks = vtkCellLinks::SafeDownCast(src); if (!cellLinks) { return; } this->Allocate(cellLinks->Size, cellLinks->Extend); vtkSMPTools::For(0, cellLinks->MaxId + 1, [&](vtkIdType ptId, vtkIdType endPtId) { for (; ptId < endPtId; ++ptId) { vtkIdType ncells = cellLinks->GetNcells(ptId); this->Array[ptId].cells = new vtkIdType[ncells]; this->Array[ptId].ncells = ncells; std::copy_n(cellLinks->Array[ptId].cells, ncells, this->Array[ptId].cells); } }); this->MaxId = cellLinks->MaxId; this->Extend = cellLinks->Extend; this->NumberOfPoints = cellLinks->NumberOfPoints; this->NumberOfCells = cellLinks->NumberOfCells; this->BuildTime.Modified(); } //------------------------------------------------------------------------------ void vtkCellLinks::ShallowCopy(vtkAbstractCellLinks* src) { auto cellLinks = vtkCellLinks::SafeDownCast(src); if (!cellLinks) { return; } this->ArraySharedPtr = cellLinks->ArraySharedPtr; this->Array = this->ArraySharedPtr.get(); this->Size = cellLinks->Size; this->MaxId = cellLinks->MaxId; this->Extend = cellLinks->Extend; this->NumberOfPoints = cellLinks->NumberOfPoints; this->NumberOfCells = cellLinks->NumberOfCells; this->BuildTime.Modified(); } //------------------------------------------------------------------------------ void vtkCellLinks::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Size: " << this->Size << "\n"; os << indent << "MaxId: " << this->MaxId << "\n"; os << indent << "Extend: " << this->Extend << "\n"; } VTK_ABI_NAMESPACE_END