2019-07-26 15:20:12 +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.
|
|
|
|
//============================================================================
|
|
|
|
#ifndef vtk_m_worklet_streamsurface_h
|
|
|
|
#define vtk_m_worklet_streamsurface_h
|
|
|
|
|
|
|
|
#include <typeinfo>
|
|
|
|
#include <vtkm/VectorAnalysis.h>
|
|
|
|
#include <vtkm/cont/Algorithm.h>
|
|
|
|
#include <vtkm/cont/ArrayHandleView.h>
|
|
|
|
#include <vtkm/cont/CellSetExplicit.h>
|
|
|
|
#include <vtkm/cont/DataSet.h>
|
|
|
|
#include <vtkm/worklet/DispatcherMapTopology.h>
|
|
|
|
#include <vtkm/worklet/WorkletMapField.h>
|
|
|
|
#include <vtkm/worklet/WorkletMapTopology.h>
|
|
|
|
|
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace worklet
|
|
|
|
{
|
|
|
|
|
|
|
|
class StreamSurface
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
//Helper worklet to count various things in each polyline.
|
2019-07-30 16:53:51 +00:00
|
|
|
class CountPolylines : public vtkm::worklet::WorkletVisitCellsWithPoints
|
2019-07-26 15:20:12 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
VTKM_CONT
|
|
|
|
CountPolylines() {}
|
|
|
|
|
|
|
|
using ControlSignature = void(CellSetIn, WholeArrayInOut invalidCell, FieldOut ptsPerPolyline);
|
|
|
|
using ExecutionSignature = void(CellShape shapeType,
|
|
|
|
PointCount numPoints,
|
|
|
|
_2 isValid,
|
|
|
|
_3 ptsPerPolyline);
|
|
|
|
using InputDomain = _1;
|
|
|
|
|
|
|
|
template <typename CellShapeTag, typename InValidType>
|
|
|
|
VTKM_EXEC void operator()(const CellShapeTag& shapeType,
|
|
|
|
const vtkm::IdComponent& numPoints,
|
|
|
|
InValidType& invalidCell,
|
|
|
|
vtkm::Id& ptsPerPolyline) const
|
|
|
|
{
|
|
|
|
// We only support polylines that contain 2 or more points.
|
|
|
|
if (shapeType.Id == vtkm::CELL_SHAPE_POLY_LINE && numPoints > 1)
|
|
|
|
ptsPerPolyline = numPoints;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
invalidCell.Set(0, 1);
|
|
|
|
ptsPerPolyline = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
|
|
|
|
//Helper worklet to determine number of triangles for each pair of polylines
|
|
|
|
class CountTriangleConn : public vtkm::worklet::WorkletMapField
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
VTKM_CONT
|
|
|
|
CountTriangleConn() {}
|
|
|
|
|
|
|
|
using ControlSignature = void(FieldIn numPts0, FieldIn numPts1, FieldOut outConnCount);
|
|
|
|
using ExecutionSignature = void(_1 numPts0, _2 numPts1, _3 outConnCount);
|
|
|
|
using InputDomain = _1;
|
|
|
|
|
|
|
|
VTKM_EXEC void operator()(const vtkm::Id& numPts0,
|
|
|
|
const vtkm::Id& numPts1,
|
|
|
|
vtkm::Id& outConnCount) const
|
|
|
|
{
|
|
|
|
if (numPts0 == numPts1)
|
|
|
|
outConnCount = (numPts0 - 1) * 2 * 3;
|
|
|
|
else if (numPts1 < numPts0)
|
|
|
|
outConnCount = (numPts0 - 1) * 2 * 3 + (numPts1 - numPts0) * 3;
|
|
|
|
else
|
|
|
|
outConnCount = (numPts1 - 1) * 2 * 3 + (numPts0 - numPts1) * 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
|
|
|
|
//Helper worklet to generate the stream surface cells
|
|
|
|
class GenerateCells : public vtkm::worklet::WorkletMapField
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
VTKM_CONT
|
|
|
|
GenerateCells() {}
|
|
|
|
|
|
|
|
using ControlSignature = void(FieldIn numPts0,
|
|
|
|
FieldIn numPts1,
|
|
|
|
FieldIn offset0,
|
|
|
|
FieldIn offset1,
|
|
|
|
FieldIn connOffset,
|
|
|
|
WholeArrayOut outConn);
|
|
|
|
using ExecutionSignature =
|
|
|
|
void(_1 numPts0, _2 numPts1, _3 ptOffset0, _4 offset1, _5 connOffset, _6 outConn);
|
|
|
|
using InputDomain = _1;
|
|
|
|
|
|
|
|
template <typename OutConnType>
|
|
|
|
VTKM_EXEC void operator()(const vtkm::Id& numPts0,
|
|
|
|
const vtkm::Id& numPts1,
|
|
|
|
const vtkm::Id& offset0,
|
|
|
|
const vtkm::Id& offset1,
|
|
|
|
const vtkm::Id& connOffset,
|
|
|
|
OutConnType& outConn) const
|
|
|
|
{
|
|
|
|
vtkm::Id idx0 = 0, idx1 = 0;
|
|
|
|
vtkm::Id nextToLastIdx0 = numPts0 - 1;
|
|
|
|
vtkm::Id nextToLastIdx1 = numPts1 - 1;
|
|
|
|
vtkm::Id outIdx = connOffset;
|
|
|
|
|
|
|
|
//There could be different numbers of points in the pairs of polylines.
|
|
|
|
//Create pairs of triangles as far as possible.
|
|
|
|
|
|
|
|
/* polyline0 polyline1
|
|
|
|
*
|
|
|
|
* idx0 + 1 x----------- x idx1 + 1
|
|
|
|
* | \ |
|
|
|
|
* | \ Tri2 |
|
|
|
|
* | \ |
|
|
|
|
* | \ |
|
|
|
|
* | Tri1 \ |
|
|
|
|
* | \|
|
|
|
|
* idx0 + 0 x ---------- x idx1 + 0
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
while (idx0 < nextToLastIdx0 && idx1 < nextToLastIdx1)
|
|
|
|
{
|
|
|
|
//Tri 1
|
|
|
|
outConn.Set(outIdx + 0, offset0 + idx0 + 0);
|
|
|
|
outConn.Set(outIdx + 1, offset1 + idx1 + 0);
|
|
|
|
outConn.Set(outIdx + 2, offset0 + idx0 + 1);
|
|
|
|
|
|
|
|
//Tri 2
|
|
|
|
outConn.Set(outIdx + 3, offset0 + idx0 + 1);
|
|
|
|
outConn.Set(outIdx + 4, offset1 + idx1 + 0);
|
|
|
|
outConn.Set(outIdx + 5, offset1 + idx1 + 1);
|
|
|
|
|
|
|
|
idx0++;
|
|
|
|
idx1++;
|
|
|
|
outIdx += 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Same number of points in both polylines. We are done.
|
|
|
|
if (numPts0 == numPts1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
//If we have more points in one polyline, create a triangle fan
|
|
|
|
//to complete the triangulation.
|
|
|
|
//polyline0 is at the end, polyline1 still has more points.
|
|
|
|
/* polyline0 polyline1
|
|
|
|
*
|
|
|
|
* x idx1 + 1
|
|
|
|
* /|
|
|
|
|
* / |
|
|
|
|
* / |
|
|
|
|
* / |
|
|
|
|
* / Tri |
|
|
|
|
* / |
|
|
|
|
* idx0 + 0 x ---------- x idx1 + 0
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
if (idx0 == nextToLastIdx0 && idx1 < nextToLastIdx1)
|
|
|
|
{
|
|
|
|
while (idx1 < nextToLastIdx1)
|
|
|
|
{
|
|
|
|
outConn.Set(outIdx + 0, offset0 + idx0 + 0);
|
|
|
|
outConn.Set(outIdx + 1, offset1 + idx1 + 0);
|
|
|
|
outConn.Set(outIdx + 2, offset1 + idx1 + 1);
|
|
|
|
idx1++;
|
|
|
|
outIdx += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//polyline1 is at the end, polyline0 still has more points.
|
|
|
|
/* polyline0 polyline1
|
|
|
|
*
|
|
|
|
* idx0 + 1 x
|
|
|
|
* | \
|
|
|
|
* | \
|
|
|
|
* | \
|
|
|
|
* | \
|
|
|
|
* | Tri \
|
|
|
|
* | \
|
|
|
|
* idx0 + 0 x ---------- x idx1 + 0
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (idx0 < nextToLastIdx0)
|
|
|
|
{
|
|
|
|
outConn.Set(outIdx + 0, offset0 + idx0 + 0);
|
|
|
|
outConn.Set(outIdx + 1, offset1 + idx1 + 0);
|
|
|
|
outConn.Set(outIdx + 2, offset0 + idx0 + 1);
|
|
|
|
idx0++;
|
|
|
|
outIdx += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
|
|
|
|
VTKM_CONT
|
|
|
|
StreamSurface() {}
|
|
|
|
|
|
|
|
VTKM_CONT
|
|
|
|
void Run(const vtkm::cont::CoordinateSystem& coords,
|
|
|
|
const vtkm::cont::DynamicCellSet& cellset,
|
2019-07-31 16:20:38 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Vec3f>& newPoints,
|
2019-07-26 15:20:12 +00:00
|
|
|
vtkm::cont::CellSetSingleType<>& newCells)
|
|
|
|
{
|
2019-07-31 16:20:38 +00:00
|
|
|
using ExplCoordsType = vtkm::cont::ArrayHandle<vtkm::Vec3f>;
|
2019-07-26 15:20:12 +00:00
|
|
|
|
|
|
|
if (!(coords.GetData().IsType<ExplCoordsType>() &&
|
|
|
|
(cellset.IsSameType(vtkm::cont::CellSetExplicit<>()) ||
|
|
|
|
cellset.IsSameType(vtkm::cont::CellSetSingleType<>()))))
|
|
|
|
{
|
|
|
|
throw vtkm::cont::ErrorBadValue("Stream surface requires polyline data.");
|
|
|
|
}
|
|
|
|
|
|
|
|
//Count number of polylines and make sure we ONLY have polylines
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> ptsPerPolyline, invalidCell;
|
|
|
|
vtkm::worklet::DispatcherMapTopology<CountPolylines> countInvoker;
|
|
|
|
|
|
|
|
//We only care if there are ANY non-polyline cells. So use a one element array.
|
|
|
|
//Any non-polyline cell will set the value to 1. No need to worry about race conditions
|
|
|
|
//as the outcasts will all set it to the same value.
|
|
|
|
invalidCell.Allocate(1);
|
2020-01-28 19:14:32 +00:00
|
|
|
invalidCell.WritePortal().Set(0, 0);
|
2019-07-26 15:20:12 +00:00
|
|
|
countInvoker.Invoke(cellset, invalidCell, ptsPerPolyline);
|
|
|
|
|
2020-01-28 19:14:32 +00:00
|
|
|
if (invalidCell.ReadPortal().Get(0) == 1)
|
2019-07-26 15:20:12 +00:00
|
|
|
throw vtkm::cont::ErrorBadValue("Stream surface requires only polyline data.");
|
|
|
|
|
|
|
|
vtkm::Id numPolylines = cellset.GetNumberOfCells();
|
|
|
|
|
|
|
|
//Compute polyline offsets
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> polylineOffset;
|
|
|
|
vtkm::cont::Algorithm::ScanExclusive(ptsPerPolyline, polylineOffset);
|
|
|
|
|
|
|
|
auto ptsPerPolyline0 = vtkm::cont::make_ArrayHandleView(ptsPerPolyline, 0, numPolylines - 1);
|
|
|
|
auto ptsPerPolyline1 = vtkm::cont::make_ArrayHandleView(ptsPerPolyline, 1, numPolylines - 1);
|
|
|
|
|
|
|
|
//Count the number of triangles to be generated
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> triangleConnCount, triangleConnOffset;
|
|
|
|
vtkm::worklet::DispatcherMapField<CountTriangleConn> countTriInvoker;
|
|
|
|
countTriInvoker.Invoke(ptsPerPolyline0, ptsPerPolyline1, triangleConnCount);
|
|
|
|
vtkm::cont::Algorithm::ScanExclusive(triangleConnCount, triangleConnOffset);
|
|
|
|
|
|
|
|
//Surface points are same as input points.
|
|
|
|
newPoints = coords.GetData().Cast<ExplCoordsType>();
|
|
|
|
|
|
|
|
//Create surface triangles
|
|
|
|
vtkm::Id numConnIds = vtkm::cont::Algorithm::Reduce(triangleConnCount, vtkm::Id(0));
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id> newConnectivity;
|
|
|
|
newConnectivity.Allocate(numConnIds);
|
|
|
|
vtkm::worklet::DispatcherMapField<GenerateCells> genCellsDisp;
|
|
|
|
|
|
|
|
genCellsDisp.Invoke(ptsPerPolyline0,
|
|
|
|
ptsPerPolyline1,
|
|
|
|
vtkm::cont::make_ArrayHandleView(polylineOffset, 0, numPolylines - 1),
|
|
|
|
vtkm::cont::make_ArrayHandleView(polylineOffset, 1, numPolylines - 1),
|
|
|
|
triangleConnOffset,
|
|
|
|
newConnectivity);
|
|
|
|
newCells.Fill(numConnIds, vtkm::CELL_SHAPE_TRIANGLE, 3, newConnectivity);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // vtk_m_worklet_streamsurface_h
|