1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //
6 //  This software is distributed WITHOUT ANY WARRANTY; without even
7 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 //  PURPOSE.  See the above copyright notice for more information.
9 //============================================================================
10 #ifndef vtk_m_exec_CellFace_h
11 #define vtk_m_exec_CellFace_h
12 
13 #include <vtkm/CellShape.h>
14 #include <vtkm/Deprecated.h>
15 #include <vtkm/ErrorCode.h>
16 #include <vtkm/Types.h>
17 #include <vtkm/exec/FunctorBase.h>
18 
19 namespace vtkm
20 {
21 namespace exec
22 {
23 
24 namespace detail
25 {
26 
27 class CellFaceTables
28 {
29 public:
30   static constexpr vtkm::Int32 MAX_FACE_SIZE = 4;
31   static constexpr vtkm::Int32 MAX_NUM_FACES = 6;
32 
NumFaces(vtkm::Int32 cellShapeId)33   VTKM_EXEC vtkm::Int32 NumFaces(vtkm::Int32 cellShapeId) const
34   {
35     VTKM_STATIC_CONSTEXPR_ARRAY vtkm::Int32 numFaces[vtkm::NUMBER_OF_CELL_SHAPES] = {
36       // NumFaces
37       0, //  0: CELL_SHAPE_EMPTY
38       0, //  1: CELL_SHAPE_VERTEX
39       0, //  2: Unused
40       0, //  3: CELL_SHAPE_LINE
41       0, //  4: CELL_SHAPE_POLY_LINE
42       0, //  5: CELL_SHAPE_TRIANGLE
43       0, //  6: Unused
44       0, //  7: CELL_SHAPE_POLYGON
45       0, //  8: Unused
46       0, //  9: CELL_SHAPE_QUAD
47       4, // 10: CELL_SHAPE_TETRA
48       0, // 11: Unused
49       6, // 12: CELL_SHAPE_HEXAHEDRON
50       5, // 13: CELL_SHAPE_WEDGE
51       5  // 14: CELL_SHAPE_PYRAMID
52     };
53     return numFaces[cellShapeId];
54   }
55 
NumPointsInFace(vtkm::Int32 cellShapeId,vtkm::Int32 faceIndex)56   VTKM_EXEC vtkm::Int32 NumPointsInFace(vtkm::Int32 cellShapeId, vtkm::Int32 faceIndex) const
57   {
58     VTKM_STATIC_CONSTEXPR_ARRAY vtkm::Int32
59       numPointsInFace[vtkm::NUMBER_OF_CELL_SHAPES][MAX_NUM_FACES] = {
60         // NumPointsInFace
61         { -1, -1, -1, -1, -1, -1 }, //  0: CELL_SHAPE_EMPTY
62         { -1, -1, -1, -1, -1, -1 }, //  1: CELL_SHAPE_VERTEX
63         { -1, -1, -1, -1, -1, -1 }, //  2: Unused
64         { -1, -1, -1, -1, -1, -1 }, //  3: CELL_SHAPE_LINE
65         { -1, -1, -1, -1, -1, -1 }, //  4: CELL_SHAPE_POLY_LINE
66         { -1, -1, -1, -1, -1, -1 }, //  5: CELL_SHAPE_TRIANGLE
67         { -1, -1, -1, -1, -1, -1 }, //  6: Unused
68         { -1, -1, -1, -1, -1, -1 }, //  7: CELL_SHAPE_POLYGON
69         { -1, -1, -1, -1, -1, -1 }, //  8: Unused
70         { -1, -1, -1, -1, -1, -1 }, //  9: CELL_SHAPE_QUAD
71         { 3, 3, 3, 3, -1, -1 },     // 10: CELL_SHAPE_TETRA
72         { -1, -1, -1, -1, -1, -1 }, // 11: Unused
73         { 4, 4, 4, 4, 4, 4 },       // 12: CELL_SHAPE_HEXAHEDRON
74         { 3, 3, 4, 4, 4, -1 },      // 13: CELL_SHAPE_WEDGE
75         { 4, 3, 3, 3, 3, -1 }       // 14: CELL_SHAPE_PYRAMID
76       };
77     return numPointsInFace[cellShapeId][faceIndex];
78   }
79 
PointsInFace(vtkm::Int32 cellShapeId,vtkm::Int32 faceIndex,vtkm::Int32 localPointIndex)80   VTKM_EXEC vtkm::Int32 PointsInFace(vtkm::Int32 cellShapeId,
81                                      vtkm::Int32 faceIndex,
82                                      vtkm::Int32 localPointIndex) const
83   {
84     // clang-format off
85     VTKM_STATIC_CONSTEXPR_ARRAY vtkm::Int32 pointsInFace[vtkm::NUMBER_OF_CELL_SHAPES][MAX_NUM_FACES]
86                                                   [MAX_FACE_SIZE] =
87     {
88       // PointsInFace
89       //  0: CELL_SHAPE_EMPTY
90       { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
91         { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } },
92       //  1: CELL_SHAPE_VERTEX
93       { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
94         { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } },
95       //  2: Unused
96       { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
97         { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } },
98       //  3: CELL_SHAPE_LINE
99       { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
100         { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } },
101       //  4: CELL_SHAPE_POLY_LINE
102       { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
103         { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } },
104       //  5: CELL_SHAPE_TRIANGLE
105       { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
106         { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } },
107       //  6: Unused
108       { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
109         { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } },
110       //  7: CELL_SHAPE_POLYGON
111       { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
112         { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } },
113       //  8: Unused
114       { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
115         { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } },
116       //  9: CELL_SHAPE_QUAD
117       { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
118         { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } },
119       // 10: CELL_SHAPE_TETRA
120       { { 0, 1, 3, -1 }, { 1, 2, 3, -1 }, { 2, 0, 3, -1 },
121         { 0, 2, 1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } },
122       // 11: Unused
123       { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 },
124         { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } },
125       // 12: CELL_SHAPE_HEXAHEDRON
126       { { 0, 4, 7, 3 }, { 1, 2, 6, 5 }, { 0, 1, 5, 4 },
127         { 3, 7, 6, 2 }, { 0, 3, 2, 1 }, { 4, 5, 6, 7 } },
128       // 13: CELL_SHAPE_WEDGE
129       { { 0, 1, 2, -1 }, { 3, 5, 4, -1 }, { 0, 3, 4, 1 },
130         { 1, 4, 5, 2 },  { 2, 5, 3, 0 }, { -1, -1, -1, -1 } },
131       // 14: CELL_SHAPE_PYRAMID
132       { { 0, 3, 2, 1 }, { 0, 1, 4, -1 }, { 1, 2, 4, -1 },
133         { 2, 3, 4, -1 }, { 3, 0, 4, -1 },{ -1, -1, -1, -1 } }
134         // clang-format on
135       };
136     return pointsInFace[cellShapeId][faceIndex][localPointIndex];
137   }
138 };
139 
140 } // namespace detail
141 
142 template <typename CellShapeTag>
CellFaceNumberOfFaces(CellShapeTag shape,vtkm::IdComponent & result)143 static inline VTKM_EXEC vtkm::ErrorCode CellFaceNumberOfFaces(CellShapeTag shape,
144                                                               vtkm::IdComponent& result)
145 {
146   (void)shape; //C4100 false positive workaround
147   detail::CellFaceTables table;
148   result = table.NumFaces(shape.Id);
149   return vtkm::ErrorCode::Success;
150 }
151 
152 template <typename CellShapeTag>
153 VTKM_DEPRECATED(1.6, "Signature changed to CellFaceNumberOfFaces(shape, result).")
154 static inline VTKM_EXEC vtkm::IdComponent
CellFaceNumberOfFaces(CellShapeTag shape,const vtkm::exec::FunctorBase & worklet)155   CellFaceNumberOfFaces(CellShapeTag shape, const vtkm::exec::FunctorBase& worklet)
156 {
157   vtkm::IdComponent result;
158   vtkm::ErrorCode status = CellFaceNumberOfFaces(shape, result);
159   if (status != vtkm::ErrorCode::Success)
160   {
161     worklet.RaiseError(vtkm::ErrorString(status));
162   }
163   return result;
164 }
165 
166 template <typename CellShapeTag>
CellFaceNumberOfPoints(vtkm::IdComponent faceIndex,CellShapeTag shape,vtkm::IdComponent & result)167 static inline VTKM_EXEC vtkm::ErrorCode CellFaceNumberOfPoints(vtkm::IdComponent faceIndex,
168                                                                CellShapeTag shape,
169                                                                vtkm::IdComponent& result)
170 {
171   if ((faceIndex < 0) || (faceIndex >= detail::CellFaceTables::MAX_NUM_FACES))
172   {
173     result = -1;
174     return vtkm::ErrorCode::InvalidFaceId;
175   }
176 
177   vtkm::IdComponent numFaces;
178   VTKM_RETURN_ON_ERROR(vtkm::exec::CellFaceNumberOfFaces(shape, numFaces));
179   if (faceIndex >= numFaces)
180   {
181     result = -1;
182     return vtkm::ErrorCode::InvalidFaceId;
183   }
184   detail::CellFaceTables table;
185   result = table.NumPointsInFace(shape.Id, faceIndex);
186   return vtkm::ErrorCode::Success;
187 }
188 
189 template <typename CellShapeTag>
190 VTKM_DEPRECATED(1.6, "Signature changed to CellFaceNumberOfPoints(faceIndex, shape, result).")
191 static inline VTKM_EXEC vtkm::IdComponent
CellFaceNumberOfPoints(vtkm::IdComponent faceIndex,CellShapeTag shape,const vtkm::exec::FunctorBase & worklet)192   CellFaceNumberOfPoints(vtkm::IdComponent faceIndex,
193                          CellShapeTag shape,
194                          const vtkm::exec::FunctorBase& worklet)
195 {
196   vtkm::IdComponent result;
197   vtkm::ErrorCode status = CellFaceNumberOfPoints(faceIndex, shape, result);
198   if (status != vtkm::ErrorCode::Success)
199   {
200     worklet.RaiseError(vtkm::ErrorString(status));
201   }
202   return result;
203 }
204 
205 template <typename CellShapeTag>
CellFaceShape(vtkm::IdComponent faceIndex,CellShapeTag shape,vtkm::UInt8 & result)206 static inline VTKM_EXEC vtkm::ErrorCode CellFaceShape(vtkm::IdComponent faceIndex,
207                                                       CellShapeTag shape,
208                                                       vtkm::UInt8& result)
209 {
210 
211   if ((faceIndex < 0) || (faceIndex >= detail::CellFaceTables::MAX_NUM_FACES))
212   {
213     result = vtkm::CELL_SHAPE_EMPTY;
214     return vtkm::ErrorCode::InvalidFaceId;
215   }
216 
217   vtkm::IdComponent numFacePoints;
218   VTKM_RETURN_ON_ERROR(CellFaceNumberOfPoints(faceIndex, shape, numFacePoints));
219   switch (numFacePoints)
220   {
221     case 3:
222       result = vtkm::CELL_SHAPE_TRIANGLE;
223       break;
224     case 4:
225       result = vtkm::CELL_SHAPE_QUAD;
226       break;
227     default:
228       result = vtkm::CELL_SHAPE_POLYGON;
229       break;
230   }
231   return vtkm::ErrorCode::Success;
232 }
233 
234 template <typename CellShapeTag>
235 VTKM_DEPRECATED(1.6, "Signature changed to CellFaceShape(faceIndex, shape, result).")
CellFaceShape(vtkm::IdComponent faceIndex,CellShapeTag shape,const vtkm::exec::FunctorBase & worklet)236 static inline VTKM_EXEC vtkm::UInt8 CellFaceShape(vtkm::IdComponent faceIndex,
237                                                   CellShapeTag shape,
238                                                   const vtkm::exec::FunctorBase& worklet)
239 {
240   vtkm::UInt8 result;
241   vtkm::ErrorCode status = CellFaceShape(faceIndex, shape, result);
242   if (status != vtkm::ErrorCode::Success)
243   {
244     worklet.RaiseError(vtkm::ErrorString(status));
245   }
246   return result;
247 }
248 
249 template <typename CellShapeTag>
CellFaceLocalIndex(vtkm::IdComponent pointIndex,vtkm::IdComponent faceIndex,CellShapeTag shape,vtkm::IdComponent & result)250 static inline VTKM_EXEC vtkm::ErrorCode CellFaceLocalIndex(vtkm::IdComponent pointIndex,
251                                                            vtkm::IdComponent faceIndex,
252                                                            CellShapeTag shape,
253                                                            vtkm::IdComponent& result)
254 {
255   vtkm::IdComponent numPointsInFace;
256   result = -1;
257   VTKM_RETURN_ON_ERROR(vtkm::exec::CellFaceNumberOfPoints(faceIndex, shape, numPointsInFace));
258   if (numPointsInFace < 1)
259   {
260     // An invalid face. We should already have gotten an error from
261     // CellFaceNumberOfPoints.
262     return vtkm::ErrorCode::InvalidFaceId;
263   }
264 
265   detail::CellFaceTables table;
266   result = table.PointsInFace(shape.Id, faceIndex, pointIndex);
267   return vtkm::ErrorCode::Success;
268 }
269 
270 template <typename CellShapeTag>
271 VTKM_DEPRECATED(1.6,
272                 "Signature changed to CellFaceLocalIndex(pointIndex, faceIndex, shape, result).")
CellFaceLocalIndex(vtkm::IdComponent pointIndex,vtkm::IdComponent faceIndex,CellShapeTag shape,const vtkm::exec::FunctorBase & worklet)273 static inline VTKM_EXEC vtkm::IdComponent CellFaceLocalIndex(vtkm::IdComponent pointIndex,
274                                                              vtkm::IdComponent faceIndex,
275                                                              CellShapeTag shape,
276                                                              const vtkm::exec::FunctorBase& worklet)
277 {
278   vtkm::IdComponent result;
279   vtkm::ErrorCode status = CellFaceLocalIndex(pointIndex, faceIndex, shape, result);
280   if (status != vtkm::ErrorCode::Success)
281   {
282     worklet.RaiseError(vtkm::ErrorString(status));
283   }
284   return result;
285 }
286 
287 /// \brief Returns a canonical identifier for a cell face
288 ///
289 /// Given information about a cell face and the global point indices for that cell, returns a
290 /// vtkm::Id3 that contains values that are unique to that face. The values for two faces will be
291 /// the same if and only if the faces contain the same points.
292 ///
293 /// Note that this property is only true if the mesh is conforming. That is, any two neighboring
294 /// cells that share a face have the same points on that face. This preculdes 2 faces sharing more
295 /// than a single point or single edge.
296 ///
297 template <typename CellShapeTag, typename GlobalPointIndicesVecType>
CellFaceCanonicalId(vtkm::IdComponent faceIndex,CellShapeTag shape,const GlobalPointIndicesVecType & globalPointIndicesVec,vtkm::Id3 & result)298 static inline VTKM_EXEC vtkm::ErrorCode CellFaceCanonicalId(
299   vtkm::IdComponent faceIndex,
300   CellShapeTag shape,
301   const GlobalPointIndicesVecType& globalPointIndicesVec,
302   vtkm::Id3& result)
303 {
304   vtkm::IdComponent numPointsInFace;
305   result = { -1 };
306   VTKM_RETURN_ON_ERROR(vtkm::exec::CellFaceNumberOfPoints(faceIndex, shape, numPointsInFace));
307   if (numPointsInFace == 0)
308   {
309     // An invalid face. We should already have gotten an error from
310     // CellFaceNumberOfPoints.
311     return vtkm::ErrorCode::InvalidFaceId;
312   }
313 
314   detail::CellFaceTables table;
315   //Sort the first 3 face points/nodes in ascending order
316   result = vtkm::Id3(globalPointIndicesVec[table.PointsInFace(shape.Id, faceIndex, 0)],
317                      globalPointIndicesVec[table.PointsInFace(shape.Id, faceIndex, 1)],
318                      globalPointIndicesVec[table.PointsInFace(shape.Id, faceIndex, 2)]);
319   vtkm::Id temp;
320   if (result[0] > result[2])
321   {
322     temp = result[0];
323     result[0] = result[2];
324     result[2] = temp;
325   }
326   if (result[0] > result[1])
327   {
328     temp = result[0];
329     result[0] = result[1];
330     result[1] = temp;
331   }
332   if (result[1] > result[2])
333   {
334     temp = result[1];
335     result[1] = result[2];
336     result[2] = temp;
337   }
338 
339   // Check the rest of the points to see if they are in the lowest 3
340   for (vtkm::IdComponent pointIndex = 3; pointIndex < numPointsInFace; pointIndex++)
341   {
342     vtkm::Id nextPoint = globalPointIndicesVec[table.PointsInFace(shape.Id, faceIndex, pointIndex)];
343     if (nextPoint < result[2])
344     {
345       if (nextPoint < result[1])
346       {
347         result[2] = result[1];
348         if (nextPoint < result[0])
349         {
350           result[1] = result[0];
351           result[0] = nextPoint;
352         }
353         else // nextPoint > P0, nextPoint < P1
354         {
355           result[1] = nextPoint;
356         }
357       }
358       else // nextPoint > P1, nextPoint < P2
359       {
360         result[2] = nextPoint;
361       }
362     }
363     else // nextPoint > P2
364     {
365       // Do nothing. nextPoint not in top 3.
366     }
367   }
368 
369   return vtkm::ErrorCode::Success;
370 }
371 
372 template <typename CellShapeTag, typename GlobalPointIndicesVecType>
373 VTKM_DEPRECATED(1.6,
374                 "Signature changed to CellFaceCononicalId(faceIndex, shape, globalIds, result).")
375 static inline VTKM_EXEC vtkm::Id3
CellFaceCanonicalId(vtkm::IdComponent faceIndex,CellShapeTag shape,const GlobalPointIndicesVecType & globalPointIndicesVec,const vtkm::exec::FunctorBase & worklet)376   CellFaceCanonicalId(vtkm::IdComponent faceIndex,
377                       CellShapeTag shape,
378                       const GlobalPointIndicesVecType& globalPointIndicesVec,
379                       const vtkm::exec::FunctorBase& worklet)
380 {
381   vtkm::Id3 result;
382   vtkm::ErrorCode status = CellFaceCanonicalId(faceIndex, shape, globalPointIndicesVec, result);
383   if (status != vtkm::ErrorCode::Success)
384   {
385     worklet.RaiseError(vtkm::ErrorString(status));
386   }
387   return result;
388 }
389 }
390 } // namespace vtkm::exec
391 
392 #endif //vtk_m_exec_CellFace_h
393