Allow external cellsets to be used by TriangleWinding worklet.

This commit is contained in:
Allison Vacanti 2019-08-09 15:04:46 -04:00
parent 19344416da
commit b3df7da222

@ -23,8 +23,16 @@
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleGroupVec.h>
#include <vtkm/cont/ArrayHandleGroupVecVariable.h>
#include <vtkm/cont/ArrayRangeCompute.h>
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/CellSetSingleType.h>
#include <vtkm/cont/DynamicCellSet.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/MaskIndices.h>
@ -48,6 +56,7 @@ namespace worklet
class TriangleWinding
{
public:
// Used by Explicit and SingleType specializations
struct WorkletWindToCellNormals : public WorkletMapField
{
using ControlSignature = void(FieldIn cellNormals, FieldInOut cellPoints, WholeArrayIn coords);
@ -82,10 +91,170 @@ public:
}
};
// Used by generic implementations:
struct WorkletGetCellShapesAndSizes : public WorkletVisitCellsWithPoints
{
using ControlSignature = void(CellSetIn cells, FieldOutCell shapes, FieldOutCell sizes);
using ExecutionSignature = void(CellShape, PointCount, _2, _3);
template <typename CellShapeTag>
VTKM_EXEC void operator()(const CellShapeTag cellShapeIn,
const vtkm::IdComponent cellSizeIn,
vtkm::UInt8& cellShapeOut,
vtkm::IdComponent& cellSizeOut) const
{
cellSizeOut = cellSizeIn;
cellShapeOut = cellShapeIn.Id;
}
};
struct WorkletWindToCellNormalsGeneric : public WorkletVisitCellsWithPoints
{
using ControlSignature = void(CellSetIn cellsIn,
WholeArrayIn coords,
FieldInCell cellNormals,
FieldOutCell cellsOut);
using ExecutionSignature = void(PointIndices, _2, _3, _4);
template <typename InputIds, typename Coords, typename Normal, typename OutputIds>
VTKM_EXEC void operator()(const InputIds& inputIds,
const Coords& coords,
const Normal& normal,
OutputIds& outputIds) const
{
VTKM_ASSERT(inputIds.GetNumberOfComponents() == outputIds.GetNumberOfComponents());
// We only care about triangles:
if (inputIds.GetNumberOfComponents() != 3)
{
// Just passthrough non-triangles
// Cannot just assign here, must do a manual component-wise copy to
// support VecFromPortal:
for (vtkm::IdComponent i = 0; i < inputIds.GetNumberOfComponents(); ++i)
{
outputIds[i] = inputIds[i];
}
return;
}
const Normal p0 = coords.Get(inputIds[0]);
const Normal p1 = coords.Get(inputIds[1]);
const Normal p2 = coords.Get(inputIds[2]);
const Normal v01 = p1 - p0;
const Normal v02 = p2 - p0;
const Normal triangleNormal = vtkm::Cross(v01, v02);
if (vtkm::Dot(normal, triangleNormal) < 0)
{ // Reorder triangle:
outputIds[0] = inputIds[0];
outputIds[1] = inputIds[2];
outputIds[2] = inputIds[1];
}
else
{ // passthrough:
outputIds[0] = inputIds[0];
outputIds[1] = inputIds[1];
outputIds[2] = inputIds[2];
}
}
};
struct Launcher
{
vtkm::cont::DynamicCellSet Result;
// Generic handler:
template <typename CellSetType,
typename PointComponentType,
typename PointStorageType,
typename CellNormalComponentType,
typename CellNormalStorageType>
VTKM_CONT void operator()(
const CellSetType& cellSet,
const vtkm::cont::ArrayHandle<vtkm::Vec<PointComponentType, 3>, PointStorageType>& coords,
const vtkm::cont::ArrayHandle<vtkm::Vec<CellNormalComponentType, 3>, CellNormalStorageType>&
cellNormals,
...)
{
const auto numCells = cellSet.GetNumberOfCells();
if (numCells == 0)
{
this->Result = cellSet;
return;
}
vtkm::cont::Invoker invoker;
// Get each cell's size:
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices;
vtkm::cont::ArrayHandle<vtkm::UInt8> cellShapes;
{
WorkletGetCellShapesAndSizes worklet;
invoker(worklet, cellSet, cellShapes, numIndices);
}
// Check to see if we can use CellSetSingleType:
vtkm::IdComponent cellSize = 0; // 0 if heterogeneous, >0 if homogeneous
vtkm::UInt8 cellShape = 0; // only valid if homogeneous
{
auto rangeHandleSizes = vtkm::cont::ArrayRangeCompute(numIndices);
auto rangeHandleShapes = vtkm::cont::ArrayRangeCompute(cellShapes);
cellShapes.ReleaseResourcesExecution();
auto rangeSizes = rangeHandleSizes.GetPortalConstControl().Get(0);
auto rangeShapes = rangeHandleShapes.GetPortalConstControl().Get(0);
const bool sameSize = vtkm::Abs(rangeSizes.Max - rangeSizes.Min) < 0.5;
const bool sameShape = vtkm::Abs(rangeShapes.Max - rangeShapes.Min) < 0.5;
if (sameSize && sameShape)
{
cellSize = static_cast<vtkm::IdComponent>(rangeSizes.Min + 0.5);
cellShape = static_cast<vtkm::UInt8>(rangeShapes.Min + 0.5);
}
}
if (cellSize > 0)
{ // Single cell type:
// don't need these anymore:
numIndices.ReleaseResources();
cellShapes.ReleaseResources();
vtkm::cont::ArrayHandle<vtkm::Id> conn;
conn.Allocate(cellSize * numCells);
auto offsets = vtkm::cont::make_ArrayHandleCounting<vtkm::Id>(0, cellSize, numCells);
auto connGroupVec = vtkm::cont::make_ArrayHandleGroupVecVariable(conn, offsets);
WorkletWindToCellNormalsGeneric worklet;
invoker(worklet, cellSet, coords, cellNormals, connGroupVec);
vtkm::cont::CellSetSingleType<> outCells;
outCells.Fill(cellSet.GetNumberOfPoints(), cellShape, cellSize, conn);
this->Result = outCells;
}
else
{ // Multiple cell types:
vtkm::cont::ArrayHandle<vtkm::Id> offsets;
vtkm::Id connSize;
vtkm::cont::ConvertNumComponentsToOffsets(numIndices, offsets, connSize);
numIndices.ReleaseResourcesExecution();
vtkm::cont::ArrayHandle<vtkm::Id> conn;
conn.Allocate(connSize);
auto connGroupVec = vtkm::cont::make_ArrayHandleGroupVecVariable(conn, offsets);
WorkletWindToCellNormalsGeneric worklet;
invoker(worklet, cellSet, coords, cellNormals, connGroupVec);
vtkm::cont::CellSetExplicit<> outCells;
outCells.Fill(cellSet.GetNumberOfPoints(), cellShapes, numIndices, conn, offsets);
this->Result = outCells;
}
}
// Specialization for CellSetExplicit
template <typename S,
typename N,
typename C,
@ -98,10 +267,18 @@ public:
const vtkm::cont::CellSetExplicit<S, N, C, O>& cellSet,
const vtkm::cont::ArrayHandle<vtkm::Vec<PointComponentType, 3>, PointStorageType>& coords,
const vtkm::cont::ArrayHandle<vtkm::Vec<CellNormalComponentType, 3>, CellNormalStorageType>&
cellNormals)
cellNormals,
int)
{
using WindToCellNormals = vtkm::worklet::DispatcherMapField<WorkletWindToCellNormals>;
const auto numCells = cellSet.GetNumberOfCells();
if (numCells == 0)
{
this->Result = cellSet;
return;
}
vtkm::cont::ArrayHandle<vtkm::Id> conn;
{
const auto& connIn = cellSet.GetConnectivityArray(vtkm::TopologyElementTagCell{},
@ -126,6 +303,7 @@ public:
this->Result = newCells;
}
// Specialization for CellSetSingleType
template <typename C,
typename PointComponentType,
typename PointStorageType,
@ -135,10 +313,18 @@ public:
const vtkm::cont::CellSetSingleType<C>& cellSet,
const vtkm::cont::ArrayHandle<vtkm::Vec<PointComponentType, 3>, PointStorageType>& coords,
const vtkm::cont::ArrayHandle<vtkm::Vec<CellNormalComponentType, 3>, CellNormalStorageType>&
cellNormals)
cellNormals,
int)
{
using WindToCellNormals = vtkm::worklet::DispatcherMapField<WorkletWindToCellNormals>;
const auto numCells = cellSet.GetNumberOfCells();
if (numCells == 0)
{
this->Result = cellSet;
return;
}
vtkm::cont::ArrayHandle<vtkm::Id> conn;
{
const auto& connIn = cellSet.GetConnectivityArray(vtkm::TopologyElementTagCell{},
@ -175,7 +361,10 @@ public:
cellNormals)
{
Launcher launcher;
vtkm::cont::CastAndCall(cellSet, launcher, coords, cellNormals);
// The last arg is just to help with overload resolution on the templated
// Launcher::operator() method, so that the more specialized impls are
// preferred over the generic one.
vtkm::cont::CastAndCall(cellSet, launcher, coords, cellNormals, 0);
return launcher.Result;
}
};