2015-11-16 19:21: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.
|
|
|
|
//
|
2017-09-20 21:33:44 +00:00
|
|
|
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
|
2015-11-16 19:21:07 +00:00
|
|
|
// Copyright 2014 UT-Battelle, LLC.
|
|
|
|
// Copyright 2014 Los Alamos National Security.
|
|
|
|
//
|
2017-09-20 21:33:44 +00:00
|
|
|
// Under the terms of Contract DE-NA0003525 with NTESS,
|
2015-11-16 19:21:07 +00:00
|
|
|
// the U.S. Government retains certain rights in this software.
|
|
|
|
//
|
|
|
|
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
|
|
|
|
// Laboratory (LANL), the U.S. Government retains certain rights in
|
|
|
|
// this software.
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
#ifndef vtk_m_worklet_MarchingCubes_h
|
|
|
|
#define vtk_m_worklet_MarchingCubes_h
|
|
|
|
|
2017-03-24 20:12:05 +00:00
|
|
|
#include <vtkm/BinaryPredicates.h>
|
2017-05-18 14:51:24 +00:00
|
|
|
#include <vtkm/VectorAnalysis.h>
|
2015-11-16 19:21:07 +00:00
|
|
|
|
|
|
|
#include <vtkm/exec/CellDerivative.h>
|
|
|
|
#include <vtkm/exec/ParametricCoordinates.h>
|
|
|
|
|
2018-08-30 15:53:18 +00:00
|
|
|
#include <vtkm/cont/ArrayCopy.h>
|
2015-11-16 19:21:07 +00:00
|
|
|
#include <vtkm/cont/ArrayHandle.h>
|
|
|
|
#include <vtkm/cont/ArrayHandleCompositeVector.h>
|
|
|
|
#include <vtkm/cont/ArrayHandleGroupVec.h>
|
|
|
|
#include <vtkm/cont/ArrayHandleIndex.h>
|
|
|
|
#include <vtkm/cont/ArrayHandlePermutation.h>
|
2017-06-19 15:56:17 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleTransform.h>
|
2016-07-21 20:54:33 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleZip.h>
|
2017-04-12 21:00:22 +00:00
|
|
|
#include <vtkm/cont/CellSetPermutation.h>
|
2015-11-16 19:21:07 +00:00
|
|
|
#include <vtkm/cont/DataSet.h>
|
|
|
|
#include <vtkm/cont/Field.h>
|
|
|
|
|
|
|
|
#include <vtkm/worklet/DispatcherMapTopology.h>
|
2017-08-08 20:31:18 +00:00
|
|
|
#include <vtkm/worklet/DispatcherPointNeighborhood.h>
|
2017-05-05 19:15:42 +00:00
|
|
|
#include <vtkm/worklet/DispatcherReduceByKey.h>
|
|
|
|
#include <vtkm/worklet/Keys.h>
|
2015-11-16 19:21:07 +00:00
|
|
|
#include <vtkm/worklet/ScatterCounting.h>
|
2017-06-19 15:56:17 +00:00
|
|
|
#include <vtkm/worklet/ScatterPermutation.h>
|
2015-11-16 19:21:07 +00:00
|
|
|
#include <vtkm/worklet/WorkletMapTopology.h>
|
2017-08-08 20:31:18 +00:00
|
|
|
#include <vtkm/worklet/WorkletPointNeighborhood.h>
|
2017-05-05 19:15:42 +00:00
|
|
|
#include <vtkm/worklet/WorkletReduceByKey.h>
|
2015-11-16 19:21:07 +00:00
|
|
|
|
2017-08-08 20:31:18 +00:00
|
|
|
#include <vtkm/worklet/contour/DataTables.h>
|
|
|
|
#include <vtkm/worklet/gradient/PointGradient.h>
|
|
|
|
#include <vtkm/worklet/gradient/StructuredPointGradient.h>
|
2015-11-16 19:21:07 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace worklet
|
|
|
|
{
|
2016-07-20 16:40:03 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
namespace marchingcubes
|
|
|
|
{
|
2017-03-14 12:56:44 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T>
|
|
|
|
struct float_type
|
|
|
|
{
|
|
|
|
using type = vtkm::FloatDefault;
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct float_type<vtkm::Float32>
|
|
|
|
{
|
|
|
|
using type = vtkm::Float32;
|
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct float_type<vtkm::Float64>
|
|
|
|
{
|
|
|
|
using type = vtkm::Float64;
|
|
|
|
};
|
2017-03-14 12:56:44 +00:00
|
|
|
|
2016-07-21 20:54:33 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename S>
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Float32, S> make_ScalarField(
|
|
|
|
const vtkm::cont::ArrayHandle<vtkm::Float32, S>& ah)
|
|
|
|
{
|
|
|
|
return ah;
|
|
|
|
}
|
2016-07-21 20:54:33 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename S>
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Float64, S> make_ScalarField(
|
|
|
|
const vtkm::cont::ArrayHandle<vtkm::Float64, S>& ah)
|
|
|
|
{
|
|
|
|
return ah;
|
|
|
|
}
|
2016-07-21 20:54:33 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename S>
|
|
|
|
vtkm::cont::ArrayHandleCast<vtkm::FloatDefault, vtkm::cont::ArrayHandle<vtkm::UInt8, S>>
|
|
|
|
make_ScalarField(const vtkm::cont::ArrayHandle<vtkm::UInt8, S>& ah)
|
|
|
|
{
|
|
|
|
return vtkm::cont::make_ArrayHandleCast(ah, vtkm::FloatDefault());
|
|
|
|
}
|
2016-07-21 20:54:33 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename S>
|
|
|
|
vtkm::cont::ArrayHandleCast<vtkm::FloatDefault, vtkm::cont::ArrayHandle<vtkm::Int8, S>>
|
|
|
|
make_ScalarField(const vtkm::cont::ArrayHandle<vtkm::Int8, S>& ah)
|
|
|
|
{
|
|
|
|
return vtkm::cont::make_ArrayHandleCast(ah, vtkm::FloatDefault());
|
|
|
|
}
|
2016-07-21 20:54:33 +00:00
|
|
|
|
2016-07-20 16:40:03 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T>
|
2016-07-20 16:40:03 +00:00
|
|
|
class ClassifyCell : public vtkm::worklet::WorkletMapPointToCell
|
|
|
|
{
|
|
|
|
public:
|
2017-05-18 14:29:41 +00:00
|
|
|
struct ClassifyCellTagType : vtkm::ListTagBase<T>
|
|
|
|
{
|
|
|
|
};
|
2016-07-21 20:54:33 +00:00
|
|
|
|
2019-01-10 18:59:25 +00:00
|
|
|
using ControlSignature = void(WholeArrayIn isoValues,
|
|
|
|
FieldInPoint fieldIn,
|
2017-05-26 17:53:28 +00:00
|
|
|
CellSetIn cellset,
|
2019-01-10 18:59:25 +00:00
|
|
|
FieldOutCell outNumTriangles,
|
|
|
|
WholeArrayIn numTrianglesTable);
|
2018-05-25 21:18:41 +00:00
|
|
|
using ExecutionSignature = void(CellShape, _1, _2, _4, _5);
|
2018-02-22 13:29:13 +00:00
|
|
|
using InputDomain = _3;
|
2016-07-20 16:40:03 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename IsoValuesType, typename FieldInType, typename NumTrianglesTablePortalType>
|
2017-05-26 17:53:28 +00:00
|
|
|
VTKM_EXEC void operator()(vtkm::CellShapeTagGeneric shape,
|
|
|
|
const IsoValuesType& isovalues,
|
|
|
|
const FieldInType& fieldIn,
|
|
|
|
vtkm::IdComponent& numTriangles,
|
2017-05-18 14:29:41 +00:00
|
|
|
const NumTrianglesTablePortalType& numTrianglesTable) const
|
2017-03-09 14:40:21 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
if (shape.Id == CELL_SHAPE_HEXAHEDRON)
|
2017-03-14 12:56:44 +00:00
|
|
|
{
|
2017-05-26 17:53:28 +00:00
|
|
|
this->operator()(
|
|
|
|
vtkm::CellShapeTagHexahedron(), isovalues, fieldIn, numTriangles, numTrianglesTable);
|
2017-03-14 12:56:44 +00:00
|
|
|
}
|
2017-03-09 14:40:21 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
numTriangles = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename IsoValuesType, typename FieldInType, typename NumTrianglesTablePortalType>
|
|
|
|
VTKM_EXEC void operator()(vtkm::CellShapeTagQuad vtkmNotUsed(shape),
|
|
|
|
const IsoValuesType& vtkmNotUsed(isovalues),
|
|
|
|
const FieldInType& vtkmNotUsed(fieldIn),
|
|
|
|
vtkm::IdComponent& vtkmNotUsed(numTriangles),
|
|
|
|
const NumTrianglesTablePortalType& vtkmNotUsed(numTrianglesTable)) const
|
2017-03-09 14:40:21 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename IsoValuesType, typename FieldInType, typename NumTrianglesTablePortalType>
|
|
|
|
VTKM_EXEC void operator()(vtkm::CellShapeTagHexahedron vtkmNotUsed(shape),
|
2017-05-26 17:53:28 +00:00
|
|
|
const IsoValuesType& isovalues,
|
|
|
|
const FieldInType& fieldIn,
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::IdComponent& numTriangles,
|
|
|
|
const NumTrianglesTablePortalType& numTrianglesTable) const
|
2016-07-20 16:40:03 +00:00
|
|
|
{
|
2017-03-14 12:56:44 +00:00
|
|
|
vtkm::IdComponent sum = 0;
|
2017-05-18 14:29:41 +00:00
|
|
|
for (vtkm::Id i = 0; i < isovalues.GetNumberOfValues(); ++i)
|
2017-03-14 12:56:44 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
const vtkm::IdComponent caseNumber =
|
|
|
|
((fieldIn[0] > isovalues[i]) | (fieldIn[1] > isovalues[i]) << 1 |
|
|
|
|
(fieldIn[2] > isovalues[i]) << 2 | (fieldIn[3] > isovalues[i]) << 3 |
|
|
|
|
(fieldIn[4] > isovalues[i]) << 4 | (fieldIn[5] > isovalues[i]) << 5 |
|
|
|
|
(fieldIn[6] > isovalues[i]) << 6 | (fieldIn[7] > isovalues[i]) << 7);
|
|
|
|
sum += numTrianglesTable.Get(caseNumber);
|
2017-03-14 12:56:44 +00:00
|
|
|
}
|
|
|
|
numTriangles = sum;
|
2016-07-20 16:40:03 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-07-21 20:54:33 +00:00
|
|
|
/// \brief Used to store data need for the EdgeWeightGenerate worklet.
|
|
|
|
/// This information is not passed as part of the arguments to the worklet as
|
|
|
|
/// that dramatically increase compile time by 200%
|
|
|
|
// -----------------------------------------------------------------------------
|
2018-08-30 15:53:18 +00:00
|
|
|
class EdgeWeightGenerateMetaData : vtkm::cont::ExecutionObjectBase
|
2016-07-21 20:54:33 +00:00
|
|
|
{
|
2018-08-30 15:53:18 +00:00
|
|
|
public:
|
|
|
|
template <typename DeviceAdapter>
|
|
|
|
class ExecObject
|
2016-07-21 20:54:33 +00:00
|
|
|
{
|
2018-08-30 15:53:18 +00:00
|
|
|
template <typename FieldType>
|
|
|
|
struct PortalTypes
|
|
|
|
{
|
|
|
|
using HandleType = vtkm::cont::ArrayHandle<FieldType>;
|
|
|
|
using ExecutionTypes = typename HandleType::template ExecutionTypes<DeviceAdapter>;
|
|
|
|
|
|
|
|
using Portal = typename ExecutionTypes::Portal;
|
|
|
|
using PortalConst = typename ExecutionTypes::PortalConst;
|
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
|
|
|
ExecObject() = default;
|
|
|
|
|
|
|
|
VTKM_CONT
|
|
|
|
ExecObject(vtkm::Id size,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::FloatDefault>& interpWeights,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id2>& interpIds,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id>& interpCellIds,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::UInt8>& interpContourId,
|
|
|
|
const vtkm::cont::ArrayHandle<vtkm::IdComponent>& edgeTable,
|
|
|
|
const vtkm::cont::ArrayHandle<vtkm::IdComponent>& numTriTable,
|
|
|
|
const vtkm::cont::ArrayHandle<vtkm::IdComponent>& triTable)
|
|
|
|
: InterpWeightsPortal(interpWeights.PrepareForOutput(3 * size, DeviceAdapter()))
|
|
|
|
, InterpIdPortal(interpIds.PrepareForOutput(3 * size, DeviceAdapter()))
|
|
|
|
, InterpCellIdPortal(interpCellIds.PrepareForOutput(3 * size, DeviceAdapter()))
|
|
|
|
, InterpContourPortal(interpContourId.PrepareForOutput(3 * size, DeviceAdapter()))
|
|
|
|
, EdgeTable(edgeTable.PrepareForInput(DeviceAdapter()))
|
|
|
|
, NumTriTable(numTriTable.PrepareForInput(DeviceAdapter()))
|
|
|
|
, TriTable(triTable.PrepareForInput(DeviceAdapter()))
|
|
|
|
{
|
|
|
|
// Interp needs to be 3 times longer than size as they are per point of the
|
|
|
|
// output triangle
|
|
|
|
}
|
|
|
|
typename PortalTypes<vtkm::FloatDefault>::Portal InterpWeightsPortal;
|
|
|
|
typename PortalTypes<vtkm::Id2>::Portal InterpIdPortal;
|
|
|
|
typename PortalTypes<vtkm::Id>::Portal InterpCellIdPortal;
|
|
|
|
typename PortalTypes<vtkm::UInt8>::Portal InterpContourPortal;
|
|
|
|
typename PortalTypes<vtkm::IdComponent>::PortalConst EdgeTable;
|
|
|
|
typename PortalTypes<vtkm::IdComponent>::PortalConst NumTriTable;
|
|
|
|
typename PortalTypes<vtkm::IdComponent>::PortalConst TriTable;
|
2016-07-21 20:54:33 +00:00
|
|
|
};
|
|
|
|
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_CONT
|
2017-05-18 14:29:41 +00:00
|
|
|
EdgeWeightGenerateMetaData(vtkm::Id size,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::FloatDefault>& interpWeights,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id2>& interpIds,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id>& interpCellIds,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::UInt8>& interpContourId,
|
|
|
|
const vtkm::cont::ArrayHandle<vtkm::IdComponent>& edgeTable,
|
|
|
|
const vtkm::cont::ArrayHandle<vtkm::IdComponent>& numTriTable,
|
Move Scatter from Worklet to Dispatcher
Previously, when a Worklet needed a scatter, the scatter object was
stored in the Worklet object. That was problematic because that means
the Scatter, which is a control object, was shoved into the execution
environment.
To prevent that, move the Scatter into the Dispatcher object. The
worklet still declares a ScatterType alias, but no longer has a
GetScatter method. Instead, the Dispatcher now takes a Scatter object in
its constructor. If using the default scatter (ScatterIdentity), the
default constructor is used. If using another type of Scatter that
requires data to set up its state, then the caller of the worklet needs
to provide that to the dispatcher. For convenience, worklets are
encouraged to have a MakeScatter method to help construct a proper
scatter object.
2018-04-27 04:43:51 +00:00
|
|
|
const vtkm::cont::ArrayHandle<vtkm::IdComponent>& triTable)
|
2018-08-30 15:53:18 +00:00
|
|
|
: Size(size)
|
|
|
|
, InterpWeights(interpWeights)
|
|
|
|
, InterpIds(interpIds)
|
|
|
|
, InterpCellIds(interpCellIds)
|
|
|
|
, InterpContourId(interpContourId)
|
|
|
|
, EdgeTable(edgeTable)
|
|
|
|
, NumTriTable(numTriTable)
|
|
|
|
, TriTable(triTable)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename DeviceAdapter>
|
|
|
|
VTKM_CONT ExecObject<DeviceAdapter> PrepareForExecution(DeviceAdapter)
|
2016-07-21 20:54:33 +00:00
|
|
|
{
|
2018-08-30 15:53:18 +00:00
|
|
|
return ExecObject<DeviceAdapter>(this->Size,
|
|
|
|
this->InterpWeights,
|
|
|
|
this->InterpIds,
|
|
|
|
this->InterpCellIds,
|
|
|
|
this->InterpContourId,
|
|
|
|
this->EdgeTable,
|
|
|
|
this->NumTriTable,
|
|
|
|
this->TriTable);
|
2016-07-21 20:54:33 +00:00
|
|
|
}
|
2018-08-30 15:53:18 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
vtkm::Id Size;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::FloatDefault> InterpWeights;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id2> InterpIds;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> InterpCellIds;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::UInt8> InterpContourId;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::IdComponent> EdgeTable;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::IdComponent> NumTriTable;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::IdComponent> TriTable;
|
2016-07-21 20:54:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/// \brief Compute the weights for each edge that is used to generate
|
|
|
|
/// a point in the resulting iso-surface
|
|
|
|
// -----------------------------------------------------------------------------
|
2018-08-30 15:53:18 +00:00
|
|
|
template <typename T>
|
2016-07-21 20:54:33 +00:00
|
|
|
class EdgeWeightGenerate : public vtkm::worklet::WorkletMapPointToCell
|
|
|
|
{
|
|
|
|
public:
|
2017-05-18 14:29:41 +00:00
|
|
|
struct ClassifyCellTagType : vtkm::ListTagBase<T>
|
|
|
|
{
|
|
|
|
};
|
2017-03-14 12:56:44 +00:00
|
|
|
|
2018-02-22 13:29:13 +00:00
|
|
|
using ScatterType = vtkm::worklet::ScatterCounting;
|
2016-07-21 20:54:33 +00:00
|
|
|
|
Move Scatter from Worklet to Dispatcher
Previously, when a Worklet needed a scatter, the scatter object was
stored in the Worklet object. That was problematic because that means
the Scatter, which is a control object, was shoved into the execution
environment.
To prevent that, move the Scatter into the Dispatcher object. The
worklet still declares a ScatterType alias, but no longer has a
GetScatter method. Instead, the Dispatcher now takes a Scatter object in
its constructor. If using the default scatter (ScatterIdentity), the
default constructor is used. If using another type of Scatter that
requires data to set up its state, then the caller of the worklet needs
to provide that to the dispatcher. For convenience, worklets are
encouraged to have a MakeScatter method to help construct a proper
scatter object.
2018-04-27 04:43:51 +00:00
|
|
|
template <typename ArrayHandleType>
|
|
|
|
VTKM_CONT static ScatterType MakeScatter(const ArrayHandleType& numOutputTrisPerCell)
|
|
|
|
{
|
2018-08-30 15:53:18 +00:00
|
|
|
return ScatterType(numOutputTrisPerCell);
|
Move Scatter from Worklet to Dispatcher
Previously, when a Worklet needed a scatter, the scatter object was
stored in the Worklet object. That was problematic because that means
the Scatter, which is a control object, was shoved into the execution
environment.
To prevent that, move the Scatter into the Dispatcher object. The
worklet still declares a ScatterType alias, but no longer has a
GetScatter method. Instead, the Dispatcher now takes a Scatter object in
its constructor. If using the default scatter (ScatterIdentity), the
default constructor is used. If using another type of Scatter that
requires data to set up its state, then the caller of the worklet needs
to provide that to the dispatcher. For convenience, worklets are
encouraged to have a MakeScatter method to help construct a proper
scatter object.
2018-04-27 04:43:51 +00:00
|
|
|
}
|
|
|
|
|
2019-01-10 18:59:25 +00:00
|
|
|
typedef void ControlSignature(CellSetIn cellset, // Cell set
|
|
|
|
WholeArrayIn isoValues,
|
|
|
|
FieldInPoint fieldIn, // Input point field defining the contour
|
|
|
|
ExecObject metaData // Metadata for edge weight generation
|
|
|
|
);
|
2018-05-25 21:18:41 +00:00
|
|
|
using ExecutionSignature =
|
2018-08-30 15:53:18 +00:00
|
|
|
void(CellShape, _2, _3, _4, InputIndex, WorkIndex, VisitIndex, FromIndices);
|
2016-07-21 20:54:33 +00:00
|
|
|
|
2018-02-22 13:29:13 +00:00
|
|
|
using InputDomain = _1;
|
2016-07-21 20:54:33 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename IsoValuesType,
|
|
|
|
typename FieldInType, // Vec-like, one per input point
|
2018-08-30 15:53:18 +00:00
|
|
|
typename IndicesVecType,
|
|
|
|
typename DeviceAdapter>
|
2017-05-26 17:53:28 +00:00
|
|
|
VTKM_EXEC void operator()(vtkm::CellShapeTagGeneric shape,
|
|
|
|
const IsoValuesType& isovalues,
|
2017-05-18 14:29:41 +00:00
|
|
|
const FieldInType& fieldIn, // Input point field defining the contour
|
2018-08-30 15:53:18 +00:00
|
|
|
EdgeWeightGenerateMetaData::ExecObject<DeviceAdapter>& metaData,
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::Id inputCellId,
|
|
|
|
vtkm::Id outputCellId,
|
|
|
|
vtkm::IdComponent visitIndex,
|
|
|
|
const IndicesVecType& indices) const
|
2016-07-21 20:54:33 +00:00
|
|
|
{ //covers when we have hexs coming from unstructured data
|
2017-05-18 14:29:41 +00:00
|
|
|
if (shape.Id == CELL_SHAPE_HEXAHEDRON)
|
2017-03-14 12:56:44 +00:00
|
|
|
{
|
2017-05-26 17:53:28 +00:00
|
|
|
this->operator()(vtkm::CellShapeTagHexahedron(),
|
|
|
|
isovalues,
|
|
|
|
fieldIn,
|
2018-08-30 15:53:18 +00:00
|
|
|
metaData,
|
2017-05-26 17:53:28 +00:00
|
|
|
inputCellId,
|
|
|
|
outputCellId,
|
|
|
|
visitIndex,
|
|
|
|
indices);
|
2017-03-14 12:56:44 +00:00
|
|
|
}
|
2016-07-21 20:54:33 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename IsoValuesType,
|
|
|
|
typename FieldInType, // Vec-like, one per input point
|
2018-08-30 15:53:18 +00:00
|
|
|
typename IndicesVecType,
|
|
|
|
typename DeviceAdapter>
|
2017-05-18 14:29:41 +00:00
|
|
|
VTKM_EXEC void operator()(
|
2017-05-26 17:53:28 +00:00
|
|
|
CellShapeTagQuad vtkmNotUsed(shape),
|
|
|
|
const IsoValuesType& vtkmNotUsed(isovalues),
|
2017-05-18 14:29:41 +00:00
|
|
|
const FieldInType& vtkmNotUsed(fieldIn), // Input point field defining the contour
|
2018-08-30 15:53:18 +00:00
|
|
|
EdgeWeightGenerateMetaData::ExecObject<DeviceAdapter>& vtkmNotUsed(metaData),
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::Id vtkmNotUsed(inputCellId),
|
|
|
|
vtkm::Id vtkmNotUsed(outputCellId),
|
|
|
|
vtkm::IdComponent vtkmNotUsed(visitIndex),
|
|
|
|
const IndicesVecType& vtkmNotUsed(indices)) const
|
2016-07-21 20:54:33 +00:00
|
|
|
{ //covers when we have quads coming from 2d structured data
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename IsoValuesType,
|
|
|
|
typename FieldInType, // Vec-like, one per input point
|
2018-08-30 15:53:18 +00:00
|
|
|
typename IndicesVecType,
|
|
|
|
typename DeviceAdapter>
|
2017-05-26 17:53:28 +00:00
|
|
|
VTKM_EXEC void operator()(vtkm::CellShapeTagHexahedron,
|
|
|
|
const IsoValuesType& isovalues,
|
2017-05-18 14:29:41 +00:00
|
|
|
const FieldInType& fieldIn, // Input point field defining the contour
|
2018-08-30 15:53:18 +00:00
|
|
|
EdgeWeightGenerateMetaData::ExecObject<DeviceAdapter>& metaData,
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::Id inputCellId,
|
|
|
|
vtkm::Id outputCellId,
|
|
|
|
vtkm::IdComponent visitIndex,
|
|
|
|
const IndicesVecType& indices) const
|
2016-07-21 20:54:33 +00:00
|
|
|
{ //covers when we have hexs coming from 3d structured data
|
|
|
|
const vtkm::Id outputPointId = 3 * outputCellId;
|
2018-02-22 13:29:13 +00:00
|
|
|
using FieldType = typename vtkm::VecTraits<FieldInType>::ComponentType;
|
2017-03-14 12:56:44 +00:00
|
|
|
|
|
|
|
vtkm::IdComponent sum = 0, caseNumber = 0;
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::IdComponent i = 0, size = static_cast<vtkm::IdComponent>(isovalues.GetNumberOfValues());
|
|
|
|
for (i = 0; i < size; ++i)
|
2017-03-14 12:56:44 +00:00
|
|
|
{
|
2017-04-12 21:00:22 +00:00
|
|
|
const FieldType ivalue = isovalues[i];
|
2017-03-14 12:56:44 +00:00
|
|
|
// Compute the Marching Cubes case number for this cell. We need to iterate
|
|
|
|
// the isovalues until the sum >= our visit index. But we need to make
|
2018-01-30 00:24:31 +00:00
|
|
|
// sure the caseNumber is correct before stopping
|
2017-05-18 14:29:41 +00:00
|
|
|
caseNumber =
|
|
|
|
((fieldIn[0] > ivalue) | (fieldIn[1] > ivalue) << 1 | (fieldIn[2] > ivalue) << 2 |
|
|
|
|
(fieldIn[3] > ivalue) << 3 | (fieldIn[4] > ivalue) << 4 | (fieldIn[5] > ivalue) << 5 |
|
|
|
|
(fieldIn[6] > ivalue) << 6 | (fieldIn[7] > ivalue) << 7);
|
2018-08-30 15:53:18 +00:00
|
|
|
sum += metaData.NumTriTable.Get(caseNumber);
|
2017-05-18 14:29:41 +00:00
|
|
|
if (sum > visitIndex)
|
2017-03-14 12:56:44 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
visitIndex = sum - visitIndex - 1;
|
2016-07-21 20:54:33 +00:00
|
|
|
|
|
|
|
// Interpolate for vertex positions and associated scalar values
|
2017-05-18 14:29:41 +00:00
|
|
|
const vtkm::Id triTableOffset = static_cast<vtkm::Id>(caseNumber * 16 + visitIndex * 3);
|
2016-07-21 20:54:33 +00:00
|
|
|
for (vtkm::IdComponent triVertex = 0; triVertex < 3; triVertex++)
|
|
|
|
{
|
2018-08-30 15:53:18 +00:00
|
|
|
const vtkm::IdComponent edgeIndex = metaData.TriTable.Get(triTableOffset + triVertex);
|
|
|
|
const vtkm::IdComponent edgeVertex0 = metaData.EdgeTable.Get(2 * edgeIndex + 0);
|
|
|
|
const vtkm::IdComponent edgeVertex1 = metaData.EdgeTable.Get(2 * edgeIndex + 1);
|
2016-07-21 20:54:33 +00:00
|
|
|
const FieldType fieldValue0 = fieldIn[edgeVertex0];
|
|
|
|
const FieldType fieldValue1 = fieldIn[edgeVertex1];
|
|
|
|
|
2017-04-12 21:00:22 +00:00
|
|
|
// Store the input cell id so that we can properly generate the normals
|
|
|
|
// in a subsequent call, after we have merged duplicate points
|
2018-08-30 15:53:18 +00:00
|
|
|
metaData.InterpCellIdPortal.Set(outputPointId + triVertex, inputCellId);
|
2017-04-12 21:00:22 +00:00
|
|
|
|
2018-08-30 15:53:18 +00:00
|
|
|
metaData.InterpContourPortal.Set(outputPointId + triVertex, static_cast<vtkm::UInt8>(i));
|
2017-04-12 21:00:22 +00:00
|
|
|
|
2018-08-30 15:53:18 +00:00
|
|
|
metaData.InterpIdPortal.Set(outputPointId + triVertex,
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::Id2(indices[edgeVertex0], indices[edgeVertex1]));
|
2016-07-21 20:54:33 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::FloatDefault interpolant = static_cast<vtkm::FloatDefault>(isovalues[i] - fieldValue0) /
|
|
|
|
static_cast<vtkm::FloatDefault>(fieldValue1 - fieldValue0);
|
2016-07-21 20:54:33 +00:00
|
|
|
|
2018-08-30 15:53:18 +00:00
|
|
|
metaData.InterpWeightsPortal.Set(outputPointId + triVertex, interpolant);
|
2016-07-21 20:54:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-08-30 15:53:18 +00:00
|
|
|
void operator=(const EdgeWeightGenerate<T>&) = delete;
|
2016-07-21 20:54:33 +00:00
|
|
|
};
|
|
|
|
|
2016-07-20 16:40:03 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
2017-06-06 17:01:45 +00:00
|
|
|
class MapPointField : public vtkm::worklet::WorkletMapField
|
2016-07-20 16:40:03 +00:00
|
|
|
{
|
|
|
|
public:
|
2019-01-10 18:59:25 +00:00
|
|
|
using ControlSignature = void(FieldIn interpolation_ids,
|
|
|
|
FieldIn interpolation_weights,
|
|
|
|
WholeArrayIn inputField,
|
|
|
|
FieldOut output);
|
2018-05-25 21:18:41 +00:00
|
|
|
using ExecutionSignature = void(_1, _2, _3, _4);
|
2018-02-22 13:29:13 +00:00
|
|
|
using InputDomain = _1;
|
2016-07-20 16:40:03 +00:00
|
|
|
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_CONT
|
2017-06-06 17:01:45 +00:00
|
|
|
MapPointField() {}
|
2016-07-20 16:40:03 +00:00
|
|
|
|
|
|
|
template <typename WeightType, typename InFieldPortalType, typename OutFieldType>
|
2017-05-26 17:53:28 +00:00
|
|
|
VTKM_EXEC void operator()(const vtkm::Id2& low_high,
|
|
|
|
const WeightType& weight,
|
|
|
|
const InFieldPortalType& inPortal,
|
|
|
|
OutFieldType& result) const
|
2016-07-20 16:40:03 +00:00
|
|
|
{
|
|
|
|
//fetch the low / high values from inPortal
|
2017-12-12 19:26:23 +00:00
|
|
|
result = static_cast<OutFieldType>(
|
|
|
|
vtkm::Lerp(inPortal.Get(low_high[0]), inPortal.Get(low_high[1]), weight));
|
2016-07-20 16:40:03 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-03-24 20:12:05 +00:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
struct MultiContourLess
|
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T>
|
2017-03-24 20:12:05 +00:00
|
|
|
VTKM_EXEC_CONT bool operator()(const T& a, const T& b) const
|
|
|
|
{
|
|
|
|
return a < b;
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U>
|
|
|
|
VTKM_EXEC_CONT bool operator()(const vtkm::Pair<T, U>& a, const vtkm::Pair<T, U>& b) const
|
2017-03-24 20:12:05 +00:00
|
|
|
{
|
|
|
|
return (a.first < b.first) || (!(b.first < a.first) && (a.second < b.second));
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U>
|
2017-03-24 20:12:05 +00:00
|
|
|
VTKM_EXEC_CONT bool operator()(const vtkm::internal::ArrayPortalValueReference<T>& a,
|
|
|
|
const U& b) const
|
|
|
|
{
|
|
|
|
U&& t = static_cast<U>(a);
|
|
|
|
return t < b;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
2017-05-05 19:15:42 +00:00
|
|
|
struct MergeDuplicateValues : vtkm::worklet::WorkletReduceByKey
|
|
|
|
{
|
2018-05-25 21:18:41 +00:00
|
|
|
using ControlSignature = void(KeysIn keys,
|
2019-01-10 18:59:25 +00:00
|
|
|
ValuesIn valuesIn1,
|
|
|
|
ValuesIn valuesIn2,
|
|
|
|
ReducedValuesOut valueOut1,
|
|
|
|
ReducedValuesOut valueOut2);
|
2018-05-25 21:18:41 +00:00
|
|
|
using ExecutionSignature = void(_1, _2, _3, _4, _5);
|
2018-02-22 13:29:13 +00:00
|
|
|
using InputDomain = _1;
|
2017-05-05 19:15:42 +00:00
|
|
|
|
2017-05-26 17:53:28 +00:00
|
|
|
template <typename T,
|
|
|
|
typename ValuesInType,
|
|
|
|
typename Values2InType,
|
|
|
|
typename ValuesOutType,
|
2017-05-18 14:29:41 +00:00
|
|
|
typename Values2OutType>
|
2017-05-26 17:53:28 +00:00
|
|
|
VTKM_EXEC void operator()(const T&,
|
|
|
|
const ValuesInType& values1,
|
|
|
|
const Values2InType& values2,
|
|
|
|
ValuesOutType& valueOut1,
|
|
|
|
Values2OutType& valueOut2) const
|
2017-05-05 19:15:42 +00:00
|
|
|
{
|
|
|
|
valueOut1 = values1[0];
|
|
|
|
valueOut2 = values2[0];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
struct CopyEdgeIds : vtkm::worklet::WorkletMapField
|
|
|
|
{
|
2019-01-10 18:59:25 +00:00
|
|
|
using ControlSignature = void(FieldIn, FieldOut);
|
2018-05-25 21:18:41 +00:00
|
|
|
using ExecutionSignature = void(_1, _2);
|
2018-02-22 13:29:13 +00:00
|
|
|
using InputDomain = _1;
|
2017-05-05 19:15:42 +00:00
|
|
|
|
|
|
|
VTKM_EXEC
|
2017-05-18 14:29:41 +00:00
|
|
|
void operator()(const vtkm::Id2& input, vtkm::Id2& output) const { output = input; }
|
2017-05-05 19:15:42 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T>
|
|
|
|
VTKM_EXEC void operator()(const vtkm::Pair<T, vtkm::Id2>& input, vtkm::Id2& output) const
|
2017-05-05 19:15:42 +00:00
|
|
|
{
|
|
|
|
output = input.second;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
2018-08-30 15:53:18 +00:00
|
|
|
template <typename KeyType, typename KeyStorage>
|
2017-05-18 14:29:41 +00:00
|
|
|
void MergeDuplicates(const vtkm::cont::ArrayHandle<KeyType, KeyStorage>& original_keys,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::FloatDefault>& weights,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id2>& edgeIds,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id>& cellids,
|
2018-08-30 15:53:18 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id>& connectivity)
|
2017-03-24 20:12:05 +00:00
|
|
|
{
|
2017-05-05 19:15:42 +00:00
|
|
|
vtkm::cont::ArrayHandle<KeyType> input_keys;
|
2018-08-30 15:53:18 +00:00
|
|
|
vtkm::cont::ArrayCopy(original_keys, input_keys);
|
|
|
|
vtkm::worklet::Keys<KeyType> keys(input_keys);
|
2017-05-05 19:15:42 +00:00
|
|
|
input_keys.ReleaseResources();
|
|
|
|
|
|
|
|
{
|
2018-08-28 20:36:50 +00:00
|
|
|
vtkm::worklet::DispatcherReduceByKey<MergeDuplicateValues> dispatcher;
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> writeCells;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::FloatDefault> writeWeights;
|
|
|
|
dispatcher.Invoke(keys, weights, cellids, writeWeights, writeCells);
|
|
|
|
weights = writeWeights;
|
|
|
|
cellids = writeCells;
|
2017-05-05 19:15:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//need to build the new connectivity
|
|
|
|
auto uniqueKeys = keys.GetUniqueKeys();
|
2018-08-30 15:53:18 +00:00
|
|
|
vtkm::cont::Algorithm::LowerBounds(
|
2017-05-26 17:53:28 +00:00
|
|
|
uniqueKeys, original_keys, connectivity, marchingcubes::MultiContourLess());
|
2017-05-05 19:15:42 +00:00
|
|
|
|
|
|
|
//update the edge ids
|
2018-08-28 20:36:50 +00:00
|
|
|
vtkm::worklet::DispatcherMapField<CopyEdgeIds> edgeDispatcher;
|
2017-05-05 19:15:42 +00:00
|
|
|
edgeDispatcher.Invoke(uniqueKeys, edgeIds);
|
2017-03-24 20:12:05 +00:00
|
|
|
}
|
|
|
|
|
2017-04-12 21:00:22 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
2017-06-19 15:56:17 +00:00
|
|
|
template <vtkm::IdComponent Comp>
|
|
|
|
struct EdgeVertex
|
|
|
|
{
|
|
|
|
VTKM_EXEC vtkm::Id operator()(const vtkm::Id2& edge) const { return edge[Comp]; }
|
|
|
|
};
|
|
|
|
|
|
|
|
class NormalsWorkletPass1 : public vtkm::worklet::WorkletMapCellToPoint
|
2017-04-12 21:00:22 +00:00
|
|
|
{
|
2017-06-19 15:56:17 +00:00
|
|
|
private:
|
|
|
|
using PointIdsArray =
|
|
|
|
vtkm::cont::ArrayHandleTransform<vtkm::cont::ArrayHandle<vtkm::Id2>, EdgeVertex<0>>;
|
|
|
|
|
2017-04-12 21:00:22 +00:00
|
|
|
public:
|
2018-05-25 21:18:41 +00:00
|
|
|
using ControlSignature = void(CellSetIn,
|
2017-06-19 15:56:17 +00:00
|
|
|
WholeCellSetIn<Point, Cell>,
|
2019-01-10 18:59:25 +00:00
|
|
|
WholeArrayIn pointCoordinates,
|
|
|
|
WholeArrayIn inputField,
|
|
|
|
FieldOutPoint normals);
|
2017-04-12 21:00:22 +00:00
|
|
|
|
2018-05-25 21:18:41 +00:00
|
|
|
using ExecutionSignature = void(CellCount, CellIndices, InputIndex, _2, _3, _4, _5);
|
2017-04-12 21:00:22 +00:00
|
|
|
|
2017-06-19 15:56:17 +00:00
|
|
|
using InputDomain = _1;
|
|
|
|
using ScatterType = vtkm::worklet::ScatterPermutation<typename PointIdsArray::StorageTag>;
|
2017-04-12 21:00:22 +00:00
|
|
|
|
Move Scatter from Worklet to Dispatcher
Previously, when a Worklet needed a scatter, the scatter object was
stored in the Worklet object. That was problematic because that means
the Scatter, which is a control object, was shoved into the execution
environment.
To prevent that, move the Scatter into the Dispatcher object. The
worklet still declares a ScatterType alias, but no longer has a
GetScatter method. Instead, the Dispatcher now takes a Scatter object in
its constructor. If using the default scatter (ScatterIdentity), the
default constructor is used. If using another type of Scatter that
requires data to set up its state, then the caller of the worklet needs
to provide that to the dispatcher. For convenience, worklets are
encouraged to have a MakeScatter method to help construct a proper
scatter object.
2018-04-27 04:43:51 +00:00
|
|
|
VTKM_CONT
|
|
|
|
static ScatterType MakeScatter(const vtkm::cont::ArrayHandle<vtkm::Id2>& edges)
|
2017-06-19 15:56:17 +00:00
|
|
|
{
|
Move Scatter from Worklet to Dispatcher
Previously, when a Worklet needed a scatter, the scatter object was
stored in the Worklet object. That was problematic because that means
the Scatter, which is a control object, was shoved into the execution
environment.
To prevent that, move the Scatter into the Dispatcher object. The
worklet still declares a ScatterType alias, but no longer has a
GetScatter method. Instead, the Dispatcher now takes a Scatter object in
its constructor. If using the default scatter (ScatterIdentity), the
default constructor is used. If using another type of Scatter that
requires data to set up its state, then the caller of the worklet needs
to provide that to the dispatcher. For convenience, worklets are
encouraged to have a MakeScatter method to help construct a proper
scatter object.
2018-04-27 04:43:51 +00:00
|
|
|
return ScatterType(vtkm::cont::make_ArrayHandleTransform(edges, EdgeVertex<0>()));
|
2017-06-19 15:56:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename FromIndexType,
|
|
|
|
typename CellSetInType,
|
|
|
|
typename WholeCoordinatesIn,
|
|
|
|
typename WholeFieldIn,
|
2017-05-26 17:53:28 +00:00
|
|
|
typename NormalType>
|
2017-06-19 15:56:17 +00:00
|
|
|
VTKM_EXEC void operator()(const vtkm::IdComponent& numCells,
|
|
|
|
const FromIndexType& cellIds,
|
|
|
|
vtkm::Id pointId,
|
|
|
|
const CellSetInType& geometry,
|
|
|
|
const WholeCoordinatesIn& pointCoordinates,
|
|
|
|
const WholeFieldIn& inputField,
|
2017-05-26 17:53:28 +00:00
|
|
|
NormalType& normal) const
|
2017-04-12 21:00:22 +00:00
|
|
|
{
|
2017-08-08 20:31:18 +00:00
|
|
|
using T = typename WholeFieldIn::ValueType;
|
|
|
|
vtkm::worklet::gradient::PointGradient<T> gradient;
|
2017-07-03 14:11:04 +00:00
|
|
|
gradient(numCells, cellIds, pointId, geometry, pointCoordinates, inputField, normal);
|
2017-06-19 15:56:17 +00:00
|
|
|
}
|
2017-04-12 21:00:22 +00:00
|
|
|
|
2017-08-08 20:31:18 +00:00
|
|
|
template <typename FromIndexType,
|
|
|
|
typename WholeCoordinatesIn,
|
|
|
|
typename WholeFieldIn,
|
|
|
|
typename NormalType>
|
|
|
|
VTKM_EXEC void operator()(const vtkm::IdComponent& vtkmNotUsed(numCells),
|
|
|
|
const FromIndexType& vtkmNotUsed(cellIds),
|
|
|
|
vtkm::Id pointId,
|
|
|
|
vtkm::exec::ConnectivityStructured<Point, Cell, 3>& geometry,
|
|
|
|
const WholeCoordinatesIn& pointCoordinates,
|
|
|
|
const WholeFieldIn& inputField,
|
|
|
|
NormalType& normal) const
|
|
|
|
{
|
|
|
|
using T = typename WholeFieldIn::ValueType;
|
|
|
|
|
|
|
|
//Optimization for structured cellsets so we can call StructuredPointGradient
|
|
|
|
//and have way faster gradients
|
|
|
|
vtkm::exec::ConnectivityStructured<Cell, Point, 3> pointGeom(geometry);
|
2018-11-18 17:41:13 +00:00
|
|
|
vtkm::exec::arg::ThreadIndicesPointNeighborhood tpn(pointId, pointId, 0, pointGeom, 0);
|
2017-08-08 20:31:18 +00:00
|
|
|
|
|
|
|
const auto& boundary = tpn.GetBoundaryState();
|
|
|
|
auto pointPortal = pointCoordinates.GetPortal();
|
|
|
|
auto fieldPortal = inputField.GetPortal();
|
2018-12-03 19:44:17 +00:00
|
|
|
vtkm::exec::FieldNeighborhood<decltype(pointPortal)> points(pointPortal, boundary);
|
|
|
|
vtkm::exec::FieldNeighborhood<decltype(fieldPortal)> field(fieldPortal, boundary);
|
2017-08-08 20:31:18 +00:00
|
|
|
|
|
|
|
vtkm::worklet::gradient::StructuredPointGradient<T> gradient;
|
|
|
|
gradient(boundary, points, field, normal);
|
|
|
|
}
|
2017-04-12 21:00:22 +00:00
|
|
|
};
|
|
|
|
|
2017-06-19 15:56:17 +00:00
|
|
|
class NormalsWorkletPass2 : public vtkm::worklet::WorkletMapCellToPoint
|
2017-04-12 21:00:22 +00:00
|
|
|
{
|
2017-06-19 15:56:17 +00:00
|
|
|
private:
|
|
|
|
using PointIdsArray =
|
|
|
|
vtkm::cont::ArrayHandleTransform<vtkm::cont::ArrayHandle<vtkm::Id2>, EdgeVertex<1>>;
|
|
|
|
|
|
|
|
public:
|
|
|
|
typedef void ControlSignature(CellSetIn,
|
|
|
|
WholeCellSetIn<Point, Cell>,
|
2019-01-10 18:59:25 +00:00
|
|
|
WholeArrayIn pointCoordinates,
|
|
|
|
WholeArrayIn inputField,
|
|
|
|
WholeArrayIn weights,
|
|
|
|
FieldInOutPoint normals);
|
2017-06-19 15:56:17 +00:00
|
|
|
|
2018-05-25 21:18:41 +00:00
|
|
|
using ExecutionSignature =
|
|
|
|
void(CellCount, CellIndices, InputIndex, _2, _3, _4, WorkIndex, _5, _6);
|
2017-06-19 15:56:17 +00:00
|
|
|
|
|
|
|
using InputDomain = _1;
|
|
|
|
using ScatterType = vtkm::worklet::ScatterPermutation<typename PointIdsArray::StorageTag>;
|
|
|
|
|
Move Scatter from Worklet to Dispatcher
Previously, when a Worklet needed a scatter, the scatter object was
stored in the Worklet object. That was problematic because that means
the Scatter, which is a control object, was shoved into the execution
environment.
To prevent that, move the Scatter into the Dispatcher object. The
worklet still declares a ScatterType alias, but no longer has a
GetScatter method. Instead, the Dispatcher now takes a Scatter object in
its constructor. If using the default scatter (ScatterIdentity), the
default constructor is used. If using another type of Scatter that
requires data to set up its state, then the caller of the worklet needs
to provide that to the dispatcher. For convenience, worklets are
encouraged to have a MakeScatter method to help construct a proper
scatter object.
2018-04-27 04:43:51 +00:00
|
|
|
VTKM_CONT
|
|
|
|
static ScatterType MakeScatter(const vtkm::cont::ArrayHandle<vtkm::Id2>& edges)
|
2017-04-12 21:00:22 +00:00
|
|
|
{
|
Move Scatter from Worklet to Dispatcher
Previously, when a Worklet needed a scatter, the scatter object was
stored in the Worklet object. That was problematic because that means
the Scatter, which is a control object, was shoved into the execution
environment.
To prevent that, move the Scatter into the Dispatcher object. The
worklet still declares a ScatterType alias, but no longer has a
GetScatter method. Instead, the Dispatcher now takes a Scatter object in
its constructor. If using the default scatter (ScatterIdentity), the
default constructor is used. If using another type of Scatter that
requires data to set up its state, then the caller of the worklet needs
to provide that to the dispatcher. For convenience, worklets are
encouraged to have a MakeScatter method to help construct a proper
scatter object.
2018-04-27 04:43:51 +00:00
|
|
|
return ScatterType(vtkm::cont::make_ArrayHandleTransform(edges, EdgeVertex<1>()));
|
2017-04-12 21:00:22 +00:00
|
|
|
}
|
|
|
|
|
2017-06-19 15:56:17 +00:00
|
|
|
template <typename FromIndexType,
|
|
|
|
typename CellSetInType,
|
|
|
|
typename WholeCoordinatesIn,
|
|
|
|
typename WholeFieldIn,
|
|
|
|
typename WholeWeightsIn,
|
|
|
|
typename NormalType>
|
|
|
|
VTKM_EXEC void operator()(const vtkm::IdComponent& numCells,
|
|
|
|
const FromIndexType& cellIds,
|
|
|
|
vtkm::Id pointId,
|
|
|
|
const CellSetInType& geometry,
|
|
|
|
const WholeCoordinatesIn& pointCoordinates,
|
|
|
|
const WholeFieldIn& inputField,
|
|
|
|
vtkm::Id edgeId,
|
|
|
|
const WholeWeightsIn& weights,
|
|
|
|
NormalType& normal) const
|
2017-04-12 21:00:22 +00:00
|
|
|
{
|
2017-08-08 20:31:18 +00:00
|
|
|
using T = typename WholeFieldIn::ValueType;
|
|
|
|
vtkm::worklet::gradient::PointGradient<T> gradient;
|
2017-06-19 15:56:17 +00:00
|
|
|
NormalType grad1;
|
2017-07-03 14:11:04 +00:00
|
|
|
gradient(numCells, cellIds, pointId, geometry, pointCoordinates, inputField, grad1);
|
2017-06-19 15:56:17 +00:00
|
|
|
|
|
|
|
NormalType grad0 = normal;
|
|
|
|
auto weight = weights.Get(edgeId);
|
|
|
|
normal = vtkm::Normal(vtkm::Lerp(grad0, grad1, weight));
|
2017-04-12 21:00:22 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 20:31:18 +00:00
|
|
|
template <typename FromIndexType,
|
|
|
|
typename WholeCoordinatesIn,
|
|
|
|
typename WholeFieldIn,
|
|
|
|
typename WholeWeightsIn,
|
|
|
|
typename NormalType>
|
|
|
|
VTKM_EXEC void operator()(const vtkm::IdComponent& vtkmNotUsed(numCells),
|
|
|
|
const FromIndexType& vtkmNotUsed(cellIds),
|
|
|
|
vtkm::Id pointId,
|
|
|
|
vtkm::exec::ConnectivityStructured<Point, Cell, 3>& geometry,
|
|
|
|
const WholeCoordinatesIn& pointCoordinates,
|
|
|
|
const WholeFieldIn& inputField,
|
|
|
|
vtkm::Id edgeId,
|
|
|
|
const WholeWeightsIn& weights,
|
|
|
|
NormalType& normal) const
|
|
|
|
{
|
|
|
|
using T = typename WholeFieldIn::ValueType;
|
|
|
|
//Optimization for structured cellsets so we can call StructuredPointGradient
|
|
|
|
//and have way faster gradients
|
|
|
|
vtkm::exec::ConnectivityStructured<Cell, Point, 3> pointGeom(geometry);
|
2018-11-18 17:41:13 +00:00
|
|
|
vtkm::exec::arg::ThreadIndicesPointNeighborhood tpn(pointId, pointId, 0, pointGeom, 0);
|
2017-08-08 20:31:18 +00:00
|
|
|
|
|
|
|
const auto& boundary = tpn.GetBoundaryState();
|
|
|
|
auto pointPortal = pointCoordinates.GetPortal();
|
|
|
|
auto fieldPortal = inputField.GetPortal();
|
2018-12-03 19:44:17 +00:00
|
|
|
vtkm::exec::FieldNeighborhood<decltype(pointPortal)> points(pointPortal, boundary);
|
|
|
|
vtkm::exec::FieldNeighborhood<decltype(fieldPortal)> field(fieldPortal, boundary);
|
2017-08-08 20:31:18 +00:00
|
|
|
|
|
|
|
vtkm::worklet::gradient::StructuredPointGradient<T> gradient;
|
|
|
|
NormalType grad1;
|
|
|
|
gradient(boundary, points, field, grad1);
|
|
|
|
|
|
|
|
NormalType grad0 = normal;
|
|
|
|
auto weight = weights.Get(edgeId);
|
|
|
|
normal = vtkm::Normal(vtkm::Lerp(grad0, grad1, weight));
|
|
|
|
}
|
2017-04-12 21:00:22 +00:00
|
|
|
};
|
2017-06-19 15:56:17 +00:00
|
|
|
|
2017-10-27 20:42:09 +00:00
|
|
|
template <typename NormalCType,
|
|
|
|
typename InputFieldType,
|
|
|
|
typename InputStorageType,
|
|
|
|
typename CellSet>
|
|
|
|
struct GenerateNormalsDeduced
|
|
|
|
{
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<NormalCType, 3>>* normals;
|
|
|
|
const vtkm::cont::ArrayHandle<InputFieldType, InputStorageType>* field;
|
|
|
|
const CellSet* cellset;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id2>* edges;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::FloatDefault>* weights;
|
|
|
|
|
2018-08-30 15:53:18 +00:00
|
|
|
template <typename CoordinateSystem>
|
|
|
|
void operator()(const CoordinateSystem& coordinates) const
|
2017-10-27 20:42:09 +00:00
|
|
|
{
|
|
|
|
// To save memory, the normals computation is done in two passes. In the first
|
|
|
|
// pass the gradient at the first vertex of each edge is computed and stored in
|
|
|
|
// the normals array. In the second pass the gradient at the second vertex is
|
|
|
|
// computed and the gradient of the first vertex is read from the normals array.
|
|
|
|
// The final normal is interpolated from the two gradient values and stored
|
|
|
|
// in the normals array.
|
|
|
|
//
|
2018-08-28 20:36:50 +00:00
|
|
|
vtkm::worklet::DispatcherMapTopology<NormalsWorkletPass1> dispatcherNormalsPass1(
|
|
|
|
NormalsWorkletPass1::MakeScatter(*edges));
|
Move Scatter from Worklet to Dispatcher
Previously, when a Worklet needed a scatter, the scatter object was
stored in the Worklet object. That was problematic because that means
the Scatter, which is a control object, was shoved into the execution
environment.
To prevent that, move the Scatter into the Dispatcher object. The
worklet still declares a ScatterType alias, but no longer has a
GetScatter method. Instead, the Dispatcher now takes a Scatter object in
its constructor. If using the default scatter (ScatterIdentity), the
default constructor is used. If using another type of Scatter that
requires data to set up its state, then the caller of the worklet needs
to provide that to the dispatcher. For convenience, worklets are
encouraged to have a MakeScatter method to help construct a proper
scatter object.
2018-04-27 04:43:51 +00:00
|
|
|
dispatcherNormalsPass1.Invoke(
|
2017-11-02 18:27:51 +00:00
|
|
|
*cellset, *cellset, coordinates, marchingcubes::make_ScalarField(*field), *normals);
|
2017-10-27 20:42:09 +00:00
|
|
|
|
2018-08-28 20:36:50 +00:00
|
|
|
vtkm::worklet::DispatcherMapTopology<NormalsWorkletPass2> dispatcherNormalsPass2(
|
|
|
|
NormalsWorkletPass2::MakeScatter(*edges));
|
Move Scatter from Worklet to Dispatcher
Previously, when a Worklet needed a scatter, the scatter object was
stored in the Worklet object. That was problematic because that means
the Scatter, which is a control object, was shoved into the execution
environment.
To prevent that, move the Scatter into the Dispatcher object. The
worklet still declares a ScatterType alias, but no longer has a
GetScatter method. Instead, the Dispatcher now takes a Scatter object in
its constructor. If using the default scatter (ScatterIdentity), the
default constructor is used. If using another type of Scatter that
requires data to set up its state, then the caller of the worklet needs
to provide that to the dispatcher. For convenience, worklets are
encouraged to have a MakeScatter method to help construct a proper
scatter object.
2018-04-27 04:43:51 +00:00
|
|
|
dispatcherNormalsPass2.Invoke(
|
2017-11-02 18:27:51 +00:00
|
|
|
*cellset, *cellset, coordinates, marchingcubes::make_ScalarField(*field), *weights, *normals);
|
2017-10-27 20:42:09 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-06-19 15:56:17 +00:00
|
|
|
template <typename NormalCType,
|
|
|
|
typename InputFieldType,
|
|
|
|
typename InputStorageType,
|
|
|
|
typename CellSet,
|
2018-08-30 15:53:18 +00:00
|
|
|
typename CoordinateSystem>
|
2017-06-19 15:56:17 +00:00
|
|
|
void GenerateNormals(vtkm::cont::ArrayHandle<vtkm::Vec<NormalCType, 3>>& normals,
|
|
|
|
const vtkm::cont::ArrayHandle<InputFieldType, InputStorageType>& field,
|
|
|
|
const CellSet& cellset,
|
|
|
|
const CoordinateSystem& coordinates,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id2>& edges,
|
2018-08-30 15:53:18 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::FloatDefault>& weights)
|
2017-06-19 15:56:17 +00:00
|
|
|
{
|
2017-10-27 20:42:09 +00:00
|
|
|
GenerateNormalsDeduced<NormalCType, InputFieldType, InputStorageType, CellSet> functor;
|
|
|
|
functor.normals = &normals;
|
|
|
|
functor.field = &field;
|
|
|
|
functor.cellset = &cellset;
|
|
|
|
functor.edges = &edges;
|
|
|
|
functor.weights = &weights;
|
|
|
|
|
|
|
|
|
2018-08-30 15:53:18 +00:00
|
|
|
vtkm::cont::CastAndCall(coordinates, functor);
|
2017-06-19 15:56:17 +00:00
|
|
|
}
|
2016-07-20 16:40:03 +00:00
|
|
|
}
|
|
|
|
|
2015-11-16 19:21:07 +00:00
|
|
|
/// \brief Compute the isosurface for a uniform grid data set
|
|
|
|
class MarchingCubes
|
|
|
|
{
|
|
|
|
public:
|
2017-05-18 14:29:41 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
MarchingCubes(bool mergeDuplicates = true)
|
|
|
|
: MergeDuplicatePoints(mergeDuplicates)
|
|
|
|
, EdgeTable()
|
|
|
|
, NumTrianglesTable()
|
|
|
|
, TriangleTable()
|
|
|
|
, InterpolationWeights()
|
|
|
|
, InterpolationEdgeIds()
|
|
|
|
{
|
|
|
|
// Set up the Marching Cubes case tables as part of the filter so that
|
|
|
|
// we cache these tables in the execution environment between execution runs
|
|
|
|
this->EdgeTable = vtkm::cont::make_ArrayHandle(vtkm::worklet::internal::edgeTable, 24);
|
2015-11-16 19:21:07 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
this->NumTrianglesTable =
|
|
|
|
vtkm::cont::make_ArrayHandle(vtkm::worklet::internal::numTrianglesTable, 256);
|
2016-01-04 21:53:46 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
this->TriangleTable = vtkm::cont::make_ArrayHandle(vtkm::worklet::internal::triTable, 256 * 16);
|
|
|
|
}
|
2015-11-16 19:21:07 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
void SetMergeDuplicatePoints(bool merge) { this->MergeDuplicatePoints = merge; }
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
bool GetMergeDuplicatePoints() const { return this->MergeDuplicatePoints; }
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
2017-05-26 17:53:28 +00:00
|
|
|
template <typename ValueType,
|
|
|
|
typename CellSetType,
|
|
|
|
typename CoordinateSystem,
|
|
|
|
typename StorageTagField,
|
|
|
|
typename CoordinateType,
|
2018-08-30 15:53:18 +00:00
|
|
|
typename StorageTagVertices>
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::CellSetSingleType<> Run(
|
2017-05-26 17:53:28 +00:00
|
|
|
const ValueType* const isovalues,
|
|
|
|
const vtkm::Id numIsoValues,
|
|
|
|
const CellSetType& cells,
|
2017-05-18 14:29:41 +00:00
|
|
|
const CoordinateSystem& coordinateSystem,
|
|
|
|
const vtkm::cont::ArrayHandle<ValueType, StorageTagField>& input,
|
2018-08-30 15:53:18 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<CoordinateType, 3>, StorageTagVertices> vertices)
|
2017-05-18 14:29:41 +00:00
|
|
|
{
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<CoordinateType, 3>> normals;
|
2017-10-27 20:42:09 +00:00
|
|
|
return this->DeduceRun(
|
2018-08-30 15:53:18 +00:00
|
|
|
isovalues, numIsoValues, cells, coordinateSystem, input, vertices, normals, false);
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
2015-11-16 19:21:07 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
//----------------------------------------------------------------------------
|
2017-05-26 17:53:28 +00:00
|
|
|
template <typename ValueType,
|
|
|
|
typename CellSetType,
|
|
|
|
typename CoordinateSystem,
|
|
|
|
typename StorageTagField,
|
|
|
|
typename CoordinateType,
|
|
|
|
typename StorageTagVertices,
|
2018-08-30 15:53:18 +00:00
|
|
|
typename StorageTagNormals>
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::CellSetSingleType<> Run(
|
2017-05-26 17:53:28 +00:00
|
|
|
const ValueType* const isovalues,
|
|
|
|
const vtkm::Id numIsoValues,
|
|
|
|
const CellSetType& cells,
|
2017-05-18 14:29:41 +00:00
|
|
|
const CoordinateSystem& coordinateSystem,
|
|
|
|
const vtkm::cont::ArrayHandle<ValueType, StorageTagField>& input,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<CoordinateType, 3>, StorageTagVertices> vertices,
|
2018-08-30 15:53:18 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<CoordinateType, 3>, StorageTagNormals> normals)
|
2017-05-18 14:29:41 +00:00
|
|
|
{
|
2017-10-27 20:42:09 +00:00
|
|
|
return this->DeduceRun(
|
2018-08-30 15:53:18 +00:00
|
|
|
isovalues, numIsoValues, cells, coordinateSystem, input, vertices, normals, true);
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
2015-11-16 19:21:07 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
//----------------------------------------------------------------------------
|
2018-08-30 15:53:18 +00:00
|
|
|
template <typename ValueType, typename StorageType>
|
2017-06-06 17:01:45 +00:00
|
|
|
vtkm::cont::ArrayHandle<ValueType> ProcessPointField(
|
2018-08-30 15:53:18 +00:00
|
|
|
const vtkm::cont::ArrayHandle<ValueType, StorageType>& input) const
|
2017-05-18 14:29:41 +00:00
|
|
|
{
|
2017-06-06 17:01:45 +00:00
|
|
|
using vtkm::worklet::marchingcubes::MapPointField;
|
|
|
|
MapPointField applyToField;
|
2018-08-28 20:36:50 +00:00
|
|
|
vtkm::worklet::DispatcherMapField<MapPointField> applyFieldDispatcher(applyToField);
|
2017-05-18 14:29:41 +00:00
|
|
|
|
2017-06-06 17:01:45 +00:00
|
|
|
vtkm::cont::ArrayHandle<ValueType> output;
|
2017-05-26 17:53:28 +00:00
|
|
|
applyFieldDispatcher.Invoke(
|
|
|
|
this->InterpolationEdgeIds, this->InterpolationWeights, input, output);
|
2017-06-06 17:01:45 +00:00
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
2018-08-30 15:53:18 +00:00
|
|
|
template <typename ValueType, typename StorageType>
|
2017-06-06 17:01:45 +00:00
|
|
|
vtkm::cont::ArrayHandle<ValueType> ProcessCellField(
|
2018-08-30 15:53:18 +00:00
|
|
|
const vtkm::cont::ArrayHandle<ValueType, StorageType>& in) const
|
2017-06-06 17:01:45 +00:00
|
|
|
{
|
|
|
|
// Use a temporary permutation array to simplify the mapping:
|
|
|
|
auto tmp = vtkm::cont::make_ArrayHandlePermutation(this->CellIdMap, in);
|
|
|
|
|
|
|
|
// Copy into an array with default storage:
|
|
|
|
vtkm::cont::ArrayHandle<ValueType> result;
|
2018-08-30 15:53:18 +00:00
|
|
|
vtkm::cont::ArrayCopy(tmp, result);
|
2017-06-06 17:01:45 +00:00
|
|
|
|
|
|
|
return result;
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
2015-11-16 19:21:07 +00:00
|
|
|
|
2017-06-08 21:02:55 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
void ReleaseCellMapArrays() { this->CellIdMap.ReleaseResources(); }
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
private:
|
2017-10-27 20:42:09 +00:00
|
|
|
template <typename ValueType,
|
|
|
|
typename CoordinateSystem,
|
|
|
|
typename StorageTagField,
|
|
|
|
typename StorageTagVertices,
|
|
|
|
typename StorageTagNormals,
|
|
|
|
typename CoordinateType,
|
2018-08-30 15:53:18 +00:00
|
|
|
typename NormalType>
|
2017-10-27 20:42:09 +00:00
|
|
|
struct DeduceCellType
|
|
|
|
{
|
|
|
|
MarchingCubes* MC = nullptr;
|
|
|
|
const ValueType* isovalues = nullptr;
|
|
|
|
const vtkm::Id* numIsoValues = nullptr;
|
|
|
|
const CoordinateSystem* coordinateSystem = nullptr;
|
|
|
|
const vtkm::cont::ArrayHandle<ValueType, StorageTagField>* inputField = nullptr;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<CoordinateType, 3>, StorageTagVertices>* vertices;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<NormalType, 3>, StorageTagNormals>* normals;
|
|
|
|
const bool* withNormals;
|
|
|
|
vtkm::cont::CellSetSingleType<>* result;
|
|
|
|
|
|
|
|
template <typename CellSetType>
|
|
|
|
void operator()(const CellSetType& cells) const
|
|
|
|
{
|
|
|
|
if (this->MC)
|
|
|
|
{
|
|
|
|
*this->result = this->MC->DoRun(isovalues,
|
|
|
|
*numIsoValues,
|
|
|
|
cells,
|
|
|
|
*coordinateSystem,
|
|
|
|
*inputField,
|
|
|
|
*vertices,
|
|
|
|
*normals,
|
2018-08-30 15:53:18 +00:00
|
|
|
*withNormals);
|
2017-10-27 20:42:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
template <typename ValueType,
|
|
|
|
typename CellSetType,
|
|
|
|
typename CoordinateSystem,
|
|
|
|
typename StorageTagField,
|
|
|
|
typename StorageTagVertices,
|
|
|
|
typename StorageTagNormals,
|
|
|
|
typename CoordinateType,
|
2018-08-30 15:53:18 +00:00
|
|
|
typename NormalType>
|
2017-10-27 20:42:09 +00:00
|
|
|
vtkm::cont::CellSetSingleType<> DeduceRun(
|
|
|
|
const ValueType* isovalues,
|
|
|
|
const vtkm::Id numIsoValues,
|
|
|
|
const CellSetType& cells,
|
|
|
|
const CoordinateSystem& coordinateSystem,
|
|
|
|
const vtkm::cont::ArrayHandle<ValueType, StorageTagField>& inputField,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<CoordinateType, 3>, StorageTagVertices> vertices,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<NormalType, 3>, StorageTagNormals> normals,
|
2018-08-30 15:53:18 +00:00
|
|
|
bool withNormals)
|
2017-10-27 20:42:09 +00:00
|
|
|
{
|
|
|
|
vtkm::cont::CellSetSingleType<> outputCells("contour");
|
|
|
|
|
|
|
|
DeduceCellType<ValueType,
|
|
|
|
CoordinateSystem,
|
|
|
|
StorageTagField,
|
|
|
|
StorageTagVertices,
|
|
|
|
StorageTagNormals,
|
|
|
|
CoordinateType,
|
2018-08-30 15:53:18 +00:00
|
|
|
NormalType>
|
2017-10-27 20:42:09 +00:00
|
|
|
functor;
|
|
|
|
functor.MC = this;
|
|
|
|
functor.isovalues = isovalues;
|
|
|
|
functor.numIsoValues = &numIsoValues;
|
|
|
|
functor.coordinateSystem = &coordinateSystem;
|
|
|
|
functor.inputField = &inputField;
|
|
|
|
functor.vertices = &vertices;
|
|
|
|
functor.normals = &normals;
|
|
|
|
functor.withNormals = &withNormals;
|
|
|
|
functor.result = &outputCells;
|
|
|
|
|
|
|
|
vtkm::cont::CastAndCall(cells, functor);
|
|
|
|
|
|
|
|
return outputCells;
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
//----------------------------------------------------------------------------
|
2017-05-26 17:53:28 +00:00
|
|
|
template <typename ValueType,
|
|
|
|
typename CellSetType,
|
|
|
|
typename CoordinateSystem,
|
|
|
|
typename StorageTagField,
|
|
|
|
typename StorageTagVertices,
|
|
|
|
typename StorageTagNormals,
|
|
|
|
typename CoordinateType,
|
2018-08-30 15:53:18 +00:00
|
|
|
typename NormalType>
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::CellSetSingleType<> DoRun(
|
2017-05-26 17:53:28 +00:00
|
|
|
const ValueType* isovalues,
|
|
|
|
const vtkm::Id numIsoValues,
|
|
|
|
const CellSetType& cells,
|
2017-05-18 14:29:41 +00:00
|
|
|
const CoordinateSystem& coordinateSystem,
|
|
|
|
const vtkm::cont::ArrayHandle<ValueType, StorageTagField>& inputField,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<CoordinateType, 3>, StorageTagVertices> vertices,
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<NormalType, 3>, StorageTagNormals> normals,
|
2018-08-30 15:53:18 +00:00
|
|
|
bool withNormals)
|
2017-05-18 14:29:41 +00:00
|
|
|
{
|
2018-05-03 17:21:04 +00:00
|
|
|
using vtkm::worklet::marchingcubes::ClassifyCell;
|
2017-05-18 14:29:41 +00:00
|
|
|
using vtkm::worklet::marchingcubes::EdgeWeightGenerate;
|
|
|
|
using vtkm::worklet::marchingcubes::EdgeWeightGenerateMetaData;
|
2018-05-03 17:21:04 +00:00
|
|
|
using vtkm::worklet::marchingcubes::MapPointField;
|
2015-11-16 19:21:07 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
// Setup the Dispatcher Typedefs
|
2018-08-28 20:36:50 +00:00
|
|
|
using ClassifyDispatcher = vtkm::worklet::DispatcherMapTopology<ClassifyCell<ValueType>>;
|
2016-07-20 16:40:03 +00:00
|
|
|
|
2018-08-30 15:53:18 +00:00
|
|
|
using GenerateDispatcher = vtkm::worklet::DispatcherMapTopology<EdgeWeightGenerate<ValueType>>;
|
2016-07-20 16:40:03 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<ValueType> isoValuesHandle =
|
2017-03-14 12:56:44 +00:00
|
|
|
vtkm::cont::make_ArrayHandle(isovalues, numIsoValues);
|
2017-05-18 14:29:41 +00:00
|
|
|
// Call the ClassifyCell functor to compute the Marching Cubes case numbers
|
|
|
|
// for each cell, and the number of vertices to be generated
|
2016-07-20 16:40:03 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::IdComponent> numOutputTrisPerCell;
|
2017-05-05 19:15:42 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
{
|
|
|
|
ClassifyCell<ValueType> classifyCell;
|
|
|
|
ClassifyDispatcher classifyCellDispatcher(classifyCell);
|
2017-05-26 17:53:28 +00:00
|
|
|
classifyCellDispatcher.Invoke(
|
|
|
|
isoValuesHandle, inputField, cells, numOutputTrisPerCell, this->NumTrianglesTable);
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
2016-07-20 16:40:03 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
//Pass 2 Generate the edges
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::UInt8> contourIds;
|
2017-06-06 17:01:45 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> originalCellIdsForPoints;
|
2017-05-18 14:29:41 +00:00
|
|
|
{
|
2018-08-30 15:53:18 +00:00
|
|
|
auto scatter = EdgeWeightGenerate<ValueType>::MakeScatter(numOutputTrisPerCell);
|
2017-05-18 14:29:41 +00:00
|
|
|
|
2017-06-06 17:01:45 +00:00
|
|
|
// Maps output cells to input cells. Store this for cell field mapping.
|
|
|
|
this->CellIdMap = scatter.GetOutputToInputMap();
|
|
|
|
|
2018-08-30 15:53:18 +00:00
|
|
|
EdgeWeightGenerateMetaData metaData(
|
2017-05-18 14:29:41 +00:00
|
|
|
scatter.GetOutputRange(numOutputTrisPerCell.GetNumberOfValues()),
|
2017-05-26 17:53:28 +00:00
|
|
|
this->InterpolationWeights,
|
|
|
|
this->InterpolationEdgeIds,
|
2017-06-06 17:01:45 +00:00
|
|
|
originalCellIdsForPoints,
|
2017-05-26 17:53:28 +00:00
|
|
|
contourIds,
|
|
|
|
this->EdgeTable,
|
|
|
|
this->NumTrianglesTable,
|
Move Scatter from Worklet to Dispatcher
Previously, when a Worklet needed a scatter, the scatter object was
stored in the Worklet object. That was problematic because that means
the Scatter, which is a control object, was shoved into the execution
environment.
To prevent that, move the Scatter into the Dispatcher object. The
worklet still declares a ScatterType alias, but no longer has a
GetScatter method. Instead, the Dispatcher now takes a Scatter object in
its constructor. If using the default scatter (ScatterIdentity), the
default constructor is used. If using another type of Scatter that
requires data to set up its state, then the caller of the worklet needs
to provide that to the dispatcher. For convenience, worklets are
encouraged to have a MakeScatter method to help construct a proper
scatter object.
2018-04-27 04:43:51 +00:00
|
|
|
this->TriangleTable);
|
2017-05-18 14:29:41 +00:00
|
|
|
|
2018-08-30 15:53:18 +00:00
|
|
|
EdgeWeightGenerate<ValueType> weightGenerate;
|
Move Scatter from Worklet to Dispatcher
Previously, when a Worklet needed a scatter, the scatter object was
stored in the Worklet object. That was problematic because that means
the Scatter, which is a control object, was shoved into the execution
environment.
To prevent that, move the Scatter into the Dispatcher object. The
worklet still declares a ScatterType alias, but no longer has a
GetScatter method. Instead, the Dispatcher now takes a Scatter object in
its constructor. If using the default scatter (ScatterIdentity), the
default constructor is used. If using another type of Scatter that
requires data to set up its state, then the caller of the worklet needs
to provide that to the dispatcher. For convenience, worklets are
encouraged to have a MakeScatter method to help construct a proper
scatter object.
2018-04-27 04:43:51 +00:00
|
|
|
GenerateDispatcher edgeDispatcher(weightGenerate, scatter);
|
2017-05-18 14:29:41 +00:00
|
|
|
edgeDispatcher.Invoke(
|
|
|
|
cells,
|
|
|
|
//cast to a scalar field if not one, as cellderivative only works on those
|
2017-05-26 17:53:28 +00:00
|
|
|
isoValuesHandle,
|
2018-08-30 15:53:18 +00:00
|
|
|
inputField,
|
|
|
|
metaData);
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
2017-03-14 12:56:44 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
if (numIsoValues <= 1 || !this->MergeDuplicatePoints)
|
|
|
|
{ //release memory early that we are not going to need again
|
|
|
|
contourIds.ReleaseResources();
|
|
|
|
}
|
2016-07-20 16:40:03 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
|
|
|
|
if (this->MergeDuplicatePoints)
|
2017-03-14 12:56:44 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
// In all the below cases you will notice that only interpolation ids
|
|
|
|
// are updated. That is because MergeDuplicates will internally update
|
|
|
|
// the InterpolationWeights and InterpolationOriginCellIds arrays to be the correct for the
|
|
|
|
// output. But for InterpolationEdgeIds we need to do it manually once done
|
|
|
|
if (numIsoValues == 1)
|
|
|
|
{
|
|
|
|
marchingcubes::MergeDuplicates(this->InterpolationEdgeIds, //keys
|
|
|
|
this->InterpolationWeights, //values
|
|
|
|
this->InterpolationEdgeIds, //values
|
2017-06-06 17:01:45 +00:00
|
|
|
originalCellIdsForPoints, //values
|
2018-08-30 15:53:18 +00:00
|
|
|
connectivity); // computed using lower bounds
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
|
|
|
else if (numIsoValues > 1)
|
|
|
|
{
|
|
|
|
marchingcubes::MergeDuplicates(
|
|
|
|
vtkm::cont::make_ArrayHandleZip(contourIds, this->InterpolationEdgeIds), //keys
|
|
|
|
this->InterpolationWeights, //values
|
|
|
|
this->InterpolationEdgeIds, //values
|
2017-06-06 17:01:45 +00:00
|
|
|
originalCellIdsForPoints, //values
|
2018-08-30 15:53:18 +00:00
|
|
|
connectivity); // computed using lower bounds
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
2017-03-24 20:12:05 +00:00
|
|
|
}
|
2017-05-18 14:29:41 +00:00
|
|
|
else
|
2017-03-24 20:12:05 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
//when we don't merge points, the connectivity array can be represented
|
|
|
|
//by a counting array. The danger of doing it this way is that the output
|
|
|
|
//type is unknown. That is why we copy it into an explicit array
|
|
|
|
vtkm::cont::ArrayHandleIndex temp(this->InterpolationEdgeIds.GetNumberOfValues());
|
2018-08-30 15:53:18 +00:00
|
|
|
vtkm::cont::ArrayCopy(temp, connectivity);
|
2017-03-14 12:56:44 +00:00
|
|
|
}
|
2016-07-20 16:40:03 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
//generate the vertices's
|
2017-06-06 17:01:45 +00:00
|
|
|
MapPointField applyToField;
|
2018-08-28 20:36:50 +00:00
|
|
|
vtkm::worklet::DispatcherMapField<MapPointField> applyFieldDispatcher(applyToField);
|
2017-04-12 21:00:22 +00:00
|
|
|
|
2017-05-26 17:53:28 +00:00
|
|
|
applyFieldDispatcher.Invoke(
|
|
|
|
this->InterpolationEdgeIds, this->InterpolationWeights, coordinateSystem, vertices);
|
2017-05-18 14:29:41 +00:00
|
|
|
|
|
|
|
//assign the connectivity to the cell set
|
|
|
|
vtkm::cont::CellSetSingleType<> outputCells("contour");
|
|
|
|
outputCells.Fill(vertices.GetNumberOfValues(), vtkm::CELL_SHAPE_TRIANGLE, 3, connectivity);
|
|
|
|
|
|
|
|
//now that the vertices have been generated we can generate the normals
|
|
|
|
if (withNormals)
|
|
|
|
{
|
2017-06-19 15:56:17 +00:00
|
|
|
marchingcubes::GenerateNormals(normals,
|
|
|
|
inputField,
|
|
|
|
cells,
|
|
|
|
coordinateSystem,
|
|
|
|
this->InterpolationEdgeIds,
|
2018-08-30 15:53:18 +00:00
|
|
|
this->InterpolationWeights);
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return outputCells;
|
|
|
|
}
|
2016-07-20 16:40:03 +00:00
|
|
|
|
|
|
|
bool MergeDuplicatePoints;
|
|
|
|
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::IdComponent> EdgeTable;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::IdComponent> NumTrianglesTable;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::IdComponent> TriangleTable;
|
|
|
|
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::FloatDefault> InterpolationWeights;
|
2017-04-12 21:00:22 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id2> InterpolationEdgeIds;
|
2017-06-08 21:02:55 +00:00
|
|
|
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> CellIdMap;
|
2015-11-16 19:21:07 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
} // namespace vtkm::worklet
|
|
|
|
|
|
|
|
#endif // vtk_m_worklet_MarchingCubes_h
|