omega_h
Reliable mesh adaptation
r3d.hpp
1 /* Dan Ibanez: This code is modified from Devon Powell's
2  * original r3d code, whose copyright notice is reproduced below:
3  * ----
4  * Routines for fast, geometrically robust clipping operations
5  * and analytic volume/moment computations over polyhedra in 3D.
6  *
7  * Devon Powell
8  * 31 August 2015
9  *
10  * This program was prepared by Los Alamos National Security, LLC at Los Alamos
11  * National Laboratory (LANL) under contract No. DE-AC52-06NA25396 with the U.S.
12  * Department of Energy (DOE). All rights in the program are reserved by the DOE
13  * and Los Alamos National Security, LLC. Permission is granted to the public to
14  * copy and use this software without charge, provided that this Notice and any
15  * statement of authorship are reproduced on all copies. Neither the U.S.
16  * Government nor LANS makes any warranty, express or implied, or assumes any
17  * liability or responsibility for the use of this software.
18  * ----
19  * We keep our own copy due to two major changes:
20  * (1) annotation to execute on GPUs via CUDA using Kokkos.
21  * this also requires the code to be in a header file,
22  * because Kokkos is incompatible with relocatable device code
23  * in CUDA versions prior to 8.0.
24  * (2) rewritten in modern C++ with templating over
25  * dimension where easily applicable.
26  */
27 
28 #ifndef R3D_HPP
29 #define R3D_HPP
30 
31 #include <cfloat>
32 #include <cmath>
33 #include <initializer_list>
34 #include <new>
35 #include <type_traits>
36 
37 #if defined(R3D_USE_KOKKOS)
38 #define R3D_INLINE KOKKOS_INLINE_FUNCTION
39 #else
40 #define R3D_INLINE inline
41 #endif
42 
43 /* The MAX_VERTS constants are more than just the maximum number
44  of vertices of a representable polytope: the clip() code actually
45  adds new vertices prior to removing old ones, so this actually
46  needs to be the maximum number of representable vertices
47  plus the maximum number of representable edges intersected by a plane */
48 
49 #ifndef R1D_MAX_VERTS
50 #define R1D_MAX_VERTS 4
51 #endif
52 
53 #ifndef R2D_MAX_VERTS
54 #define R2D_MAX_VERTS 64
55 #endif
56 
57 #ifndef R3D_MAX_VERTS
58 #define R3D_MAX_VERTS 128
59 #endif
60 
61 namespace r3d {
62 
63 using Real = double;
64 using Int = int;
65 
66 constexpr Real ONE_THIRD = (1.0 / 3.0);
67 constexpr Real ONE_SIXTH = (1.0 / 6.0);
68 
69 template <typename T>
70 struct ArithTraits;
71 
72 template <>
73 struct ArithTraits<double> {
74  static R3D_INLINE double max() { return DBL_MAX; }
75  static R3D_INLINE double min() { return -DBL_MAX; }
76 };
77 
78 R3D_INLINE Real cube(Real x) { return x * x * x; }
79 
80 template <typename T>
81 constexpr R3D_INLINE T square(T x) {
82  return x * x;
83 }
84 
85 template<typename T, int N>
86 using Few = Omega_h::Few<T, N>;
87 
88 template <Int n>
89 struct Vector : public Few<Real, n> {
90  R3D_INLINE Vector() {}
91  inline Vector(std::initializer_list<Real> l) : Few<Real, n>(l) {}
92  R3D_INLINE void operator=(Vector<n> const& rhs) {
94  }
95  R3D_INLINE Vector(Vector<n> const& rhs) : Few<Real, n>(rhs) {}
96 };
97 
98 R3D_INLINE Vector<2> vector_2(Real x, Real y) {
99  Vector<2> v;
100  v[0] = x;
101  v[1] = y;
102  return v;
103 }
104 
105 R3D_INLINE Vector<3> vector_3(Real x, Real y, Real z) {
106  Vector<3> v;
107  v[0] = x;
108  v[1] = y;
109  v[2] = z;
110  return v;
111 }
112 
113 template <Int n>
114 R3D_INLINE Vector<n> operator+(Vector<n> a, Vector<n> b) {
115  Vector<n> c;
116  for (Int i = 0; i < n; ++i) c[i] = a[i] + b[i];
117  return c;
118 }
119 
120 template <Int n>
121 R3D_INLINE Vector<n>& operator+=(Vector<n>& a, Vector<n> b) {
122  a = a + b;
123  return a;
124 }
125 
126 template <Int n>
127 R3D_INLINE Vector<n> operator-(Vector<n> a, Vector<n> b) {
128  Vector<n> c;
129  for (Int i = 0; i < n; ++i) c[i] = a[i] - b[i];
130  return c;
131 }
132 
133 template <Int n>
134 R3D_INLINE Vector<n>& operator-=(Vector<n>& a, Vector<n> b) {
135  a = a - b;
136  return a;
137 }
138 
139 template <Int n>
140 R3D_INLINE Vector<n> operator-(Vector<n> a) {
141  Vector<n> c;
142  for (Int i = 0; i < n; ++i) c[i] = -a[i];
143  return c;
144 }
145 
146 template <Int n>
147 R3D_INLINE Vector<n> operator*(Vector<n> a, Real b) {
148  Vector<n> c;
149  for (Int i = 0; i < n; ++i) c[i] = a[i] * b;
150  return c;
151 }
152 
153 template <Int n>
154 R3D_INLINE Vector<n>& operator*=(Vector<n>& a, Real b) {
155  a = a * b;
156  return a;
157 }
158 
159 template <Int n>
160 R3D_INLINE Vector<n> operator*(Real a, Vector<n> b) {
161  return b * a;
162 }
163 
164 template <Int n>
165 R3D_INLINE Vector<n> operator/(Vector<n> a, Real b) {
166  Vector<n> c;
167  for (Int i = 0; i < n; ++i) c[i] = a[i] / b;
168  return c;
169 }
170 
171 template <Int n>
172 R3D_INLINE Vector<n>& operator/=(Vector<n>& a, Real b) {
173  a = a / b;
174  return a;
175 }
176 
177 template <Int n>
178 R3D_INLINE Real operator*(Vector<n> a, Vector<n> b) {
179  Real c = a[0] * b[0];
180  for (Int i = 1; i < n; ++i) c += a[i] * b[i];
181  return c;
182 }
183 
184 template <Int n>
185 R3D_INLINE Real norm_squared(Vector<n> v) {
186  return v * v;
187 }
188 
189 template <Int n>
190 R3D_INLINE Real norm(Vector<n> v) {
191  return std::sqrt(norm_squared(v));
192 }
193 
194 template <Int n>
195 R3D_INLINE Vector<n> normalize(Vector<n> v) {
196  return v / norm(v);
197 }
198 
199 R3D_INLINE Vector<3> cross(Vector<3> a, Vector<3> b) {
200  return vector_3(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],
201  a[0] * b[1] - a[1] * b[0]);
202 }
203 
204 template <Int dim>
205 struct Plane {
207  Real d;
208 };
209 
210 template <Int dim>
211 struct Vertex {
212  Int pnbrs[dim];
214 };
215 
216 template <Int dim>
217 struct MaxVerts;
218 
219 template <>
220 struct MaxVerts<1> {
221  enum { value = R1D_MAX_VERTS };
222 };
223 
224 template <>
225 struct MaxVerts<2> {
226  enum { value = R2D_MAX_VERTS };
227 };
228 
229 template <>
230 struct MaxVerts<3> {
231  enum { value = R3D_MAX_VERTS };
232 };
233 
237 template <Int dim>
238 struct Polytope {
239  enum { max_verts = MaxVerts<dim>::value };
240  Vertex<dim> verts[max_verts];
241  Int nverts;
242 };
243 
244 template <Int dim>
245 R3D_INLINE Vector<dim> wav(Vector<dim> va, Real wa, Vector<dim> vb, Real wb) {
246  Vector<dim> vr;
247  for (Int i = 0; i < dim; ++i) vr[i] = (wa * va[i] + wb * vb[i]) / (wa + wb);
248  return vr;
249 }
250 
251 /* This class encapsulates the code that was different
252  * between r3d_clip and r2d_clip
253  */
254 
255 template <Int dim>
256 struct ClipHelper;
257 
258 template <>
259 struct ClipHelper<3> {
260  R3D_INLINE static void finalize_links(Int onv, Polytope<3>& poly) {
261  for (auto vstart = onv; vstart < poly.nverts; ++vstart) {
262  auto vcur = vstart;
263  auto vnext = poly.verts[vcur].pnbrs[0];
264  do {
265  Int np;
266  for (np = 0; np < 3; ++np)
267  if (poly.verts[vnext].pnbrs[np] == vcur) break;
268  vcur = vnext;
269  auto pnext = (np + 1) % 3;
270  vnext = poly.verts[vcur].pnbrs[pnext];
271  } while (vcur < onv);
272  poly.verts[vstart].pnbrs[2] = vcur;
273  poly.verts[vcur].pnbrs[1] = vstart;
274  }
275  }
276  R3D_INLINE static void init_new_vert_link(
277  Polytope<3>& poly, Int vcur, Int np) {
278  (void)np;
279  poly.verts[poly.nverts].pnbrs[0] = vcur;
280  }
281 };
282 
283 template <>
284 struct ClipHelper<2> {
285  R3D_INLINE static void finalize_links(Int onv, Polytope<2>& poly) {
286  for (auto vstart = onv; vstart < poly.nverts; ++vstart) {
287  if (poly.verts[vstart].pnbrs[1] >= 0) continue;
288  auto vcur = poly.verts[vstart].pnbrs[0];
289  do {
290  vcur = poly.verts[vcur].pnbrs[0];
291  } while (vcur < onv);
292  poly.verts[vstart].pnbrs[1] = vcur;
293  poly.verts[vcur].pnbrs[0] = vstart;
294  }
295  }
296  R3D_INLINE static void init_new_vert_link(
297  Polytope<2>& poly, Int vcur, Int np) {
298  poly.verts[poly.nverts].pnbrs[1 - np] = vcur;
299  poly.verts[poly.nverts].pnbrs[np] = -1;
300  }
301 };
302 
303 template <>
304 struct ClipHelper<1> {
305  R3D_INLINE static void finalize_links(Int, Polytope<1>&) {}
306  R3D_INLINE static void init_new_vert_link(
307  Polytope<1>& poly, Int vcur, Int np) {
308  poly.verts[poly.nverts].pnbrs[np] = vcur;
309  }
310 };
311 
323 template <Int dim>
324 R3D_INLINE void clip(
325  Polytope<dim>& poly, Plane<dim> const* planes, Int nplanes) {
326  if (poly.nverts <= 0) return;
327 
328  // variable declarations
329  Int v, p, np, onv, vcur, vnext, numunclipped;
330 
331  // signed distances to the clipping plane
332  Real sdists[Polytope<dim>::max_verts];
333  Real smin, smax;
334 
335  // loop over each clip plane
336  for (p = 0; p < nplanes; ++p) {
337  // calculate signed distances to the clip plane
338  onv = poly.nverts;
339  smin = ArithTraits<Real>::max();
340  smax = ArithTraits<Real>::min();
341 
342  // for marking clipped vertices
343  Int clipped[MaxVerts<dim>::value] = {}; // all initialized to zero
344  for (v = 0; v < onv; ++v) {
345  sdists[v] = planes[p].d + (poly.verts[v].pos * planes[p].n);
346  if (sdists[v] < smin) smin = sdists[v];
347  if (sdists[v] > smax) smax = sdists[v];
348  if (sdists[v] < 0.0) clipped[v] = 1;
349  }
350 
351  // skip this face if the poly lies entirely on one side of it
352  if (smin >= 0.0) continue;
353  if (smax <= 0.0) {
354  poly.nverts = 0;
355  return;
356  }
357 
358  // check all edges and insert new vertices on the bisected edges
359  for (vcur = 0; vcur < onv; ++vcur) {
360  if (clipped[vcur]) continue;
361  for (np = 0; np < dim; ++np) {
362  vnext = poly.verts[vcur].pnbrs[np];
363  if (!clipped[vnext]) continue;
364  ClipHelper<dim>::init_new_vert_link(poly, vcur, np);
365  poly.verts[vcur].pnbrs[np] = poly.nverts;
366  poly.verts[poly.nverts].pos = wav(poly.verts[vcur].pos, -sdists[vnext],
367  poly.verts[vnext].pos, sdists[vcur]);
368  ++(poly.nverts);
369  }
370  }
371 
372  // for each new vert, search around the poly for its new neighbors
373  // and doubly-link everything
374  ClipHelper<dim>::finalize_links(onv, poly);
375 
376  // go through and compress the vertex list, removing clipped verts
377  // and re-indexing accordingly (reusing `clipped` to re-index everything)
378  numunclipped = 0;
379  for (v = 0; v < poly.nverts; ++v) {
380  if (!clipped[v]) {
381  poly.verts[numunclipped] = poly.verts[v];
382  clipped[v] = numunclipped++;
383  }
384  }
385  poly.nverts = numunclipped;
386  for (v = 0; v < poly.nverts; ++v)
387  for (np = 0; np < dim; ++np)
388  poly.verts[v].pnbrs[np] = clipped[poly.verts[v].pnbrs[np]];
389  }
390 }
391 
392 template <Int dim>
393 R3D_INLINE void clip(Polytope<dim>& poly, Plane<dim> const& plane) {
394  clip(poly, &plane, 1);
395 }
396 
397 template <Int dim, Int nplanes>
398 R3D_INLINE void clip(Polytope<dim>& poly, Few<Plane<dim>, nplanes> planes) {
399  clip(poly, &planes[0], nplanes);
400 }
401 
409 R3D_INLINE void init(Polytope<3>& poly, Few<Vector<3>, 4> verts) {
410  // initialize graph connectivity
411  poly.nverts = 4;
412  poly.verts[0].pnbrs[0] = 1;
413  poly.verts[0].pnbrs[1] = 3;
414  poly.verts[0].pnbrs[2] = 2;
415  poly.verts[1].pnbrs[0] = 2;
416  poly.verts[1].pnbrs[1] = 3;
417  poly.verts[1].pnbrs[2] = 0;
418  poly.verts[2].pnbrs[0] = 0;
419  poly.verts[2].pnbrs[1] = 3;
420  poly.verts[2].pnbrs[2] = 1;
421  poly.verts[3].pnbrs[0] = 1;
422  poly.verts[3].pnbrs[1] = 2;
423  poly.verts[3].pnbrs[2] = 0;
424 
425  // copy vertex coordinates
426  for (Int v = 0; v < 4; ++v) poly.verts[v].pos = verts[v];
427 }
428 
436 R3D_INLINE void init(Polytope<2>& poly, Few<Vector<2>, 3> vertices) {
437  constexpr Int numverts = 3;
438  // init the poly
439  poly.nverts = numverts;
440  for (Int v = 0; v < poly.nverts; ++v) {
441  poly.verts[v].pos = vertices[v];
442  poly.verts[v].pnbrs[0] = (v + 1) % (numverts);
443  poly.verts[v].pnbrs[1] = (numverts + v - 1) % (numverts);
444  }
445 }
446 
450 R3D_INLINE void init(Polytope<1>& poly, Few<Vector<1>, 2> vertices) {
451  constexpr Int numverts = 2;
452  // init the poly
453  poly.nverts = numverts;
454  for (Int v = 0; v < poly.nverts; ++v) {
455  poly.verts[v].pos = vertices[v];
456  poly.verts[v].pnbrs[0] = 1 - v;
457  }
458 }
459 
460 R3D_INLINE Plane<3> tet_face_from_verts(Vector<3> a, Vector<3> b, Vector<3> c) {
461  auto center = ONE_THIRD * (a + b + c);
462  auto normal = normalize(cross((b - a), (c - a)));
463  auto d = -(normal * center);
464  return Plane<3>{normal, d};
465 }
466 
478 R3D_INLINE Few<Plane<3>, 4> faces_from_verts(Few<Vector<3>, 4> verts) {
479  Few<Plane<3>, 4> faces;
480  faces[0] = tet_face_from_verts(verts[3], verts[2], verts[1]);
481  faces[1] = tet_face_from_verts(verts[0], verts[2], verts[3]);
482  faces[2] = tet_face_from_verts(verts[0], verts[3], verts[1]);
483  faces[3] = tet_face_from_verts(verts[0], verts[1], verts[2]);
484  return faces;
485 }
486 
499 R3D_INLINE Few<Plane<2>, 3> faces_from_verts(Few<Vector<2>, 3> vertices) {
500  constexpr Int numverts = 3;
501  Int f;
502  Vector<2> p0, p1;
503  Few<Plane<2>, 3> faces;
504  // calculate a centroid and a unit normal for each face
505  for (f = 0; f < numverts; ++f) {
506  p0 = vertices[f];
507  p1 = vertices[(f + 1) % numverts];
508  // normal of the edge
509  faces[f].n[0] = p0[1] - p1[1];
510  faces[f].n[1] = p1[0] - p0[0];
511  // normalize the normals and set the signed distance to origin
512  faces[f].n = normalize(faces[f].n);
513  faces[f].d = -(faces[f].n * p0);
514  }
515  return faces;
516 }
517 
526 R3D_INLINE Few<Plane<1>, 2> faces_from_verts(Few<Vector<1>, 2> vertices) {
527  Few<Plane<1>, 2> faces;
528  faces[0].n = normalize(vertices[1] - vertices[0]);
529  faces[1].n = normalize(vertices[0] - vertices[1]);
530  faces[0].d = -(faces[0].n * vertices[0]);
531  faces[1].d = -(faces[1].n * vertices[1]);
532  return faces;
533 }
534 
535 R3D_INLINE constexpr Int num_moments_3d(Int order) {
536  return ((order + 1) * (order + 2) * (order + 3) / 6);
537 }
538 
539 R3D_INLINE constexpr Int num_moments_2d(Int order) {
540  return ((order + 1) * (order + 2) / 2);
541 }
542 
543 template <Int dim, Int order>
544 struct NumMoments;
545 
546 template <Int order>
547 struct NumMoments<3, order> {
548  enum { value = num_moments_3d(order) };
549 };
550 
551 template <Int order>
552 struct NumMoments<2, order> {
553  enum { value = num_moments_2d(order) };
554 };
555 
579 template <Int polyorder>
580 R3D_INLINE void reduce(Polytope<3> const& poly, Real* moments) {
581  if (poly.nverts <= 0) return;
582 
583  // var declarations
584  Real sixv;
585  Int np, m, i, j, k, corder;
586  Int vstart, pstart, vcur, vnext, pnext;
587  Vector<3> v0, v1, v2;
588 
589  // zero the moments
590  for (m = 0; m < num_moments_3d(polyorder); ++m) moments[m] = 0.0;
591 
592  // for keeping track of which edges have been visited
593  Int emarks[Polytope<3>::max_verts][3] = {{}}; // initialized to zero
594 
595  // Storage for coefficients
596  // keep two layers of the pyramid of coefficients
597  // Note: Uses twice as much space as needed, but indexing is faster this way
598  Int prevlayer = 0;
599  Int curlayer = 1;
600  Real S[polyorder + 1][polyorder + 1][2];
601  Real D[polyorder + 1][polyorder + 1][2];
602  Real C[polyorder + 1][polyorder + 1][2];
603 
604  // loop over all vertices to find the starting point for each face
605  for (vstart = 0; vstart < poly.nverts; ++vstart)
606  for (pstart = 0; pstart < 3; ++pstart) {
607  // skip this face if we have marked it
608  if (emarks[vstart][pstart]) continue;
609 
610  // initialize face looping
611  pnext = pstart;
612  vcur = vstart;
613  emarks[vcur][pnext] = 1;
614  vnext = poly.verts[vcur].pnbrs[pnext];
615  v0 = poly.verts[vcur].pos;
616 
617  // move to the second edge
618  for (np = 0; np < 3; ++np)
619  if (poly.verts[vnext].pnbrs[np] == vcur) break;
620  vcur = vnext;
621  pnext = (np + 1) % 3;
622  emarks[vcur][pnext] = 1;
623  vnext = poly.verts[vcur].pnbrs[pnext];
624 
625  // make a triangle fan using edges
626  // and first vertex
627  while (vnext != vstart) {
628  v2 = poly.verts[vcur].pos;
629  v1 = poly.verts[vnext].pos;
630 
631  sixv = (-v2[0] * v1[1] * v0[2] + v1[0] * v2[1] * v0[2] +
632  v2[0] * v0[1] * v1[2] - v0[0] * v2[1] * v1[2] -
633  v1[0] * v0[1] * v2[2] + v0[0] * v1[1] * v2[2]);
634 
635  // calculate the moments
636  // using the fast recursive method of Koehl (2012)
637  // essentially building a set of trinomial pyramids, one layer at a time
638 
639  // base case
640  S[0][0][prevlayer] = 1.0;
641  D[0][0][prevlayer] = 1.0;
642  C[0][0][prevlayer] = 1.0;
643  moments[0] += ONE_SIXTH * sixv;
644 
645  // build up successive polynomial orders
646  for (corder = 1, m = 1; corder <= polyorder; ++corder) {
647  for (i = corder; i >= 0; --i)
648  for (j = corder - i; j >= 0; --j, ++m) {
649  k = corder - i - j;
650  C[i][j][curlayer] = 0;
651  D[i][j][curlayer] = 0;
652  S[i][j][curlayer] = 0;
653  if (i > 0) {
654  C[i][j][curlayer] += v2[0] * C[i - 1][j][prevlayer];
655  D[i][j][curlayer] += v1[0] * D[i - 1][j][prevlayer];
656  S[i][j][curlayer] += v0[0] * S[i - 1][j][prevlayer];
657  }
658  if (j > 0) {
659  C[i][j][curlayer] += v2[1] * C[i][j - 1][prevlayer];
660  D[i][j][curlayer] += v1[1] * D[i][j - 1][prevlayer];
661  S[i][j][curlayer] += v0[1] * S[i][j - 1][prevlayer];
662  }
663  if (k > 0) {
664  C[i][j][curlayer] += v2[2] * C[i][j][prevlayer];
665  D[i][j][curlayer] += v1[2] * D[i][j][prevlayer];
666  S[i][j][curlayer] += v0[2] * S[i][j][prevlayer];
667  }
668  D[i][j][curlayer] += C[i][j][curlayer];
669  S[i][j][curlayer] += D[i][j][curlayer];
670  moments[m] += sixv * S[i][j][curlayer];
671  }
672  curlayer = 1 - curlayer;
673  prevlayer = 1 - prevlayer;
674  }
675 
676  // move to the next edge
677  for (np = 0; np < 3; ++np)
678  if (poly.verts[vnext].pnbrs[np] == vcur) break;
679  vcur = vnext;
680  pnext = (np + 1) % 3;
681  emarks[vcur][pnext] = 1;
682  vnext = poly.verts[vcur].pnbrs[pnext];
683  }
684  }
685 
686  // reuse C to recursively compute the leading multinomial coefficients
687  C[0][0][prevlayer] = 1.0;
688  for (corder = 1, m = 1; corder <= polyorder; ++corder) {
689  for (i = corder; i >= 0; --i)
690  for (j = corder - i; j >= 0; --j, ++m) {
691  k = corder - i - j;
692  C[i][j][curlayer] = 0.0;
693  if (i > 0) C[i][j][curlayer] += C[i - 1][j][prevlayer];
694  if (j > 0) C[i][j][curlayer] += C[i][j - 1][prevlayer];
695  if (k > 0) C[i][j][curlayer] += C[i][j][prevlayer];
696  moments[m] /=
697  C[i][j][curlayer] * (corder + 1) * (corder + 2) * (corder + 3);
698  }
699  curlayer = 1 - curlayer;
700  prevlayer = 1 - prevlayer;
701  }
702 }
703 
726 template <Int polyorder>
727 R3D_INLINE void reduce(Polytope<2> const& poly, Real* moments) {
728  if (poly.nverts <= 0) return;
729 
730  // var declarations
731  Int vcur, vnext, m, i, j, corder;
732  Real twoa;
733  Vector<2> v0, v1;
734 
735  // zero the moments
736  for (m = 0; m < num_moments_2d(polyorder); ++m) moments[m] = 0.0;
737 
738  // Storage for coefficients
739  // keep two layers of the triangle of coefficients
740  Int prevlayer = 0;
741  Int curlayer = 1;
742  Real D[polyorder + 1][2];
743  Real C[polyorder + 1][2];
744 
745  // iterate over edges and compute a sum over simplices
746  for (vcur = 0; vcur < poly.nverts; ++vcur) {
747  vnext = poly.verts[vcur].pnbrs[0];
748  v0 = poly.verts[vcur].pos;
749  v1 = poly.verts[vnext].pos;
750  twoa = (v0[0] * v1[1] - v0[1] * v1[0]);
751 
752  // calculate the moments
753  // using the fast recursive method of Koehl (2012)
754  // essentially building a set of Pascal's triangles, one layer at a time
755 
756  // base case
757  D[0][prevlayer] = 1.0;
758  C[0][prevlayer] = 1.0;
759  moments[0] += 0.5 * twoa;
760 
761  // build up successive polynomial orders
762  for (corder = 1, m = 1; corder <= polyorder; ++corder) {
763  for (i = corder; i >= 0; --i, ++m) {
764  j = corder - i;
765  C[i][curlayer] = 0;
766  D[i][curlayer] = 0;
767  if (i > 0) {
768  C[i][curlayer] += v1[0] * C[i - 1][prevlayer];
769  D[i][curlayer] += v0[0] * D[i - 1][prevlayer];
770  }
771  if (j > 0) {
772  C[i][curlayer] += v1[1] * C[i][prevlayer];
773  D[i][curlayer] += v0[1] * D[i][prevlayer];
774  }
775  D[i][curlayer] += C[i][curlayer];
776  moments[m] += twoa * D[i][curlayer];
777  }
778  curlayer = 1 - curlayer;
779  prevlayer = 1 - prevlayer;
780  }
781  }
782 
783  // reuse C to recursively compute the leading multinomial coefficients
784  C[0][prevlayer] = 1.0;
785  for (corder = 1, m = 1; corder <= polyorder; ++corder) {
786  for (i = corder; i >= 0; --i, ++m) {
787  j = corder - i;
788  C[i][curlayer] = 0.0;
789  if (i > 0) C[i][curlayer] += C[i - 1][prevlayer];
790  if (j > 0) C[i][curlayer] += C[i][prevlayer];
791  moments[m] /= C[i][curlayer] * (corder + 1) * (corder + 2);
792  }
793  curlayer = 1 - curlayer;
794  prevlayer = 1 - prevlayer;
795  }
796 }
797 
798 template <Int dim, Int order>
799 struct Polynomial {
800  enum { nterms = NumMoments<dim, order>::value };
801  Real coeffs[nterms];
802 };
803 
804 template <Int dim, Int order>
805 R3D_INLINE Real integrate(
806  Polytope<dim> const& polytope, Polynomial<dim, order> polynomial) {
807  Real moments[decltype(polynomial)::nterms] = {};
808  reduce<order>(polytope, moments);
809  Real result = 0;
810  for (Int i = 0; i < decltype(polynomial)::nterms; ++i)
811  result += moments[i] * polynomial.coeffs[i];
812  return result;
813 }
814 
815 /* Cop-out: instead of figuring out how to implement
816  integrate() for 1D edges, just hardcode the
817  length measurement */
818 R3D_INLINE Real measure(Polytope<1> const& polytope) {
819  return std::abs(polytope.verts[1].pos[0] - polytope.verts[0].pos[0]);
820 }
821 
822 R3D_INLINE Real measure(Polytope<2> const& polytope) {
823  return integrate(polytope, Polynomial<2, 0>{{1}});
824 }
825 
826 R3D_INLINE Real measure(Polytope<3> const& polytope) {
827  return integrate(polytope, Polynomial<3, 0>{{1}});
828 }
829 
830 template <Int dim>
831 R3D_INLINE void intersect_simplices(Polytope<dim>& poly,
832  Few<Vector<dim>, dim + 1> verts0, Few<Vector<dim>, dim + 1> verts1) {
833  init(poly, verts0);
834  auto faces1 = faces_from_verts(verts1);
835  clip(poly, faces1);
836 }
837 
862 R3D_INLINE void init_poly(Polytope<3>& poly, Vector<3>* vertices, Int numverts,
863  Int** faceinds, Int* numvertsperface, Int numfaces) {
864  // dummy vars
865  Int v, vprev, vcur, vnext, f, np;
866 
867  // count up the number of faces per vertex
868  // and act accordingly
869  Int eperv[R3D_MAX_VERTS] = {0};
870  Int maxeperv = 0;
871  for (f = 0; f < numfaces; ++f)
872  for (v = 0; v < numvertsperface[f]; ++v) ++eperv[faceinds[f][v]];
873  for (v = 0; v < numverts; ++v)
874  if (eperv[v] > maxeperv) maxeperv = eperv[v];
875 
876  // clear the poly
877  poly.nverts = 0;
878 
879  if (maxeperv == 3) {
880  // simple case with no need for duplicate vertices
881 
882  // read in vertex locations
883  poly.nverts = numverts;
884  for (v = 0; v < poly.nverts; ++v) {
885  poly.verts[v].pos = vertices[v];
886  for (np = 0; np < 3; ++np) poly.verts[v].pnbrs[np] = R3D_MAX_VERTS;
887  }
888 
889  // build graph connectivity by correctly orienting half-edges for each
890  // vertex
891  for (f = 0; f < numfaces; ++f) {
892  for (v = 0; v < numvertsperface[f]; ++v) {
893  vprev = faceinds[f][v];
894  vcur = faceinds[f][(v + 1) % numvertsperface[f]];
895  vnext = faceinds[f][(v + 2) % numvertsperface[f]];
896  for (np = 0; np < 3; ++np) {
897  if (poly.verts[vcur].pnbrs[np] == vprev) {
898  poly.verts[vcur].pnbrs[(np + 2) % 3] = vnext;
899  break;
900  } else if (poly.verts[vcur].pnbrs[np] == vnext) {
901  poly.verts[vcur].pnbrs[(np + 1) % 3] = vprev;
902  break;
903  }
904  }
905  if (np == 3) {
906  poly.verts[vcur].pnbrs[1] = vprev;
907  poly.verts[vcur].pnbrs[0] = vnext;
908  }
909  }
910  }
911  } else {
912  // we need to create duplicate, degenerate vertices to account for more than
913  // three edges per vertex. This is complicated.
914 
915  // need more variables
916  Int v0, v1, v00, v11, numunclipped;
917 
918  // we need a few extra buffers to handle the necessary operations
919  Vertex<3> vbtmp[3 * R3D_MAX_VERTS];
920  Int vstart[R3D_MAX_VERTS];
921 
922  // build vertex mappings to degenerate duplicates
923  // and read in vertex locations
924  poly.nverts = 0;
925  for (v = 0; v < numverts; ++v) {
926  vstart[v] = poly.nverts;
927  for (vcur = 0; vcur < eperv[v]; ++vcur) {
928  vbtmp[poly.nverts].pos = vertices[v];
929  for (np = 0; np < 3; ++np) vbtmp[poly.nverts].pnbrs[np] = R3D_MAX_VERTS;
930  ++(poly.nverts);
931  }
932  }
933 
934  // fill in connectivity for all duplicates
935  {
936  Int util[3 * R3D_MAX_VERTS] = {0};
937  for (f = 0; f < numfaces; ++f) {
938  for (v = 0; v < numvertsperface[f]; ++v) {
939  vprev = faceinds[f][v];
940  vcur = faceinds[f][(v + 1) % numvertsperface[f]];
941  vnext = faceinds[f][(v + 2) % numvertsperface[f]];
942  auto vcur_old = vcur;
943  vcur = vstart[vcur] + util[vcur];
944  util[vcur_old]++;
945  vbtmp[vcur].pnbrs[1] = vnext;
946  vbtmp[vcur].pnbrs[2] = vprev;
947  }
948  }
949  }
950 
951  // link degenerate duplicates, putting them in the correct order
952  // use util to mark and avoid double-processing verts
953  {
954  Int util[3 * R3D_MAX_VERTS] = {0};
955  for (v = 0; v < numverts; ++v) {
956  for (v0 = vstart[v]; v0 < vstart[v] + eperv[v]; ++v0) {
957  for (v1 = vstart[v]; v1 < vstart[v] + eperv[v]; ++v1) {
958  if (vbtmp[v0].pnbrs[2] == vbtmp[v1].pnbrs[1] && !util[v0]) {
959  vbtmp[v0].pnbrs[2] = v1;
960  vbtmp[v1].pnbrs[0] = v0;
961  util[v0] = 1;
962  }
963  }
964  }
965  }
966  }
967 
968  // complete vertex pairs
969  {
970  Int util[3 * R3D_MAX_VERTS] = {0};
971  for (v0 = 0; v0 < numverts; ++v0)
972  for (v1 = v0 + 1; v1 < numverts; ++v1) {
973  for (v00 = vstart[v0]; v00 < vstart[v0] + eperv[v0]; ++v00)
974  for (v11 = vstart[v1]; v11 < vstart[v1] + eperv[v1]; ++v11) {
975  if (vbtmp[v00].pnbrs[1] == v1 && vbtmp[v11].pnbrs[1] == v0 &&
976  !util[v00] && !util[v11]) {
977  vbtmp[v00].pnbrs[1] = v11;
978  vbtmp[v11].pnbrs[1] = v00;
979  util[v00] = 1;
980  util[v11] = 1;
981  }
982  }
983  }
984  }
985 
986  // remove unnecessary dummy vertices
987  {
988  Int util[3 * R3D_MAX_VERTS] = {0};
989  for (v = 0; v < numverts; ++v) {
990  v0 = vstart[v];
991  v1 = vbtmp[v0].pnbrs[0];
992  v00 = vbtmp[v0].pnbrs[2];
993  v11 = vbtmp[v1].pnbrs[0];
994  vbtmp[v00].pnbrs[0] = vbtmp[v0].pnbrs[1];
995  vbtmp[v11].pnbrs[2] = vbtmp[v1].pnbrs[1];
996  for (np = 0; np < 3; ++np)
997  if (vbtmp[vbtmp[v0].pnbrs[1]].pnbrs[np] == v0) break;
998  vbtmp[vbtmp[v0].pnbrs[1]].pnbrs[np] = v00;
999  for (np = 0; np < 3; ++np)
1000  if (vbtmp[vbtmp[v1].pnbrs[1]].pnbrs[np] == v1) break;
1001  vbtmp[vbtmp[v1].pnbrs[1]].pnbrs[np] = v11;
1002  util[v0] = 1;
1003  util[v1] = 1;
1004  }
1005 
1006  // copy to the real vertbuffer and compress
1007  numunclipped = 0;
1008  for (v = 0; v < poly.nverts; ++v) {
1009  if (!util[v]) {
1010  poly.verts[numunclipped] = vbtmp[v];
1011  util[v] = numunclipped++;
1012  }
1013  }
1014  poly.nverts = numunclipped;
1015  for (v = 0; v < poly.nverts; ++v)
1016  for (np = 0; np < 3; ++np)
1017  poly.verts[v].pnbrs[np] = util[poly.verts[v].pnbrs[np]];
1018  }
1019  }
1020 }
1021 
1037 R3D_INLINE void init_poly(
1038  Polytope<2>& poly, Vector<2>* vertices, Int numverts) {
1039  poly.nverts = numverts;
1040  Int v;
1041  for (v = 0; v < poly.nverts; ++v) {
1042  poly.verts[v].pos = vertices[v];
1043  poly.verts[v].pnbrs[0] = (v + 1) % (poly.nverts);
1044  poly.verts[v].pnbrs[1] = (poly.nverts + v - 1) % (poly.nverts);
1045  }
1046 }
1047 
1070 R3D_INLINE void poly_faces_from_verts(Plane<3>* faces, Vector<3>* vertices,
1071  Int** faceinds, Int* numvertsperface, Int numfaces) {
1072  // dummy vars
1073  Int v, f;
1074  Vector<3> p0, p1, p2;
1075 
1076  // calculate a centroid and a unit normal for each face
1077  for (f = 0; f < numfaces; ++f) {
1078  auto centroid = vector_3(0, 0, 0);
1079  faces[f].n = vector_3(0, 0, 0);
1080 
1081  for (v = 0; v < numvertsperface[f]; ++v) {
1082  // add cross product of edges to the total normal
1083  p0 = vertices[faceinds[f][v]];
1084  p1 = vertices[faceinds[f][(v + 1) % numvertsperface[f]]];
1085  p2 = vertices[faceinds[f][(v + 2) % numvertsperface[f]]];
1086  faces[f].n = faces[f].n + cross(p1 - p0, p2 - p0);
1087 
1088  // add the vertex position to the centroid
1089  centroid = centroid + p0;
1090  }
1091 
1092  // normalize the normals and set the signed distance to origin
1093  centroid = centroid / Real(numvertsperface[f]);
1094  faces[f].n = normalize(faces[f].n);
1095  faces[f].d = -(faces[f].n * centroid);
1096  }
1097 }
1098 
1099 } // end namespace r3d
1100 
1101 #endif
Definition: Omega_h_few.hpp:61
Definition: r3d.hpp:70
Definition: r3d.hpp:256
Definition: r3d.hpp:217
Definition: r3d.hpp:544
Definition: r3d.hpp:205
Vector< dim > n
Definition: r3d.hpp:206
Real d
Definition: r3d.hpp:207
Definition: r3d.hpp:799
A polyhedron. Can be convex, nonconvex, even multiply-connected.
Definition: r3d.hpp:238
Int nverts
Definition: r3d.hpp:241
Vertex< dim > verts[max_verts]
Definition: r3d.hpp:240
Definition: r3d.hpp:89
Definition: r3d.hpp:211
Int pnbrs[dim]
Definition: r3d.hpp:212
Vector< dim > pos
Definition: r3d.hpp:213