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