vtk-m2/vtkm/worklet/contour/FlyingEdgesHelpers.h
Robert Maynard 16e04db157 FlyingEdges: Handle when pass 1 generates no intersections
Previously if pass 1 generated no intersections, pass 2 would
incorrectly generate no intersections resulting in an empty
dataset.
2020-06-11 08:32:28 -04:00

262 lines
8.7 KiB
C++

//============================================================================
// 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.
//============================================================================
#ifndef vtk_m_worklet_contour_flyingedges_helpers_h
#define vtk_m_worklet_contour_flyingedges_helpers_h
#include <vtkm/Types.h>
namespace vtkm
{
namespace worklet
{
namespace flying_edges
{
struct FlyingEdges3D
{
public:
// Edge case table values.
enum EdgeClass
{
Below = 0, // below isovalue
Above = 1, // above isovalue
LeftAbove = 1, // left vertex is above isovalue
RightAbove = 2, // right vertex is above isovalue
BothAbove = 3 // entire edge is above isovalue
};
enum CellClass
{
Interior = 0,
MinBoundary = 1,
MaxBoundary = 2
};
};
struct SumXAxis
{
static constexpr vtkm::Id xindex = 0;
static constexpr vtkm::Id yindex = 1;
static constexpr vtkm::Id zindex = 2;
};
struct SumYAxis
{
static constexpr vtkm::Id xindex = 1;
static constexpr vtkm::Id yindex = 0;
static constexpr vtkm::Id zindex = 2;
};
template <typename Device>
struct select_AxisToSum
{
using type = SumXAxis;
};
template <>
struct select_AxisToSum<vtkm::cont::DeviceAdapterTagCuda>
{
using type = SumYAxis;
};
inline vtkm::cont::CellSetStructured<2> make_metaDataMesh2D(SumXAxis, const vtkm::Id3& pdims)
{
vtkm::cont::CellSetStructured<2> metaDataMesh;
metaDataMesh.SetPointDimensions(vtkm::Id2{ pdims[1], pdims[2] });
return metaDataMesh;
}
inline vtkm::cont::CellSetStructured<2> make_metaDataMesh2D(SumYAxis, const vtkm::Id3& pdims)
{
vtkm::cont::CellSetStructured<2> metaDataMesh;
metaDataMesh.SetPointDimensions(vtkm::Id2{ pdims[0], pdims[2] });
return metaDataMesh;
}
VTKM_EXEC inline vtkm::Id3 compute_ijk(SumXAxis, const vtkm::Id3& executionSpaceIJK)
{
return vtkm::Id3{ 0, executionSpaceIJK[0], executionSpaceIJK[1] };
}
VTKM_EXEC inline vtkm::Id3 compute_ijk(SumYAxis, const vtkm::Id3& executionSpaceIJK)
{
return vtkm::Id3{ executionSpaceIJK[0], 0, executionSpaceIJK[1] };
}
VTKM_EXEC inline vtkm::Id3 compute_cdims(SumXAxis,
const vtkm::Id3& executionSpacePDims,
vtkm::Id numOfXPoints)
{
return vtkm::Id3{ numOfXPoints - 1, executionSpacePDims[0] - 1, executionSpacePDims[1] - 1 };
}
VTKM_EXEC inline vtkm::Id3 compute_cdims(SumYAxis,
const vtkm::Id3& executionSpacePDims,
vtkm::Id numOfYPoints)
{
return vtkm::Id3{ executionSpacePDims[0] - 1, numOfYPoints - 1, executionSpacePDims[1] - 1 };
}
VTKM_EXEC inline vtkm::Id3 compute_pdims(SumXAxis,
const vtkm::Id3& executionSpacePDims,
vtkm::Id numOfXPoints)
{
return vtkm::Id3{ numOfXPoints, executionSpacePDims[0], executionSpacePDims[1] };
}
VTKM_EXEC inline vtkm::Id3 compute_pdims(SumYAxis,
const vtkm::Id3& executionSpacePDims,
vtkm::Id numOfYPoints)
{
return vtkm::Id3{ executionSpacePDims[0], numOfYPoints, executionSpacePDims[1] };
}
VTKM_EXEC inline vtkm::Id compute_start(SumXAxis, const vtkm::Id3& ijk, const vtkm::Id3& dims)
{
return (dims[0] * ijk[1]) + ((dims[0] * dims[1]) * ijk[2]);
}
VTKM_EXEC inline vtkm::Id compute_start(SumYAxis, const vtkm::Id3& ijk, const vtkm::Id3& dims)
{
return ijk[0] + ((dims[0] * dims[1]) * ijk[2]);
}
VTKM_EXEC inline vtkm::Id4 compute_neighbor_starts(SumXAxis,
const vtkm::Id3& ijk,
const vtkm::Id3& pdims)
{
//Optimized form of
// return vtkm::Id4 { compute_start(sx, ijk, pdims),
// compute_start(sx, ijk + vtkm::Id3{ 0, 1, 0 }, pdims),
// compute_start(sx, ijk + vtkm::Id3{ 0, 0, 1 }, pdims),
// compute_start(sx, ijk + vtkm::Id3{ 0, 1, 1 }, pdims) };
const auto sliceSize = (pdims[0] * pdims[1]);
const auto rowPos = (pdims[0] * ijk[1]);
return vtkm::Id4{ rowPos + (sliceSize * ijk[2]),
rowPos + pdims[0] + (sliceSize * ijk[2]),
rowPos + (sliceSize * (ijk[2] + 1)),
rowPos + pdims[0] + (sliceSize * (ijk[2] + 1)) };
}
VTKM_EXEC inline vtkm::Id4 compute_neighbor_starts(SumYAxis,
const vtkm::Id3& ijk,
const vtkm::Id3& pdims)
{
//Optimized form of
// return vtkm::Id4{ compute_start(sy, ijk, pdims),
// compute_start(sy, ijk + vtkm::Id3{ 1, 0, 0 }, pdims),
// compute_start(sy, ijk + vtkm::Id3{ 0, 0, 1 }, pdims),
// compute_start(sy, ijk + vtkm::Id3{ 1, 0, 1 }, pdims) };
const auto sliceSize = (pdims[0] * pdims[1]);
return vtkm::Id4{ ijk[0] + (sliceSize * ijk[2]),
ijk[0] + 1 + (sliceSize * ijk[2]),
ijk[0] + (sliceSize * (ijk[2] + 1)),
ijk[0] + 1 + (sliceSize * (ijk[2] + 1)) };
}
VTKM_EXEC inline vtkm::Id compute_inc(SumXAxis, const vtkm::Id3&)
{
return 1;
}
VTKM_EXEC inline vtkm::Id compute_inc(SumYAxis, const vtkm::Id3& dims)
{
return dims[0];
}
//----------------------------------------------------------------------------
template <typename WholeEdgeField>
VTKM_EXEC inline vtkm::UInt8 getEdgeCase(const WholeEdgeField& edges,
const vtkm::Id4& startPos,
vtkm::Id inc)
{
vtkm::UInt8 e0 = edges.Get(startPos[0] + inc);
vtkm::UInt8 e1 = edges.Get(startPos[1] + inc);
vtkm::UInt8 e2 = edges.Get(startPos[2] + inc);
vtkm::UInt8 e3 = edges.Get(startPos[3] + inc);
return static_cast<vtkm::UInt8>(e0 | (e1 << 2) | (e2 << 4) | (e3 << 6));
}
//----------------------------------------------------------------------------
template <typename WholeEdgeField, typename FieldInPointId>
VTKM_EXEC inline bool computeTrimBounds(vtkm::Id rightMax,
const WholeEdgeField& edges,
const FieldInPointId& axis_mins,
const FieldInPointId& axis_maxs,
const vtkm::Id4& startPos,
vtkm::Id inc,
vtkm::Id& left,
vtkm::Id& right)
{
// find adjusted trim values.
left = vtkm::Min(axis_mins[0], axis_mins[1]);
left = vtkm::Min(left, axis_mins[2]);
left = vtkm::Min(left, axis_mins[3]);
right = vtkm::Max(axis_maxs[0], axis_maxs[1]);
right = vtkm::Max(right, axis_maxs[2]);
right = vtkm::Max(right, axis_maxs[3]);
// The trim edges may need adjustment if the contour travels between rows
// of edges (without intersecting these edges). This means checking
// whether the trim faces at (left,right) made up of the edges intersect
// the contour.
if (left > rightMax && right == 0)
{
//verify that we have nothing to generate and early terminate.
bool mins_same = (axis_mins[0] == axis_mins[1] && axis_mins[0] == axis_mins[2] &&
axis_mins[0] == axis_mins[3]);
bool maxs_same = (axis_maxs[0] == axis_maxs[1] && axis_maxs[0] == axis_maxs[2] &&
axis_maxs[0] == axis_maxs[3]);
left = 0;
right = rightMax;
if (mins_same && maxs_same)
{
vtkm::UInt8 e0 = edges.Get(startPos[0]);
vtkm::UInt8 e1 = edges.Get(startPos[1]);
vtkm::UInt8 e2 = edges.Get(startPos[2]);
vtkm::UInt8 e3 = edges.Get(startPos[3]);
if (e0 == e1 && e1 == e2 && e2 == e3)
{
//We have nothing to process in this row
return false;
}
}
}
else
{
vtkm::UInt8 e0 = edges.Get(startPos[0] + (left * inc));
vtkm::UInt8 e1 = edges.Get(startPos[1] + (left * inc));
vtkm::UInt8 e2 = edges.Get(startPos[2] + (left * inc));
vtkm::UInt8 e3 = edges.Get(startPos[3] + (left * inc));
if ((e0 & 0x1) != (e1 & 0x1) || (e1 & 0x1) != (e2 & 0x1) || (e2 & 0x1) != (e3 & 0x1))
{
left = 0;
}
e0 = edges.Get(startPos[0] + (right * inc));
e1 = edges.Get(startPos[1] + (right * inc));
e2 = edges.Get(startPos[2] + (right * inc));
e3 = edges.Get(startPos[3] + (right * inc));
if ((e0 & 0x2) != (e1 & 0x2) || (e1 & 0x2) != (e2 & 0x2) || (e2 & 0x2) != (e3 & 0x2))
{
right = rightMax;
}
}
return true;
}
}
}
}
#endif