Add support for field mapping.

This commit is contained in:
Dave Pugmire 2019-08-22 08:14:52 -04:00
parent cbc972f101
commit 43ddcab81e
3 changed files with 190 additions and 44 deletions

@ -29,32 +29,43 @@ template <typename Policy>
inline VTKM_CONT vtkm::cont::DataSet Tube::DoExecute(const vtkm::cont::DataSet& input,
vtkm::filter::PolicyBase<Policy>)
{
vtkm::worklet::Tube tube(this->Capping, this->NumberOfSides, this->Radius);
this->Worklet.SetCapping(this->Capping);
this->Worklet.SetNumberOfSides(this->NumberOfSides);
this->Worklet.SetRadius(this->Radius);
vtkm::cont::ArrayHandle<vtkm::Vec3f> newPoints;
vtkm::cont::CellSetSingleType<> newCells;
tube.Run(input.GetCoordinateSystem(this->GetActiveCoordinateSystemIndex()),
input.GetCellSet(this->GetActiveCellSetIndex()),
newPoints,
newCells);
this->Worklet.Run(input.GetCoordinateSystem(this->GetActiveCoordinateSystemIndex()),
input.GetCellSet(this->GetActiveCellSetIndex()),
newPoints,
newCells);
vtkm::cont::DataSet outData;
vtkm::cont::CoordinateSystem outCoords("coordinates", newPoints);
outData.AddCellSet(newCells);
outData.AddCoordinateSystem(outCoords);
return outData;
}
//-----------------------------------------------------------------------------
template <typename T, typename StorageType, typename DerivedPolicy>
inline VTKM_CONT bool Tube::DoMapField(vtkm::cont::DataSet&,
const vtkm::cont::ArrayHandle<T, StorageType>&,
const vtkm::filter::FieldMetadata&,
inline VTKM_CONT bool Tube::DoMapField(vtkm::cont::DataSet& result,
const vtkm::cont::ArrayHandle<T, StorageType>& input,
const vtkm::filter::FieldMetadata& fieldMeta,
vtkm::filter::PolicyBase<DerivedPolicy>)
{
return false;
vtkm::cont::ArrayHandle<T> fieldArray;
if (fieldMeta.IsPointField())
fieldArray = this->Worklet.ProcessPointField(input);
else if (fieldMeta.IsCellField())
fieldArray = this->Worklet.ProcessCellField(input);
else
return false;
//use the same meta data as the input so we get the same field name, etc.
result.AddField(fieldMeta.AsField(fieldArray));
return true;
}
}
} // namespace vtkm::filter

