2022-02-02 02:45:07 +00:00
|
|
|
//============================================================================
|
|
|
|
// Copyright (c) Kitware, Inc.
|
|
|
|
// All rights reserved.
|
|
|
|
// See LICENSE.txt 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.
|
|
|
|
//============================================================================
|
2022-01-05 20:30:40 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleGroupVec.h>
|
|
|
|
#include <vtkm/cont/CellSetSingleType.h>
|
|
|
|
#include <vtkm/cont/Initialize.h>
|
|
|
|
|
|
|
|
#include <vtkm/exec/CellEdge.h>
|
|
|
|
|
|
|
|
#include <vtkm/worklet/AverageByKey.h>
|
|
|
|
#include <vtkm/worklet/Keys.h>
|
|
|
|
#include <vtkm/worklet/ScatterCounting.h>
|
|
|
|
|
2022-02-07 20:34:18 +00:00
|
|
|
#include <vtkm/io/VTKDataSetReader.h>
|
|
|
|
#include <vtkm/io/VTKDataSetWriter.h>
|
2022-01-05 20:30:40 +00:00
|
|
|
|
2022-12-01 20:07:56 +00:00
|
|
|
#include <vtkm/filter/Filter.h>
|
2022-05-26 18:52:08 +00:00
|
|
|
#include <vtkm/filter/MapFieldMergeAverage.h>
|
|
|
|
#include <vtkm/filter/MapFieldPermutation.h>
|
2022-02-07 20:34:18 +00:00
|
|
|
#include <vtkm/filter/contour/Contour.h>
|
|
|
|
#include <vtkm/worklet/WorkletMapTopology.h>
|
2022-01-05 20:30:40 +00:00
|
|
|
|
2022-02-11 15:22:48 +00:00
|
|
|
namespace
|
2022-01-05 20:30:40 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
struct CountEdgesWorklet : vtkm::worklet::WorkletVisitCellsWithPoints
|
|
|
|
{
|
|
|
|
using ControlSignature = void(CellSetIn cellSet, FieldOut numEdges);
|
|
|
|
using ExecutionSignature = _2(CellShape, PointCount);
|
|
|
|
|
|
|
|
template <typename CellShapeTag>
|
2022-10-12 00:23:44 +00:00
|
|
|
VTKM_EXEC vtkm::IdComponent operator()(CellShapeTag cellShape,
|
|
|
|
vtkm::IdComponent numPointsInCell) const
|
2022-01-05 20:30:40 +00:00
|
|
|
{
|
|
|
|
vtkm::IdComponent numEdges;
|
|
|
|
vtkm::exec::CellEdgeNumberOfEdges(numPointsInCell, cellShape, numEdges);
|
|
|
|
return numEdges;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct EdgeIdsWorklet : vtkm::worklet::WorkletVisitCellsWithPoints
|
|
|
|
{
|
|
|
|
using ControlSignature = void(CellSetIn cellSet, FieldOut canonicalIds);
|
|
|
|
using ExecutionSignature = void(CellShape cellShape,
|
|
|
|
PointIndices globalPointIndices,
|
|
|
|
VisitIndex localEdgeIndex,
|
|
|
|
_2 canonicalIdOut);
|
|
|
|
|
|
|
|
using ScatterType = vtkm::worklet::ScatterCounting;
|
|
|
|
|
|
|
|
template <typename CellShapeTag, typename PointIndexVecType>
|
|
|
|
VTKM_EXEC void operator()(CellShapeTag cellShape,
|
|
|
|
const PointIndexVecType& globalPointIndicesForCell,
|
|
|
|
vtkm::IdComponent localEdgeIndex,
|
|
|
|
vtkm::Id2& canonicalIdOut) const
|
|
|
|
{
|
|
|
|
vtkm::IdComponent numPointsInCell = globalPointIndicesForCell.GetNumberOfComponents();
|
|
|
|
|
|
|
|
vtkm::exec::CellEdgeCanonicalId(
|
|
|
|
numPointsInCell, localEdgeIndex, cellShape, globalPointIndicesForCell, canonicalIdOut);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct EdgeIndicesWorklet : vtkm::worklet::WorkletReduceByKey
|
|
|
|
{
|
|
|
|
using ControlSignature = void(KeysIn keys,
|
|
|
|
WholeCellSetIn<> inputCells,
|
|
|
|
ValuesIn originCells,
|
|
|
|
ValuesIn originEdges,
|
|
|
|
ReducedValuesOut connectivityOut);
|
|
|
|
using ExecutionSignature = void(_2 inputCells, _3 originCell, _4 originEdge, _5 connectivityOut);
|
|
|
|
using InputDomain = _1;
|
|
|
|
|
|
|
|
template <typename CellSetType, typename OriginCellsType, typename OriginEdgesType>
|
|
|
|
VTKM_EXEC void operator()(const CellSetType& cellSet,
|
|
|
|
const OriginCellsType& originCells,
|
|
|
|
const OriginEdgesType& originEdges,
|
|
|
|
vtkm::Id2& connectivityOut) const
|
|
|
|
{
|
|
|
|
// Regardless of how many cells are sharing the edge we are generating, we
|
|
|
|
// know that each cell/edge given to us by the reduce-by-key refers to the
|
|
|
|
// same edge, so we can just look at the first cell to get the edge.
|
|
|
|
vtkm::IdComponent numPointsInCell = cellSet.GetNumberOfIndices(originCells[0]);
|
|
|
|
vtkm::IdComponent edgeIndex = originEdges[0];
|
|
|
|
auto cellShape = cellSet.GetCellShape(originCells[0]);
|
|
|
|
|
2022-02-14 18:11:30 +00:00
|
|
|
vtkm::ErrorCode error;
|
2022-01-05 20:30:40 +00:00
|
|
|
vtkm::IdComponent pointInCellIndex0;
|
2022-02-14 18:11:30 +00:00
|
|
|
error =
|
|
|
|
vtkm::exec::CellEdgeLocalIndex(numPointsInCell, 0, edgeIndex, cellShape, pointInCellIndex0);
|
|
|
|
if (error != vtkm::ErrorCode::Success)
|
|
|
|
{
|
2022-02-14 18:15:55 +00:00
|
|
|
this->RaiseError(vtkm::ErrorString(error));
|
|
|
|
return;
|
2022-02-14 18:11:30 +00:00
|
|
|
}
|
2022-01-05 20:30:40 +00:00
|
|
|
vtkm::IdComponent pointInCellIndex1;
|
2022-02-14 18:11:30 +00:00
|
|
|
error =
|
|
|
|
vtkm::exec::CellEdgeLocalIndex(numPointsInCell, 1, edgeIndex, cellShape, pointInCellIndex1);
|
|
|
|
if (error != vtkm::ErrorCode::Success)
|
|
|
|
{
|
2022-02-14 18:15:55 +00:00
|
|
|
this->RaiseError(vtkm::ErrorString(error));
|
|
|
|
return;
|
2022-02-14 18:11:30 +00:00
|
|
|
}
|
2022-01-05 20:30:40 +00:00
|
|
|
|
|
|
|
auto globalPointIndicesForCell = cellSet.GetIndices(originCells[0]);
|
|
|
|
connectivityOut[0] = globalPointIndicesForCell[pointInCellIndex0];
|
|
|
|
connectivityOut[1] = globalPointIndicesForCell[pointInCellIndex1];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-02-11 15:22:48 +00:00
|
|
|
}
|
2022-01-05 20:30:40 +00:00
|
|
|
|
2022-02-11 15:22:48 +00:00
|
|
|
namespace
|
2022-01-05 20:30:40 +00:00
|
|
|
{
|
|
|
|
|
2022-05-26 18:52:08 +00:00
|
|
|
VTKM_CONT bool DoMapField(
|
|
|
|
vtkm::cont::DataSet& result,
|
|
|
|
const vtkm::cont::Field& inputField,
|
2022-10-12 00:23:44 +00:00
|
|
|
const vtkm::worklet::ScatterCounting::OutputToInputMapType& outputToInputCellMap,
|
|
|
|
const vtkm::worklet::Keys<vtkm::Id2>& cellToEdgeKeys)
|
2022-01-05 20:30:40 +00:00
|
|
|
{
|
2022-05-26 18:52:08 +00:00
|
|
|
vtkm::cont::Field outputField;
|
2022-01-05 20:30:40 +00:00
|
|
|
|
2022-08-29 18:42:02 +00:00
|
|
|
if (inputField.IsPointField())
|
2022-05-26 18:52:08 +00:00
|
|
|
{
|
|
|
|
outputField = inputField; // pass through
|
|
|
|
}
|
2022-08-29 18:42:02 +00:00
|
|
|
else if (inputField.IsCellField())
|
2022-05-26 18:52:08 +00:00
|
|
|
{
|
|
|
|
vtkm::cont::Field permuted;
|
2022-10-12 00:23:44 +00:00
|
|
|
vtkm::filter::MapFieldPermutation(inputField, outputToInputCellMap, permuted);
|
|
|
|
vtkm::filter::MapFieldMergeAverage(permuted, cellToEdgeKeys, outputField);
|
2022-05-26 18:52:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2022-01-05 20:30:40 +00:00
|
|
|
|
2022-05-26 18:52:08 +00:00
|
|
|
result.AddField(outputField);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-12 00:23:44 +00:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2022-12-01 20:07:56 +00:00
|
|
|
class ExtractEdges : public vtkm::filter::Filter
|
2022-05-26 18:52:08 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inData) override;
|
2022-01-05 20:30:40 +00:00
|
|
|
};
|
|
|
|
|
2022-05-26 18:52:08 +00:00
|
|
|
VTKM_CONT vtkm::cont::DataSet ExtractEdges::DoExecute(const vtkm::cont::DataSet& inData)
|
2022-01-05 20:30:40 +00:00
|
|
|
{
|
2022-05-26 18:52:08 +00:00
|
|
|
auto inCellSet = inData.GetCellSet();
|
2022-01-05 20:30:40 +00:00
|
|
|
|
|
|
|
// First, count the edges in each cell.
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::IdComponent> edgeCounts;
|
2022-02-11 15:22:48 +00:00
|
|
|
this->Invoke(CountEdgesWorklet{}, inCellSet, edgeCounts);
|
2022-01-05 20:30:40 +00:00
|
|
|
|
|
|
|
// Second, using these counts build a scatter that repeats a cell's visit
|
|
|
|
// for each edge in the cell.
|
|
|
|
vtkm::worklet::ScatterCounting scatter(edgeCounts);
|
2022-10-12 00:23:44 +00:00
|
|
|
vtkm::worklet::ScatterCounting::OutputToInputMapType outputToInputCellMap;
|
|
|
|
outputToInputCellMap = scatter.GetOutputToInputMap(inCellSet.GetNumberOfCells());
|
2022-01-05 20:30:40 +00:00
|
|
|
vtkm::worklet::ScatterCounting::VisitArrayType outputToInputEdgeMap =
|
|
|
|
scatter.GetVisitArray(inCellSet.GetNumberOfCells());
|
|
|
|
|
|
|
|
// Third, for each edge, extract a canonical id.
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id2> canonicalIds;
|
2022-02-11 15:22:48 +00:00
|
|
|
this->Invoke(EdgeIdsWorklet{}, scatter, inCellSet, canonicalIds);
|
2022-01-05 20:30:40 +00:00
|
|
|
|
|
|
|
// Fourth, construct a Keys object to combine all like edge ids.
|
2022-10-12 00:23:44 +00:00
|
|
|
vtkm::worklet::Keys<vtkm::Id2> cellToEdgeKeys;
|
|
|
|
cellToEdgeKeys = vtkm::worklet::Keys<vtkm::Id2>(canonicalIds);
|
2022-01-05 20:30:40 +00:00
|
|
|
|
|
|
|
// Fifth, use a reduce-by-key to extract indices for each unique edge.
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> connectivityArray;
|
2022-02-11 15:22:48 +00:00
|
|
|
this->Invoke(EdgeIndicesWorklet{},
|
2022-10-12 00:23:44 +00:00
|
|
|
cellToEdgeKeys,
|
2022-01-05 20:30:40 +00:00
|
|
|
inCellSet,
|
2022-10-12 00:23:44 +00:00
|
|
|
outputToInputCellMap,
|
2022-01-05 20:30:40 +00:00
|
|
|
outputToInputEdgeMap,
|
|
|
|
vtkm::cont::make_ArrayHandleGroupVec<2>(connectivityArray));
|
|
|
|
|
|
|
|
// Sixth, use the created connectivity array to build a cell set.
|
|
|
|
vtkm::cont::CellSetSingleType<> outCellSet;
|
|
|
|
outCellSet.Fill(inCellSet.GetNumberOfPoints(), vtkm::CELL_SHAPE_LINE, 2, connectivityArray);
|
|
|
|
|
2022-05-26 18:52:08 +00:00
|
|
|
auto mapper = [&](auto& outDataSet, const auto& f) {
|
2022-10-12 00:23:44 +00:00
|
|
|
DoMapField(outDataSet, f, outputToInputCellMap, cellToEdgeKeys);
|
2022-05-26 18:52:08 +00:00
|
|
|
};
|
2022-10-31 17:22:37 +00:00
|
|
|
return this->CreateResult(inData, outCellSet, mapper);
|
2022-01-05 20:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
|
|
{
|
|
|
|
auto opts = vtkm::cont::InitializeOptions::DefaultAnyDevice;
|
|
|
|
vtkm::cont::InitializeResult config = vtkm::cont::Initialize(argc, argv, opts);
|
|
|
|
|
|
|
|
const char* input = "data/kitchen.vtk";
|
|
|
|
vtkm::io::VTKDataSetReader reader(input);
|
|
|
|
vtkm::cont::DataSet ds_from_file = reader.ReadDataSet();
|
|
|
|
|
2022-02-07 20:34:18 +00:00
|
|
|
vtkm::filter::contour::Contour contour;
|
2022-01-05 20:30:40 +00:00
|
|
|
contour.SetActiveField("c1");
|
|
|
|
contour.SetIsoValue(0.10);
|
|
|
|
vtkm::cont::DataSet ds_from_contour = contour.Execute(ds_from_file);
|
|
|
|
|
2022-02-11 15:22:48 +00:00
|
|
|
ExtractEdges extractEdges;
|
2022-01-05 20:30:40 +00:00
|
|
|
vtkm::cont::DataSet wireframe = extractEdges.Execute(ds_from_contour);
|
|
|
|
|
|
|
|
vtkm::io::VTKDataSetWriter writer("out_wireframe.vtk");
|
|
|
|
writer.WriteDataSet(wireframe);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|