Files
ThirdParty-6/ParaView-5.0.1/Plugins/ThickenLayeredCells/vtkThickenLayeredCells.cxx

261 lines
7.6 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkThickenLayeredCells.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkThickenLayeredCells.h"
#include "vtkCellIterator.h"
#include "vtkIdList.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkPoints.h"
#include "vtkUnstructuredGrid.h"
#include "vtkVector.h"
#include "vtkVectorOperators.h"
#include <cassert>
#include <set>
#include <map>
#include <algorithm>
namespace
{
typedef std::pair<vtkIdType, vtkIdType> vtkEdge;
class vtkEdgeInfo
{
public:
vtkEdge Edge;
double Sum;
int Count;
int Layer;
vtkEdgeInfo() : Sum(0), Count(0), Layer(-1)
{
}
double GetAverageValue() const
{
assert(this->Count > 0);
return this->Sum / this->Count;
}
};
class vtkEdgeInfoDescending
{
public:
bool operator()(const vtkEdgeInfo& a, const vtkEdgeInfo& b) const
{
return b.Layer < a.Layer;
}
};
typedef std::map<vtkEdge, vtkEdgeInfo> vtkEdgeMap;
class vtkNodeInfo
{
vtkVector2i Layers;
public:
vtkNodeInfo() : Layers(-1, -1) {}
void AddLayer(int layer)
{
if (this->Layers[0] == -1)
{
this->Layers[0] = layer;
}
else if (this->Layers[1] == -1)
{
int layer0 = this->Layers[0];
this->Layers[0] = std::min(layer0, layer);
this->Layers[1] = std::max(layer0, layer);
}
else
{
vtkGenericWarningMacro("An egde is shared between more than 2 layers!!!! Ignoring.");
}
}
inline bool OffsetForLayer(int layer, int fixed_layer) const
{
assert(layer != -1);
if (this->Layers[1] == layer)
{
return true;
}
if (this->Layers[1] == -1 && this->Layers[0] == layer)
{
return layer != fixed_layer;
}
return false;
}
};
class vtkNodeMap : public std::map<vtkIdType, vtkNodeInfo>
{
public:
void AddEdge(const vtkEdge& edge, int layer)
{
(*this)[edge.first].AddLayer(layer);
(*this)[edge.second].AddLayer(layer);
}
};
int vtkDisplacePoints(vtkEdgeMap& edges, vtkNodeMap& nodes,
vtkPoints* ipoints, vtkPoints* opoints, int outermost_layer)
{
// sort edges by layer, since we displace points in that order.
// We use descending order since layer 1 is the inner most layer and layer 6 is the outermost
// and we want to keep layer 6 invariant.
std::multiset<vtkEdgeInfo, vtkEdgeInfoDescending> sorted_edges;
for (vtkEdgeMap::const_iterator miter = edges.begin(); miter != edges.end(); ++miter)
{
sorted_edges.insert(miter->second);
}
for (std::multiset<vtkEdgeInfo, vtkEdgeInfoDescending>::const_iterator seiter = sorted_edges.begin();
seiter != sorted_edges.end(); ++seiter)
{
const double avgThickness = seiter->GetAverageValue();
vtkVector3d pt1, pt2;
ipoints->GetPoint(seiter->Edge.first, pt1.GetData());
ipoints->GetPoint(seiter->Edge.second, pt2.GetData());
vtkVector3d vec = pt2 - pt1;
vec.Normalize();
opoints->GetPoint(seiter->Edge.first, pt1.GetData());
opoints->GetPoint(seiter->Edge.second, pt2.GetData());
int offset_count = 0;
if (nodes[seiter->Edge.first].OffsetForLayer(seiter->Layer, outermost_layer))
{
opoints->SetPoint(seiter->Edge.first, (pt2 - vec * avgThickness).GetData());
offset_count++;
}
else
{
opoints->SetPoint(seiter->Edge.first, pt1.GetData());
}
if (nodes[seiter->Edge.second].OffsetForLayer(seiter->Layer, outermost_layer))
{
opoints->SetPoint(seiter->Edge.second, (pt1 + vec * avgThickness).GetData());
offset_count++;
}
else
{
opoints->SetPoint(seiter->Edge.second, pt2.GetData());
}
assert(offset_count == 1);
}
return 1;
}
};
vtkStandardNewMacro(vtkThickenLayeredCells);
//----------------------------------------------------------------------------
vtkThickenLayeredCells::vtkThickenLayeredCells()
{
}
//----------------------------------------------------------------------------
vtkThickenLayeredCells::~vtkThickenLayeredCells()
{
}
//----------------------------------------------------------------------------
int vtkThickenLayeredCells::RequestData(vtkInformation* vtkNotUsed(request),
vtkInformationVector** inputVector,
vtkInformationVector* outputVector)
{
vtkUnstructuredGrid* input = vtkUnstructuredGrid::GetData(inputVector[0], 0);
vtkUnstructuredGrid* output = vtkUnstructuredGrid::GetData(outputVector);
output->ShallowCopy(input);
vtkPoints* ipoints = input->GetPoints();
vtkNew<vtkPoints> opoints;
opoints->DeepCopy(ipoints);
output->SetPoints(opoints.GetPointer());
vtkNew<vtkIdList> ptIds;
int association = 0;
vtkDataArray* thickness = this->GetInputArrayToProcess(0, input, association);
if (association != vtkDataObject::FIELD_ASSOCIATION_CELLS)
{
vtkErrorMacro("We only support cell data for thickness");
return 0;
}
vtkDataArray* layer = this->GetInputArrayToProcess(1, input, association);
if (association != vtkDataObject::FIELD_ASSOCIATION_CELLS)
{
vtkErrorMacro("We only support cell data for 'layer'");
return 0;
}
double layerRange[2];
layer->GetRange(layerRange, 0);
// Compute average thickness for all the edges.
vtkEdgeMap edges;
vtkNodeMap nodes;
bool warned_once = false;
// Iterate over cells to locate edges and but those edges in the `edges` map. The edges
// keep track of the two nodes that form the edge as well as which layer the edge belongs to.
// At the same time, we build a nodes datastructure which tells us the information about the
// at-most-two layers that the node is shared with.
vtkCellIterator *iter = input->NewCellIterator();
for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextCell())
{
if (iter->GetCellType() != VTK_WEDGE)
{
// We only handle wedges.
if (!warned_once)
{
warned_once = true;
vtkWarningMacro("This filter currently only supports Wedges. Ignoring all other cell types.");
}
continue;
}
input->GetCellPoints(iter->GetCellId(), ptIds.GetPointer());
assert(ptIds->GetNumberOfIds() == 6);
for (int cc=0; cc < 3; cc++)
{
vtkIdType p1 = std::min(ptIds->GetId(cc), ptIds->GetId(cc+3));
vtkIdType p2 = std::max(ptIds->GetId(cc), ptIds->GetId(cc+3));
vtkEdgeInfo& info = edges[vtkEdge(p1, p2)];
info.Edge.first = p1;
info.Edge.second = p2;
if (info.Count == 0)
{
info.Layer = layer->GetComponent(iter->GetCellId(), 0);
nodes.AddEdge(info.Edge, info.Layer);
}
else
{
assert(info.Layer == layer->GetComponent(iter->GetCellId(), 0));
}
info.Sum += thickness->GetComponent(iter->GetCellId(), 0);
info.Count++;
}
}
iter->Delete();
return vtkDisplacePoints(edges, nodes, ipoints, opoints.GetPointer(), layerRange[1]);
}
//----------------------------------------------------------------------------
void vtkThickenLayeredCells::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}