@ -9,6 +9,7 @@
//============================================================================
#include <vtkm/cont/DataSetBuilderExplicit.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/Tube.h>
@ -29,11 +30,13 @@ void TestTubeFilters()
using VecType = vtkm::Vec3f;
vtkm::cont::DataSetBuilderExplicitIterative dsb;
vtkm::cont::DataSetFieldAdd dsf;
std::vector<vtkm::Id> ids;
ids.clear();
appendPts(dsb, VecType(0, 0, 0), ids);
appendPts(dsb, VecType(1, 0, 0), ids);
appendPts(dsb, VecType(2, 0, 0), ids);
dsb.AddCell(vtkm::CELL_SHAPE_POLY_LINE, ids);
ids.clear();
@ -42,24 +45,34 @@ void TestTubeFilters()
appendPts(dsb, VecType(2, 1, 0), ids);
dsb.AddCell(vtkm::CELL_SHAPE_POLY_LINE, ids);
ids.clear();
appendPts(dsb, VecType(0, 0, 0), ids);
appendPts(dsb, VecType(1, 0, 0), ids);
appendPts(dsb, VecType(2, 1, 0), ids);
appendPts(dsb, VecType(3, 0, 0), ids);
appendPts(dsb, VecType(4, 0, 0), ids);
dsb.AddCell(vtkm::CELL_SHAPE_POLY_LINE, ids);
vtkm::cont::DataSet ds = dsb.Create();
std::vector<vtkm::FloatDefault> ptVar, cellVar;
//Polyline 1.
ptVar.push_back(0);
ptVar.push_back(1);
ptVar.push_back(2);
cellVar.push_back(100);
cellVar.push_back(101);
//Polyline 2.
ptVar.push_back(10);
ptVar.push_back(11);
ptVar.push_back(12);
cellVar.push_back(110);
cellVar.push_back(111);
dsf.AddPointField(ds, "pointVar", ptVar);
dsf.AddCellField(ds, "cellVar", cellVar);
vtkm::filter::Tube tubeFilter;
tubeFilter.SetCapping(true);
tubeFilter.SetNumberOfSides(13);
tubeFilter.SetNumberOfSides(3);
tubeFilter.SetRadius(static_cast<vtkm::FloatDefault>(0.2));
auto output = tubeFilter.Execute(ds);
//Validate the result is correct.
VTKM_TEST_ASSERT(output.GetNumberOfCellSets() == 1,
"Wrong number of cellsets in the output dataset");
@ -67,10 +80,34 @@ void TestTubeFilters()
"Wrong number of coordinate systems in the output dataset");
vtkm::cont::CoordinateSystem coords = output.GetCoordinateSystem();
VTKM_TEST_ASSERT(coords.GetNumberOfPoints() == 136, "Wrong number of coordinates");
VTKM_TEST_ASSERT(coords.GetNumberOfPoints() == 22, "Wrong number of coordinates");
vtkm::cont::DynamicCellSet dcells = output.GetCellSet();
VTKM_TEST_ASSERT(dcells.GetNumberOfCells() == 260, "Wrong number of cells");
VTKM_TEST_ASSERT(dcells.GetNumberOfCells() == 36, "Wrong number of cells");
//Validate the point field
auto ptArr =
output.GetField("pointVar").GetData().Cast<vtkm::cont::ArrayHandle<vtkm::FloatDefault>>();
VTKM_TEST_ASSERT(ptArr.GetNumberOfValues() == 22, "Wrong number of values in point field");
std::vector<vtkm::FloatDefault> ptVals = { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2,
10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 12 };
auto portal = ptArr.GetPortalConstControl();
for (vtkm::Id i = 0; i < 22; i++)
VTKM_TEST_ASSERT(portal.Get(i) == ptVals[i], "Wrong value for point field");
//Validate the cell field
auto cellArr =
output.GetField("cellVar").GetData().Cast<vtkm::cont::ArrayHandle<vtkm::FloatDefault>>();
VTKM_TEST_ASSERT(cellArr.GetNumberOfValues() == 36, "Wrong number of values in cell field");
std::vector<vtkm::FloatDefault> cellVals = { 100, 100, 100, 100, 100, 100, 101, 101, 101,
101, 101, 101, 100, 100, 100, 101, 101, 101,
110, 110, 110, 110, 110, 110, 111, 111, 111,
111, 111, 111, 110, 110, 110, 111, 111, 111 };
portal = cellArr.GetPortalConstControl();
for (vtkm::Id i = 0; i < 36; i++)
VTKM_TEST_ASSERT(portal.Get(i) == cellVals[i], "Wrong value for cell field");
}
}

