1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
#include "vtkHyperTreeGridCellSizeStrategy.h"
#include "vtkDoubleArray.h"
#include "vtkHyperTreeGridNonOrientedGeometryCursor.h"
#include "vtkUnsignedCharArray.h"
VTK_ABI_NAMESPACE_BEGIN
vtkStandardNewMacro(vtkHyperTreeGridCellSizeStrategy);
namespace
{
/**
* Return the size of the cell pointed by the cursor.
* In practice, we multiply every non-null size value for the current cell.
*/
double GetCellSize(vtkHyperTreeGridNonOrientedGeometryCursor* cursor)
{
double cellSize = 1.0;
bool nullSize = true;
double* size = cursor->GetSize();
std::vector<double> dimensions(size, size + 3);
for (auto& edgeSize : dimensions)
{
if (edgeSize != 0.0)
{
nullSize = false;
cellSize *= edgeSize;
}
}
if (nullSize)
{
// Every size coordinate is null, so the cell size is also null
cellSize = 0.0;
}
return cellSize;
}
}
//------------------------------------------------------------------------------
vtkHyperTreeGridCellSizeStrategy::vtkHyperTreeGridCellSizeStrategy() = default;
//------------------------------------------------------------------------------
vtkHyperTreeGridCellSizeStrategy::~vtkHyperTreeGridCellSizeStrategy() = default;
//------------------------------------------------------------------------------
void vtkHyperTreeGridCellSizeStrategy::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
os << indent << "UseIndexedVolume: " << this->UseIndexedVolume << "\n";
os << indent << "VolumeLookup size: " << this->VolumeLookup.size() << "\n";
os << indent << "SizeIndirectionTable size: "
<< (this->SizeIndirectionTable ? this->SizeIndirectionTable->GetNumberOfTuples() : 0) << "\n";
os << indent << "SizeDiscreteValues size: "
<< (this->SizeDiscreteValues ? this->SizeDiscreteValues->GetNumberOfTuples() : 0) << "\n";
os << indent << "SizeFullValues size: "
<< (this->SizeFullValues ? this->SizeFullValues->GetNumberOfTuples() : 0) << "\n";
os << indent << "OutputSizeArray size: "
<< (this->OutputSizeArray ? this->OutputSizeArray->GetNumberOfTuples() : 0) << "\n";
}
//------------------------------------------------------------------------------
bool vtkHyperTreeGridCellSizeStrategy::InsertSize(double cellSize, vtkIdType currentIndex)
{
// Use a hash table for O(1) insertion and search time instead of searching the VTK array
const auto& inserted = this->VolumeLookup.insert(
std::make_pair(cellSize, static_cast<unsigned char>(this->VolumeLookup.size())));
if (inserted.second)
{
// Insertion succeeded : new element in the lookup table
this->SizeDiscreteValues->InsertTuple1(this->SizeDiscreteValues->GetNumberOfTuples(), cellSize);
}
// New element or not, fill the indirection table
this->SizeIndirectionTable->SetTuple1(currentIndex, inserted.first->second);
return inserted.first->second < std::numeric_limits<unsigned char>::max();
}
//------------------------------------------------------------------------------
void vtkHyperTreeGridCellSizeStrategy::ConvertSizes()
{
// Dump the volume values from the map keys
std::vector<double> temp_volume;
temp_volume.resize(this->VolumeLookup.size(), 0.0);
for (const auto& vol_id : this->VolumeLookup)
{
temp_volume[vol_id.second] = vol_id.first;
}
this->VolumeLookup.clear();
// Construct the volume array
this->SizeFullValues->SetNumberOfComponents(1);
this->SizeFullValues->SetNumberOfTuples(SizeIndirectionTable->GetNumberOfTuples());
for (int i = 0; i < SizeIndirectionTable->GetNumberOfTuples(); i++)
{
this->SizeFullValues->SetTuple1(i, temp_volume[SizeIndirectionTable->GetTuple1(i)]);
}
}
//------------------------------------------------------------------------------
void vtkHyperTreeGridCellSizeStrategy::Initialize(vtkHyperTreeGrid* inputHTG)
{
this->UseIndexedVolume = true;
this->SizeDiscreteValues->SetNumberOfComponents(
1); // We don't know yet how many different values we can have
this->OutputSizeArray->SetNumberOfComponents(1);
this->OutputSizeArray->SetNumberOfTuples(inputHTG->GetNumberOfCells());
this->SizeIndirectionTable->SetNumberOfComponents(1);
this->SizeIndirectionTable->SetNumberOfTuples(inputHTG->GetNumberOfCells());
// Initialize the whole indirection array with 0 values
this->InsertSize(0.0, 0); // Make sure size 0 is in the size lookup map.
for (vtkIdType i = 0; i < this->SizeIndirectionTable->GetNumberOfValues(); i++)
{
this->SizeIndirectionTable->SetTuple1(i, 0.0);
}
}
//------------------------------------------------------------------------------
void vtkHyperTreeGridCellSizeStrategy::Compute(vtkHyperTreeGridNonOrientedGeometryCursor* cursor)
{
double cellSize = ::GetCellSize(cursor);
vtkIdType currentIndex = cursor->GetGlobalNodeIndex();
if (!this->UseIndexedVolume)
{
// We don't use the implicit array anymore but a full Size array
this->SizeFullValues->SetTuple1(currentIndex, cellSize);
return;
}
// Try to insert size in the indexed array
if (this->InsertSize(cellSize, currentIndex))
{
return;
}
// We have too many different size values to store them in an unsigned char,
// so at this point, we give up on implicit indexed array and use a classic VTK double array to
// store values. This requires that values are copied from the indirect storage array to the
// final double array.
this->UseIndexedVolume = false;
this->ConvertSizes();
}
//------------------------------------------------------------------------------
vtkDataArray* vtkHyperTreeGridCellSizeStrategy::GetAndFinalizeArray()
{
if (this->UseIndexedVolume)
{
// The size values take a discrete number of different values : one value for each level
// Thus, we can use an indexed (implicit) array as an indirection table to store the size as a
// uchar (256 possible values/levels) instead of a double for each cell to save memory (1 byte
// stored instead of 8)
this->OutputSizeArray->SetName(this->ArrayName.c_str());
this->OutputSizeArray->SetNumberOfComponents(1);
this->OutputSizeArray->SetNumberOfTuples(this->SizeIndirectionTable->GetNumberOfValues());
this->OutputSizeArray->SetBackend(std::make_shared<vtkIndexedImplicitBackend<double>>(
SizeIndirectionTable, SizeDiscreteValues));
return this->OutputSizeArray;
}
else
{
this->SizeFullValues->SetName(this->ArrayName.c_str());
return this->SizeFullValues;
}
}
VTK_ABI_NAMESPACE_END
|