1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //  This software is distributed WITHOUT ANY WARRANTY; without even
6 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
7 //  PURPOSE.  See the above copyright notice for more information.
8 //
9 //  Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
10 //  Copyright 2015 UT-Battelle, LLC.
11 //  Copyright 2015 Los Alamos National Security.
12 //
13 //  Under the terms of Contract DE-NA0003525 with NTESS,
14 //  the U.S. Government retains certain rights in this software.
15 //
16 //  Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
17 //  Laboratory (LANL), the U.S. Government retains certain rights in
18 //  this software.
19 //============================================================================
20 
21 #include <vtkm/rendering/raytracing/CylinderExtractor.h>
22 
23 #include <vtkm/cont/Algorithm.h>
24 #include <vtkm/rendering/Cylinderizer.h>
25 #include <vtkm/rendering/raytracing/Worklets.h>
26 #include <vtkm/worklet/DispatcherMapField.h>
27 #include <vtkm/worklet/DispatcherMapTopology.h>
28 
29 namespace vtkm
30 {
31 namespace rendering
32 {
33 namespace raytracing
34 {
35 
36 namespace detail
37 {
38 
39 class CountSegments : public vtkm::worklet::WorkletMapPointToCell
40 {
41 public:
42   VTKM_CONT
CountSegments()43   CountSegments() {}
44   typedef void ControlSignature(CellSetIn cellset, FieldOut<>);
45   typedef void ExecutionSignature(CellShape, _2);
46 
47   VTKM_EXEC
operator ()(vtkm::CellShapeTagGeneric shapeType,vtkm::Id & segments) const48   void operator()(vtkm::CellShapeTagGeneric shapeType, vtkm::Id& segments) const
49   {
50     if (shapeType.Id == vtkm::CELL_SHAPE_LINE)
51       segments = 1;
52     else if (shapeType.Id == vtkm::CELL_SHAPE_TRIANGLE)
53       segments = 3;
54     else if (shapeType.Id == vtkm::CELL_SHAPE_QUAD)
55       segments = 4;
56     else
57       segments = 0;
58   }
59 
60   VTKM_EXEC
operator ()(vtkm::CellShapeTagHexahedron vtkmNotUsed (shapeType),vtkm::Id & points) const61   void operator()(vtkm::CellShapeTagHexahedron vtkmNotUsed(shapeType), vtkm::Id& points) const
62   {
63     points = 0;
64   }
65 
66   VTKM_EXEC
operator ()(vtkm::CellShapeTagQuad vtkmNotUsed (shapeType),vtkm::Id & points) const67   void operator()(vtkm::CellShapeTagQuad vtkmNotUsed(shapeType), vtkm::Id& points) const
68   {
69     points = 0;
70   }
71 
72 }; // ClassCountSegments
73 
74 class Pointify : public vtkm::worklet::WorkletMapPointToCell
75 {
76 
77 public:
78   VTKM_CONT
Pointify()79   Pointify() {}
80   typedef void ControlSignature(CellSetIn cellset, FieldInCell<>, WholeArrayOut<>);
81   typedef void ExecutionSignature(_2, CellShape, PointIndices, WorkIndex, _3);
82 
83   template <typename VecType, typename OutputPortal>
operator ()(const vtkm::Id & vtkmNotUsed (pointOffset),vtkm::CellShapeTagQuad vtkmNotUsed (shapeType),const VecType & vtkmNotUsed (cellIndices),const vtkm::Id & vtkmNotUsed (cellId),OutputPortal & vtkmNotUsed (outputIndices)) const84   VTKM_EXEC void operator()(const vtkm::Id& vtkmNotUsed(pointOffset),
85                             vtkm::CellShapeTagQuad vtkmNotUsed(shapeType),
86                             const VecType& vtkmNotUsed(cellIndices),
87                             const vtkm::Id& vtkmNotUsed(cellId),
88                             OutputPortal& vtkmNotUsed(outputIndices)) const
89   {
90   }
91 
92   template <typename VecType, typename OutputPortal>
operator ()(const vtkm::Id & vtkmNotUsed (pointOffset),vtkm::CellShapeTagHexahedron vtkmNotUsed (shapeType),const VecType & vtkmNotUsed (cellIndices),const vtkm::Id & vtkmNotUsed (cellId),OutputPortal & vtkmNotUsed (outputIndices)) const93   VTKM_EXEC void operator()(const vtkm::Id& vtkmNotUsed(pointOffset),
94                             vtkm::CellShapeTagHexahedron vtkmNotUsed(shapeType),
95                             const VecType& vtkmNotUsed(cellIndices),
96                             const vtkm::Id& vtkmNotUsed(cellId),
97                             OutputPortal& vtkmNotUsed(outputIndices)) const
98 
99   {
100   }
101 
102   template <typename VecType, typename OutputPortal>
operator ()(const vtkm::Id & pointOffset,vtkm::CellShapeTagGeneric shapeType,const VecType & cellIndices,const vtkm::Id & cellId,OutputPortal & outputIndices) const103   VTKM_EXEC void operator()(const vtkm::Id& pointOffset,
104                             vtkm::CellShapeTagGeneric shapeType,
105                             const VecType& cellIndices,
106                             const vtkm::Id& cellId,
107                             OutputPortal& outputIndices) const
108   {
109 
110     if (shapeType.Id == vtkm::CELL_SHAPE_LINE)
111     {
112       vtkm::Id3 segment;
113       segment[0] = cellId;
114       segment[1] = cellIndices[0];
115       segment[2] = cellIndices[1];
116       outputIndices.Set(pointOffset, segment);
117     }
118     else if (shapeType.Id == vtkm::CELL_SHAPE_TRIANGLE)
119     {
120       vtkm::Id3 segment;
121       segment[0] = cellId;
122       segment[1] = cellIndices[0];
123       segment[2] = cellIndices[1];
124       outputIndices.Set(pointOffset, segment);
125 
126       segment[1] = cellIndices[1];
127       segment[2] = cellIndices[2];
128       outputIndices.Set(pointOffset + 1, segment);
129 
130       segment[1] = cellIndices[2];
131       segment[2] = cellIndices[0];
132       outputIndices.Set(pointOffset + 2, segment);
133     }
134     else if (shapeType.Id == vtkm::CELL_SHAPE_QUAD)
135     {
136       vtkm::Id3 segment;
137       segment[0] = cellId;
138       segment[1] = cellIndices[0];
139       segment[2] = cellIndices[1];
140       outputIndices.Set(pointOffset, segment);
141 
142       segment[1] = cellIndices[1];
143       segment[2] = cellIndices[2];
144       outputIndices.Set(pointOffset + 1, segment);
145 
146       segment[1] = cellIndices[2];
147       segment[2] = cellIndices[3];
148       outputIndices.Set(pointOffset + 2, segment);
149 
150       segment[1] = cellIndices[3];
151       segment[2] = cellIndices[0];
152       outputIndices.Set(pointOffset + 3, segment);
153     }
154   }
155 }; //class pointify
156 
157 class Iterator : public vtkm::worklet::WorkletMapField
158 {
159 
160 public:
161   VTKM_CONT
Iterator()162   Iterator() {}
163   typedef void ControlSignature(FieldOut<>);
164   typedef void ExecutionSignature(_1, WorkIndex);
165   VTKM_EXEC
operator ()(vtkm::Id2 & index,const vtkm::Id2 & idx) const166   void operator()(vtkm::Id2& index, const vtkm::Id2& idx) const { index = idx; }
167 }; //class Iterator
168 
169 class FieldRadius : public vtkm::worklet::WorkletMapField
170 {
171 protected:
172   vtkm::Float32 MinRadius;
173   vtkm::Float32 RadiusDelta;
174   vtkm::Float32 MinValue;
175   vtkm::Float32 InverseDelta;
176 
177 public:
178   VTKM_CONT
FieldRadius(const vtkm::Float32 minRadius,const vtkm::Float32 maxRadius,const vtkm::Range scalarRange)179   FieldRadius(const vtkm::Float32 minRadius,
180               const vtkm::Float32 maxRadius,
181               const vtkm::Range scalarRange)
182     : MinRadius(minRadius)
183     , RadiusDelta(maxRadius - minRadius)
184     , MinValue(static_cast<vtkm::Float32>(scalarRange.Min))
185   {
186     vtkm::Float32 delta = static_cast<vtkm::Float32>(scalarRange.Max - scalarRange.Min);
187     if (delta != 0.f)
188       InverseDelta = 1.f / (delta);
189     else
190       InverseDelta = 0.f; // just map scalar to 0;
191   }
192 
193   typedef void ControlSignature(FieldIn<>, FieldOut<>, WholeArrayIn<Scalar>);
194   typedef void ExecutionSignature(_1, _2, _3);
195 
196   template <typename ScalarPortalType>
operator ()(const vtkm::Id3 & cylId,vtkm::Float32 & radius,const ScalarPortalType & scalars) const197   VTKM_EXEC void operator()(const vtkm::Id3& cylId,
198                             vtkm::Float32& radius,
199                             const ScalarPortalType& scalars) const
200   {
201     vtkm::Float32 scalar = static_cast<vtkm::Float32>(scalars.Get(cylId[0]));
202     vtkm::Float32 t = (scalar - MinValue) * InverseDelta;
203     radius = MinRadius + t * RadiusDelta;
204   }
205 
206 }; //class FieldRadius
207 
208 } //namespace detail
209 
210 
ExtractCells(const vtkm::cont::DynamicCellSet & cells,const vtkm::Float32 radius)211 void CylinderExtractor::ExtractCells(const vtkm::cont::DynamicCellSet& cells,
212                                      const vtkm::Float32 radius)
213 {
214   vtkm::Id numOfSegments;
215   vtkm::rendering::Cylinderizer geometrizer;
216   geometrizer.Run(cells, this->CylIds, numOfSegments);
217 
218   this->SetUniformRadius(radius);
219 }
220 
ExtractCells(const vtkm::cont::DynamicCellSet & cells,const vtkm::cont::Field & field,const vtkm::Float32 minRadius,const vtkm::Float32 maxRadius)221 void CylinderExtractor::ExtractCells(const vtkm::cont::DynamicCellSet& cells,
222                                      const vtkm::cont::Field& field,
223                                      const vtkm::Float32 minRadius,
224                                      const vtkm::Float32 maxRadius)
225 {
226   vtkm::Id numOfSegments;
227   vtkm::rendering::Cylinderizer geometrizer;
228   geometrizer.Run(cells, this->CylIds, numOfSegments);
229 
230   this->SetVaryingRadius(minRadius, maxRadius, field);
231 }
232 
SetUniformRadius(const vtkm::Float32 radius)233 void CylinderExtractor::SetUniformRadius(const vtkm::Float32 radius)
234 {
235   const vtkm::Id size = this->CylIds.GetNumberOfValues();
236   Radii.Allocate(size);
237 
238   vtkm::cont::ArrayHandleConstant<vtkm::Float32> radiusHandle(radius, size);
239   vtkm::cont::Algorithm::Copy(radiusHandle, Radii);
240 }
241 
SetCylinderIdsFromCells(const vtkm::cont::DynamicCellSet & cells)242 void CylinderExtractor::SetCylinderIdsFromCells(const vtkm::cont::DynamicCellSet& cells)
243 {
244   vtkm::Id numCells = cells.GetNumberOfCells();
245   if (numCells == 0)
246   {
247     return;
248   }
249   //
250   // look for points in the cell set
251   //
252   if (cells.IsSameType(vtkm::cont::CellSetExplicit<>()))
253   {
254     vtkm::cont::ArrayHandle<vtkm::Id> points;
255     vtkm::worklet::DispatcherMapTopology<detail::CountSegments>(detail::CountSegments())
256       .Invoke(cells, points);
257 
258     vtkm::Id totalPoints = 0;
259     totalPoints = vtkm::cont::Algorithm::Reduce(points, vtkm::Id(0));
260 
261     vtkm::cont::ArrayHandle<vtkm::Id> cellOffsets;
262     vtkm::cont::Algorithm::ScanExclusive(points, cellOffsets);
263     CylIds.Allocate(totalPoints);
264 
265     vtkm::worklet::DispatcherMapTopology<detail::Pointify>(detail::Pointify())
266       .Invoke(cells, cellOffsets, this->CylIds);
267   }
268 }
269 
SetVaryingRadius(const vtkm::Float32 minRadius,const vtkm::Float32 maxRadius,const vtkm::cont::Field & field)270 void CylinderExtractor::SetVaryingRadius(const vtkm::Float32 minRadius,
271                                          const vtkm::Float32 maxRadius,
272                                          const vtkm::cont::Field& field)
273 {
274   vtkm::cont::ArrayHandle<vtkm::Range> rangeArray = field.GetRange();
275   if (rangeArray.GetNumberOfValues() != 1)
276   {
277     throw vtkm::cont::ErrorBadValue("Cylinder Extractor: scalar field must have one component");
278   }
279 
280   vtkm::Range range = rangeArray.GetPortalConstControl().Get(0);
281 
282   Radii.Allocate(this->CylIds.GetNumberOfValues());
283   vtkm::worklet::DispatcherMapField<detail::FieldRadius>(
284     detail::FieldRadius(minRadius, maxRadius, range))
285     .Invoke(this->CylIds, this->Radii, field);
286 }
287 
288 
GetCylIds()289 vtkm::cont::ArrayHandle<vtkm::Id3> CylinderExtractor::GetCylIds()
290 {
291   return this->CylIds;
292 }
293 
GetRadii()294 vtkm::cont::ArrayHandle<vtkm::Float32> CylinderExtractor::GetRadii()
295 {
296   return this->Radii;
297 }
298 
GetNumberOfCylinders() const299 vtkm::Id CylinderExtractor::GetNumberOfCylinders() const
300 {
301   return this->CylIds.GetNumberOfValues();
302 }
303 }
304 }
305 } //namespace vtkm::rendering::raytracing
306