@ -42,12 +42,14 @@ public:
using ControlSignature = void(CellSetIn,
FieldOut ptsPerPolyline,
FieldOut ptsPerTube,
FieldOut numTubeConnIds);
FieldOut numTubeConnIds,
FieldOut linesPerPolyline);
using ExecutionSignature = void(CellShape shapeType,
PointCount numPoints,
_2 ptsPerPolyline,
_3 ptsPerTube,
_4 numTubeConnIds);
_4 numTubeConnIds,
_5 linesPerPolyline);
using InputDomain = _1;
template <typename CellShapeTag>
@ -55,7 +57,8 @@ public:
const vtkm::IdComponent& numPoints,
vtkm::Id& ptsPerPolyline,
vtkm::Id& ptsPerTube,
vtkm::Id& numTubeConnIds) const
vtkm::Id& numTubeConnIds,
vtkm::Id& linesPerPolyline) const
{
// We only support polylines that contain 2 or more points.
if (shapeType.Id == vtkm::CELL_SHAPE_POLY_LINE && numPoints > 1)
@ -64,6 +67,7 @@ public:
ptsPerTube = this->NumSides * numPoints;
// (two tris per segment) X (numSides) X numVertsPerCell
numTubeConnIds = (numPoints - 1) * 2 * this->NumSides * this->NumVertsPerCell;
linesPerPolyline = numPoints - 1;
//Capping adds center vertex in middle of cap, plus NumSides triangles for cap.
if (this->Capping)
@ -77,6 +81,7 @@ public:
ptsPerPolyline = 0;
ptsPerTube = 0;
numTubeConnIds = 0;
linesPerPolyline = 0;
}
}
@ -266,7 +271,8 @@ public:
WholeArrayIn normals,
FieldInCell tubePointOffsets,
FieldInCell polylineOffset,
WholeArrayOut newPointCoords);
WholeArrayOut newPointCoords,
WholeArrayOut outPointSrcIdx);
using ExecutionSignature = void(CellShape shapeType,
PointCount numPoints,
PointIndices ptIndices,
@ -274,14 +280,16 @@ public:
_3 inNormals,
_4 tubePointOffsets,
_5 polylineOffset,
_6 outPts);
_6 outPts,
_7 outPointSrcIdx);
using InputDomain = _1;
template <typename CellShapeTag,
typename PointIndexType,
typename InPointsType,
typename InNormalsType,
typename OutPointsType>
typename OutPointsType,
typename OutPointSrcIdxType>
VTKM_EXEC void operator()(const CellShapeTag& shapeType,
const vtkm::IdComponent& numPoints,
const PointIndexType& ptIndices,
@ -289,7 +297,8 @@ public:
const InNormalsType& inNormals,
const vtkm::Id& tubePointOffsets,
const vtkm::Id& polylineOffset,
OutPointsType& outPts) const
OutPointsType& outPts,
OutPointSrcIdxType& outPointSrcIdx) const
{
if (shapeType.Id != vtkm::CELL_SHAPE_POLY_LINE || numPoints < 2)
return;
@ -297,12 +306,15 @@ public:
{
vtkm::Vec3f n, p, pNext, sNext, sPrev;
vtkm::Id outIdx = tubePointOffsets;
vtkm::Id pIdx, pNextIdx;
for (vtkm::IdComponent j = 0; j < numPoints; j++)
{
if (j == 0) //first point
{
p = inPts.Get(ptIndices[j]);
pNext = inPts.Get(ptIndices[j + 1]);
pIdx = ptIndices[j];
pNextIdx = ptIndices[j + 1];
p = inPts.Get(pIdx);
pNext = inPts.Get(pNextIdx);
sNext = pNext - p;
sPrev = sNext;
}
@ -310,11 +322,14 @@ public:
{
sPrev = sNext;
p = pNext;
pIdx = pNextIdx;
}
else
{
p = pNext;
pNext = inPts.Get(ptIndices[j + 1]);
pIdx = pNextIdx;
pNextIdx = ptIndices[j + 1];
pNext = inPts.Get(pNextIdx);
sPrev = sNext;
sNext = pNext - p;
}
@ -344,6 +359,7 @@ public:
if (this->Capping && j == 0)
{
outPts.Set(outIdx, p);
outPointSrcIdx.Set(outIdx, pIdx);
outIdx++;
}
@ -357,6 +373,7 @@ public:
normal = w * cosValue + nP * sinValue;
auto newPt = p + this->Radius * normal;
outPts.Set(outIdx, newPt);
outPointSrcIdx.Set(outIdx, pIdx);
outIdx++;
}
@ -364,6 +381,7 @@ public:
if (this->Capping && j == numPoints - 1)
{
outPts.Set(outIdx, p);
outPointSrcIdx.Set(outIdx, pIdx);
outIdx++;
}
}
@ -391,20 +409,26 @@ public:
using ControlSignature = void(CellSetIn cellset,
FieldInCell tubePointOffsets,
FieldInCell tubeConnOffsets,
WholeArrayOut outConnectivity);
FieldInCell segOffset,
WholeArrayOut outConnectivity,
WholeArrayOut outCellSrcIdx);
using ExecutionSignature = void(CellShape shapeType,
PointCount numPoints,
_2 tubePointOffset,
_3 tubeConnOffsets,
_4 outConn);
_4 segOffset,
_5 outConn,
_6 outCellSrcIdx);
using InputDomain = _1;
template <typename CellShapeTag, typename OutConnType>
template <typename CellShapeTag, typename OutConnType, typename OutCellSrcIdxType>
VTKM_EXEC void operator()(const CellShapeTag& shapeType,
const vtkm::IdComponent& numPoints,
const vtkm::Id& tubePointOffset,
const vtkm::Id& tubeConnOffset,
OutConnType& outConn) const
const vtkm::Id& segOffset,
OutConnType& outConn,
OutCellSrcIdxType& outCellSrcIdx) const
{
if (shapeType.Id != vtkm::CELL_SHAPE_POLY_LINE || numPoints < 2)
return;
@ -421,6 +445,7 @@ public:
outConn.Set(outIdx + 1, tubePtOffset + i * this->NumSides + (j + 1) % this->NumSides);
outConn.Set(outIdx + 2,
tubePtOffset + (i + 1) * this->NumSides + (j + 1) % this->NumSides);
outCellSrcIdx.Set(outIdx / 3, segOffset + static_cast<vtkm::Id>(i));
outIdx += 3;
//Triangle 2: verts 0,2,3
@ -428,6 +453,7 @@ public:
outConn.Set(outIdx + 1,
tubePtOffset + (i + 1) * this->NumSides + (j + 1) % this->NumSides);
outConn.Set(outIdx + 2, tubePtOffset + (i + 1) * this->NumSides + j);
outCellSrcIdx.Set(outIdx / 3, segOffset + static_cast<vtkm::Id>(i));
outIdx += 3;
}
}
@ -441,6 +467,7 @@ public:
outConn.Set(outIdx + 0, startCenterPt);
outConn.Set(outIdx + 1, startCenterPt + 1 + j);
outConn.Set(outIdx + 2, startCenterPt + 1 + ((j + 1) % this->NumSides));
outCellSrcIdx.Set(outIdx / 3, segOffset);
outIdx += 3;
}
@ -453,6 +480,7 @@ public:
outConn.Set(outIdx + 0, endCenterPt);
outConn.Set(outIdx + 1, endOffsetPt + j);
outConn.Set(outIdx + 2, endOffsetPt + ((j + 1) % this->NumSides));
outCellSrcIdx.Set(outIdx / 3, segOffset + static_cast<vtkm::Id>(numPoints - 2));
outIdx += 3;
}
}
@ -464,6 +492,26 @@ public:
vtkm::Id NumSides;
};
class MapField : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn sourceIdx, WholeArrayIn sourceArray, FieldOut output);
using ExecutionSignature = void(_1 sourceIdx, _2 sourceArray, _3 output);
using InputDomain = _1;
VTKM_CONT
MapField() {}
template <typename SourceArrayType, typename T>
VTKM_EXEC void operator()(const vtkm::Id& sourceIdx,
const SourceArrayType& sourceArray,
T& output) const
{
output = sourceArray.Get(sourceIdx);
}
};
VTKM_CONT
Tube()
: Capping(false)
@ -481,6 +529,13 @@ public:
{
}
VTKM_CONT
void SetCapping(bool v) { this->Capping = v; }
VTKM_CONT
void SetNumberOfSides(vtkm::Id n) { this->NumSides = n; }
VTKM_CONT
void SetRadius(vtkm::FloatDefault r) { this->Radius = r; }
VTKM_CONT
void Run(const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::DynamicCellSet& cellset,
@ -498,48 +553,91 @@ public:
}
//Count number of polyline pts, tube pts and tube cells
vtkm::cont::ArrayHandle<vtkm::Id> ptsPerPolyline, ptsPerTube, numTubeConnIds;
vtkm::cont::ArrayHandle<vtkm::Id> ptsPerPolyline, ptsPerTube, numTubeConnIds, segPerPolyline;
CountSegments countSegs(this->Capping, this->NumSides);
vtkm::worklet::DispatcherMapTopology<CountSegments> countInvoker(countSegs);
countInvoker.Invoke(cellset, ptsPerPolyline, ptsPerTube, numTubeConnIds);
countInvoker.Invoke(cellset, ptsPerPolyline, ptsPerTube, numTubeConnIds, segPerPolyline);
vtkm::Id totalPolylinePts = vtkm::cont::Algorithm::Reduce(ptsPerPolyline, vtkm::Id(0));
if (totalPolylinePts == 0)
throw vtkm::cont::ErrorBadValue("Tube filter only supported for polyline data.");
vtkm::Id totalTubePts = vtkm::cont::Algorithm::Reduce(ptsPerTube, vtkm::Id(0));
vtkm::Id totalTubeConnIds = vtkm::cont::Algorithm::Reduce(numTubeConnIds, vtkm::Id(0));
//All cells are triangles, so cell count is simple to compute.
vtkm::Id totalTubeCells = totalTubeConnIds / 3;
vtkm::cont::ArrayHandle<vtkm::Id> polylineOffset, tubePointOffsets, tubeConnOffsets;
vtkm::cont::Algorithm::ScanExclusive(ptsPerPolyline, polylineOffset);
vtkm::cont::ArrayHandle<vtkm::Id> polylinePtOffset, tubePointOffsets, tubeConnOffsets,
segOffset;
vtkm::cont::Algorithm::ScanExclusive(ptsPerPolyline, polylinePtOffset);
vtkm::cont::Algorithm::ScanExclusive(ptsPerTube, tubePointOffsets);
vtkm::cont::Algorithm::ScanExclusive(numTubeConnIds, tubeConnOffsets);
vtkm::cont::Algorithm::ScanExclusive(segPerPolyline, segOffset);
//Generate normals at each point on all polylines
ExplCoordsType inCoords = coords.GetData().Cast<ExplCoordsType>();
NormalsType normals;
normals.Allocate(totalPolylinePts);
vtkm::worklet::DispatcherMapTopology<GenerateNormals> genNormalsDisp;
genNormalsDisp.Invoke(cellset, inCoords, polylineOffset, normals);
genNormalsDisp.Invoke(cellset, inCoords, polylinePtOffset, normals);
//Generate the tube points
newPoints.Allocate(totalTubePts);
this->OutputPointSourceIndex.Allocate(totalTubePts);
GeneratePoints genPts(this->Capping, this->NumSides, this->Radius);
vtkm::worklet::DispatcherMapTopology<GeneratePoints> genPtsDisp(genPts);
genPtsDisp.Invoke(cellset, inCoords, normals, tubePointOffsets, polylineOffset, newPoints);
genPtsDisp.Invoke(cellset,
inCoords,
normals,
tubePointOffsets,
polylinePtOffset,
newPoints,
this->OutputPointSourceIndex);
//Generate tube cells
vtkm::cont::ArrayHandle<vtkm::Id> newConnectivity;
newConnectivity.Allocate(totalTubeConnIds);
this->OutputCellSourceIndex.Allocate(totalTubeCells);
GenerateCells genCells(this->Capping, this->NumSides);
vtkm::worklet::DispatcherMapTopology<GenerateCells> genCellsDisp(genCells);
genCellsDisp.Invoke(cellset, tubePointOffsets, tubeConnOffsets, newConnectivity);
genCellsDisp.Invoke(cellset,
tubePointOffsets,
tubeConnOffsets,
segOffset,
newConnectivity,
this->OutputCellSourceIndex);
newCells.Fill(totalTubePts, vtkm::CELL_SHAPE_TRIANGLE, 3, newConnectivity);
}
template <typename T, typename StorageType>
vtkm::cont::ArrayHandle<T> ProcessPointField(
const vtkm::cont::ArrayHandle<T, StorageType>& input) const
{
vtkm::cont::ArrayHandle<T> output;
vtkm::worklet::DispatcherMapField<MapField> mapFieldDisp;
output.Allocate(this->OutputPointSourceIndex.GetNumberOfValues());
mapFieldDisp.Invoke(this->OutputPointSourceIndex, input, output);
return output;
}
template <typename T, typename StorageType>
vtkm::cont::ArrayHandle<T> ProcessCellField(
const vtkm::cont::ArrayHandle<T, StorageType>& input) const
{
vtkm::cont::ArrayHandle<T> output;
vtkm::worklet::DispatcherMapField<MapField> mapFieldDisp;
output.Allocate(this->OutputCellSourceIndex.GetNumberOfValues());
mapFieldDisp.Invoke(this->OutputCellSourceIndex, input, output);
return output;
}
private:
bool Capping;
vtkm::Id NumSides;
vtkm::FloatDefault Radius;
vtkm::cont::ArrayHandle<vtkm::Id> OutputCellSourceIndex;
vtkm::cont::ArrayHandle<vtkm::Id> OutputPointSourceIndex;
};
}
}