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 class Few {
87  using UninitT = typename std::aligned_storage<sizeof(T), alignof(T)>::type;
88  UninitT array_[n];
89 
90  public:
91  enum { size = n };
92  R3D_INLINE T* data() { return reinterpret_cast<T*>(array_); }
93  R3D_INLINE T const* data() const {
94  return reinterpret_cast<T const*>(array_);
95  }
96  R3D_INLINE T volatile* data() volatile {
97  return reinterpret_cast<T volatile*>(array_);
98  }
99  R3D_INLINE T const volatile* data() const volatile {
100  return reinterpret_cast<T const volatile*>(array_);
101  }
102  R3D_INLINE T& operator[](Int i) { return data()[i]; }
103  R3D_INLINE T const& operator[](Int i) const { return data()[i]; }
104  R3D_INLINE T volatile& operator[](Int i) volatile { return data()[i]; }
105  R3D_INLINE T const volatile& operator[](Int i) const volatile {
106  return data()[i];
107  }
108  Few(std::initializer_list<T> l) {
109  Int i = 0;
110  for (auto it = l.begin(); it != l.end(); ++it) {
111  new (data() + (i++)) T(*it);
112  }
113  }
114  R3D_INLINE Few() {
115  for (Int i = 0; i < n; ++i) new (data() + i) T();
116  }
117 #ifdef OMPTARGET
118 #pragma omp declare target
119 #endif
120  R3D_INLINE ~Few() {
121  for (Int i = 0; i < n; ++i) (data()[i]).~T();
122  }
123 #ifdef OMPTARGET
124 #pragma omp end declare target
125 #endif
126  R3D_INLINE void operator=(Few<T, n> const& rhs) volatile {
127  for (Int i = 0; i < n; ++i) data()[i] = rhs[i];
128  }
129  R3D_INLINE void operator=(Few<T, n> const& rhs) {
130  for (Int i = 0; i < n; ++i) data()[i] = rhs[i];
131  }
132  R3D_INLINE void operator=(Few<T, n> const volatile& rhs) {
133  for (Int i = 0; i < n; ++i) data()[i] = rhs[i];
134  }
135  R3D_INLINE Few(Few<T, n> const& rhs) {
136  for (Int i = 0; i < n; ++i) new (data() + i) T(rhs[i]);
137  }
138  R3D_INLINE Few(Few<T, n> const volatile& rhs) {
139  for (Int i = 0; i < n; ++i) new (data() + i) T(rhs[i]);
140  }
141 };
142 
143 template <Int n>
144 struct Vector : public Few<Real, n> {
145  R3D_INLINE Vector() {}
146  inline Vector(std::initializer_list<Real> l) : Few<Real, n>(l) {}
147  R3D_INLINE void operator=(Vector<n> const& rhs) volatile {
149  }
150  R3D_INLINE Vector(Vector<n> const& rhs) : Few<Real, n>(rhs) {}
151  R3D_INLINE Vector(const volatile Vector<n>& rhs) : Few<Real, n>(rhs) {}
152 };
153 
154 R3D_INLINE Vector<2> vector_2(Real x, Real y) {
155  Vector<2> v;
156  v[0] = x;
157  v[1] = y;
158  return v;
159 }
160 
161 R3D_INLINE Vector<3> vector_3(Real x, Real y, Real z) {
162  Vector<3> v;
163  v[0] = x;
164  v[1] = y;
165  v[2] = z;
166  return v;
167 }
168 
169 template <Int n>
170 R3D_INLINE Vector<n> operator+(Vector<n> a, Vector<n> b) {
171  Vector<n> c;
172  for (Int i = 0; i < n; ++i) c[i] = a[i] + b[i];
173  return c;
174 }
175 
176 template <Int n>
177 R3D_INLINE Vector<n>& operator+=(Vector<n>& a, Vector<n> b) {
178  a = a + b;
179  return a;
180 }
181 
182 template <Int n>
183 R3D_INLINE Vector<n> operator-(Vector<n> a, Vector<n> b) {
184  Vector<n> c;
185  for (Int i = 0; i < n; ++i) c[i] = a[i] - b[i];
186  return c;
187 }
188 
189 template <Int n>
190 R3D_INLINE Vector<n>& operator-=(Vector<n>& a, Vector<n> b) {
191  a = a - b;
192  return a;
193 }
194 
195 template <Int n>
196 R3D_INLINE Vector<n> operator-(Vector<n> a) {
197  Vector<n> c;
198  for (Int i = 0; i < n; ++i) c[i] = -a[i];
199  return c;
200 }
201 
202 template <Int n>
203 R3D_INLINE Vector<n> operator*(Vector<n> a, Real b) {
204  Vector<n> c;
205  for (Int i = 0; i < n; ++i) c[i] = a[i] * b;
206  return c;
207 }
208 
209 template <Int n>
210 R3D_INLINE Vector<n>& operator*=(Vector<n>& a, Real b) {
211  a = a * b;
212  return a;
213 }
214 
215 template <Int n>
216 R3D_INLINE Vector<n> operator*(Real a, Vector<n> b) {
217  return b * a;
218 }
219 
220 template <Int n>
221 R3D_INLINE Vector<n> operator/(Vector<n> a, Real b) {
222  Vector<n> c;
223  for (Int i = 0; i < n; ++i) c[i] = a[i] / b;
224  return c;
225 }
226 
227 template <Int n>
228 R3D_INLINE Vector<n>& operator/=(Vector<n>& a, Real b) {
229  a = a / b;
230  return a;
231 }
232 
233 template <Int n>
234 R3D_INLINE Real operator*(Vector<n> a, Vector<n> b) {
235  Real c = a[0] * b[0];
236  for (Int i = 1; i < n; ++i) c += a[i] * b[i];
237  return c;
238 }
239 
240 template <Int n>
241 R3D_INLINE Real norm_squared(Vector<n> v) {
242  return v * v;
243 }
244 
245 template <Int n>
246 R3D_INLINE Real norm(Vector<n> v) {
247  return std::sqrt(norm_squared(v));
248 }
249 
250 template <Int n>
251 R3D_INLINE Vector<n> normalize(Vector<n> v) {
252  return v / norm(v);
253 }
254 
255 R3D_INLINE Vector<3> cross(Vector<3> a, Vector<3> b) {
256  return vector_3(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],
257  a[0] * b[1] - a[1] * b[0]);
258 }
259 
260 template <Int dim>
261 struct Plane {
263  Real d;
264 };
265 
266 template <Int dim>
267 struct Vertex {
268  Int pnbrs[dim];
270 };
271 
272 template <Int dim>
273 struct MaxVerts;
274 
275 template <>
276 struct MaxVerts<1> {
277  enum { value = R1D_MAX_VERTS };
278 };
279 
280 template <>
281 struct MaxVerts<2> {
282  enum { value = R2D_MAX_VERTS };
283 };
284 
285 template <>
286 struct MaxVerts<3> {
287  enum { value = R3D_MAX_VERTS };
288 };
289 
293 template <Int dim>
294 struct Polytope {
295  enum { max_verts = MaxVerts<dim>::value };
296  Vertex<dim> verts[max_verts];
297  Int nverts;
298 };
299 
300 template <Int dim>
301 R3D_INLINE Vector<dim> wav(Vector<dim> va, Real wa, Vector<dim> vb, Real wb) {
302  Vector<dim> vr;
303  for (Int i = 0; i < dim; ++i) vr[i] = (wa * va[i] + wb * vb[i]) / (wa + wb);
304  return vr;
305 }
306 
307 /* This class encapsulates the code that was different
308  * between r3d_clip and r2d_clip
309  */
310 
311 template <Int dim>
312 struct ClipHelper;
313 
314 template <>
315 struct ClipHelper<3> {
316  R3D_INLINE static void finalize_links(Int onv, Polytope<3>& poly) {
317  for (auto vstart = onv; vstart < poly.nverts; ++vstart) {
318  auto vcur = vstart;
319  auto vnext = poly.verts[vcur].pnbrs[0];
320  do {
321  Int np;
322  for (np = 0; np < 3; ++np)
323  if (poly.verts[vnext].pnbrs[np] == vcur) break;
324  vcur = vnext;
325  auto pnext = (np + 1) % 3;
326  vnext = poly.verts[vcur].pnbrs[pnext];
327  } while (vcur < onv);
328  poly.verts[vstart].pnbrs[2] = vcur;
329  poly.verts[vcur].pnbrs[1] = vstart;
330  }
331  }
332  R3D_INLINE static void init_new_vert_link(
333  Polytope<3>& poly, Int vcur, Int np) {
334  (void)np;
335  poly.verts[poly.nverts].pnbrs[0] = vcur;
336  }
337 };
338 
339 template <>
340 struct ClipHelper<2> {
341  R3D_INLINE static void finalize_links(Int onv, Polytope<2>& poly) {
342  for (auto vstart = onv; vstart < poly.nverts; ++vstart) {
343  if (poly.verts[vstart].pnbrs[1] >= 0) continue;
344  auto vcur = poly.verts[vstart].pnbrs[0];
345  do {
346  vcur = poly.verts[vcur].pnbrs[0];
347  } while (vcur < onv);
348  poly.verts[vstart].pnbrs[1] = vcur;
349  poly.verts[vcur].pnbrs[0] = vstart;
350  }
351  }
352  R3D_INLINE static void init_new_vert_link(
353  Polytope<2>& poly, Int vcur, Int np) {
354  poly.verts[poly.nverts].pnbrs[1 - np] = vcur;
355  poly.verts[poly.nverts].pnbrs[np] = -1;
356  }
357 };
358 
359 template <>
360 struct ClipHelper<1> {
361  R3D_INLINE static void finalize_links(Int, Polytope<1>&) {}
362  R3D_INLINE static void init_new_vert_link(
363  Polytope<1>& poly, Int vcur, Int np) {
364  poly.verts[poly.nverts].pnbrs[np] = vcur;
365  }
366 };
367 
379 template <Int dim>
380 R3D_INLINE void clip(
381  Polytope<dim>& poly, Plane<dim> const* planes, Int nplanes) {
382  if (poly.nverts <= 0) return;
383 
384  // variable declarations
385  Int v, p, np, onv, vcur, vnext, numunclipped;
386 
387  // signed distances to the clipping plane
388  Real sdists[Polytope<dim>::max_verts];
389  Real smin, smax;
390 
391  // loop over each clip plane
392  for (p = 0; p < nplanes; ++p) {
393  // calculate signed distances to the clip plane
394  onv = poly.nverts;
395  smin = ArithTraits<Real>::max();
396  smax = ArithTraits<Real>::min();
397 
398  // for marking clipped vertices
399  Int clipped[MaxVerts<dim>::value] = {}; // all initialized to zero
400  for (v = 0; v < onv; ++v) {
401  sdists[v] = planes[p].d + (poly.verts[v].pos * planes[p].n);
402  if (sdists[v] < smin) smin = sdists[v];
403  if (sdists[v] > smax) smax = sdists[v];
404  if (sdists[v] < 0.0) clipped[v] = 1;
405  }
406 
407  // skip this face if the poly lies entirely on one side of it
408  if (smin >= 0.0) continue;
409  if (smax <= 0.0) {
410  poly.nverts = 0;
411  return;
412  }
413 
414  // check all edges and insert new vertices on the bisected edges
415  for (vcur = 0; vcur < onv; ++vcur) {
416  if (clipped[vcur]) continue;
417  for (np = 0; np < dim; ++np) {
418  vnext = poly.verts[vcur].pnbrs[np];
419  if (!clipped[vnext]) continue;
420  ClipHelper<dim>::init_new_vert_link(poly, vcur, np);
421  poly.verts[vcur].pnbrs[np] = poly.nverts;
422  poly.verts[poly.nverts].pos = wav(poly.verts[vcur].pos, -sdists[vnext],
423  poly.verts[vnext].pos, sdists[vcur]);
424  ++(poly.nverts);
425  }
426  }
427 
428  // for each new vert, search around the poly for its new neighbors
429  // and doubly-link everything
430  ClipHelper<dim>::finalize_links(onv, poly);
431 
432  // go through and compress the vertex list, removing clipped verts
433  // and re-indexing accordingly (reusing `clipped` to re-index everything)
434  numunclipped = 0;
435  for (v = 0; v < poly.nverts; ++v) {
436  if (!clipped[v]) {
437  poly.verts[numunclipped] = poly.verts[v];
438  clipped[v] = numunclipped++;
439  }
440  }
441  poly.nverts = numunclipped;
442  for (v = 0; v < poly.nverts; ++v)
443  for (np = 0; np < dim; ++np)
444  poly.verts[v].pnbrs[np] = clipped[poly.verts[v].pnbrs[np]];
445  }
446 }
447 
448 template <Int dim>
449 R3D_INLINE void clip(Polytope<dim>& poly, Plane<dim> const& plane) {
450  clip(poly, &plane, 1);
451 }
452 
453 template <Int dim, Int nplanes>
454 R3D_INLINE void clip(Polytope<dim>& poly, Few<Plane<dim>, nplanes> planes) {
455  clip(poly, &planes[0], nplanes);
456 }
457 
465 R3D_INLINE void init(Polytope<3>& poly, Few<Vector<3>, 4> verts) {
466  // initialize graph connectivity
467  poly.nverts = 4;
468  poly.verts[0].pnbrs[0] = 1;
469  poly.verts[0].pnbrs[1] = 3;
470  poly.verts[0].pnbrs[2] = 2;
471  poly.verts[1].pnbrs[0] = 2;
472  poly.verts[1].pnbrs[1] = 3;
473  poly.verts[1].pnbrs[2] = 0;
474  poly.verts[2].pnbrs[0] = 0;
475  poly.verts[2].pnbrs[1] = 3;
476  poly.verts[2].pnbrs[2] = 1;
477  poly.verts[3].pnbrs[0] = 1;
478  poly.verts[3].pnbrs[1] = 2;
479  poly.verts[3].pnbrs[2] = 0;
480 
481  // copy vertex coordinates
482  for (Int v = 0; v < 4; ++v) poly.verts[v].pos = verts[v];
483 }
484 
492 R3D_INLINE void init(Polytope<2>& poly, Few<Vector<2>, 3> vertices) {
493  constexpr Int numverts = 3;
494  // init the poly
495  poly.nverts = numverts;
496  for (Int v = 0; v < poly.nverts; ++v) {
497  poly.verts[v].pos = vertices[v];
498  poly.verts[v].pnbrs[0] = (v + 1) % (numverts);
499  poly.verts[v].pnbrs[1] = (numverts + v - 1) % (numverts);
500  }
501 }
502 
506 R3D_INLINE void init(Polytope<1>& poly, Few<Vector<1>, 2> vertices) {
507  constexpr Int numverts = 2;
508  // init the poly
509  poly.nverts = numverts;
510  for (Int v = 0; v < poly.nverts; ++v) {
511  poly.verts[v].pos = vertices[v];
512  poly.verts[v].pnbrs[0] = 1 - v;
513  }
514 }
515 
516 R3D_INLINE Plane<3> tet_face_from_verts(Vector<3> a, Vector<3> b, Vector<3> c) {
517  auto center = ONE_THIRD * (a + b + c);
518  auto normal = normalize(cross((b - a), (c - a)));
519  auto d = -(normal * center);
520  return Plane<3>{normal, d};
521 }
522 
534 R3D_INLINE Few<Plane<3>, 4> faces_from_verts(Few<Vector<3>, 4> verts) {
535  Few<Plane<3>, 4> faces;
536  faces[0] = tet_face_from_verts(verts[3], verts[2], verts[1]);
537  faces[1] = tet_face_from_verts(verts[0], verts[2], verts[3]);
538  faces[2] = tet_face_from_verts(verts[0], verts[3], verts[1]);
539  faces[3] = tet_face_from_verts(verts[0], verts[1], verts[2]);
540  return faces;
541 }
542 
555 R3D_INLINE Few<Plane<2>, 3> faces_from_verts(Few<Vector<2>, 3> vertices) {
556  constexpr Int numverts = 3;
557  Int f;
558  Vector<2> p0, p1;
559  Few<Plane<2>, 3> faces;
560  // calculate a centroid and a unit normal for each face
561  for (f = 0; f < numverts; ++f) {
562  p0 = vertices[f];
563  p1 = vertices[(f + 1) % numverts];
564  // normal of the edge
565  faces[f].n[0] = p0[1] - p1[1];
566  faces[f].n[1] = p1[0] - p0[0];
567  // normalize the normals and set the signed distance to origin
568  faces[f].n = normalize(faces[f].n);
569  faces[f].d = -(faces[f].n * p0);
570  }
571  return faces;
572 }
573 
582 R3D_INLINE Few<Plane<1>, 2> faces_from_verts(Few<Vector<1>, 2> vertices) {
583  Few<Plane<1>, 2> faces;
584  faces[0].n = normalize(vertices[1] - vertices[0]);
585  faces[1].n = normalize(vertices[0] - vertices[1]);
586  faces[0].d = -(faces[0].n * vertices[0]);
587  faces[1].d = -(faces[1].n * vertices[1]);
588  return faces;
589 }
590 
591 R3D_INLINE constexpr Int num_moments_3d(Int order) {
592  return ((order + 1) * (order + 2) * (order + 3) / 6);
593 }
594 
595 R3D_INLINE constexpr Int num_moments_2d(Int order) {
596  return ((order + 1) * (order + 2) / 2);
597 }
598 
599 template <Int dim, Int order>
600 struct NumMoments;
601 
602 template <Int order>
603 struct NumMoments<3, order> {
604  enum { value = num_moments_3d(order) };
605 };
606 
607 template <Int order>
608 struct NumMoments<2, order> {
609  enum { value = num_moments_2d(order) };
610 };
611 
635 template <Int polyorder>
636 R3D_INLINE void reduce(Polytope<3> const& poly, Real* moments) {
637  if (poly.nverts <= 0) return;
638 
639  // var declarations
640  Real sixv;
641  Int np, m, i, j, k, corder;
642  Int vstart, pstart, vcur, vnext, pnext;
643  Vector<3> v0, v1, v2;
644 
645  // zero the moments
646  for (m = 0; m < num_moments_3d(polyorder); ++m) moments[m] = 0.0;
647 
648  // for keeping track of which edges have been visited
649  Int emarks[Polytope<3>::max_verts][3] = {{}}; // initialized to zero
650 
651  // Storage for coefficients
652  // keep two layers of the pyramid of coefficients
653  // Note: Uses twice as much space as needed, but indexing is faster this way
654  Int prevlayer = 0;
655  Int curlayer = 1;
656  Real S[polyorder + 1][polyorder + 1][2];
657  Real D[polyorder + 1][polyorder + 1][2];
658  Real C[polyorder + 1][polyorder + 1][2];
659 
660  // loop over all vertices to find the starting point for each face
661  for (vstart = 0; vstart < poly.nverts; ++vstart)
662  for (pstart = 0; pstart < 3; ++pstart) {
663  // skip this face if we have marked it
664  if (emarks[vstart][pstart]) continue;
665 
666  // initialize face looping
667  pnext = pstart;
668  vcur = vstart;
669  emarks[vcur][pnext] = 1;
670  vnext = poly.verts[vcur].pnbrs[pnext];
671  v0 = poly.verts[vcur].pos;
672 
673  // move to the second edge
674  for (np = 0; np < 3; ++np)
675  if (poly.verts[vnext].pnbrs[np] == vcur) break;
676  vcur = vnext;
677  pnext = (np + 1) % 3;
678  emarks[vcur][pnext] = 1;
679  vnext = poly.verts[vcur].pnbrs[pnext];
680 
681  // make a triangle fan using edges
682  // and first vertex
683  while (vnext != vstart) {
684  v2 = poly.verts[vcur].pos;
685  v1 = poly.verts[vnext].pos;
686 
687  sixv = (-v2[0] * v1[1] * v0[2] + v1[0] * v2[1] * v0[2] +
688  v2[0] * v0[1] * v1[2] - v0[0] * v2[1] * v1[2] -
689  v1[0] * v0[1] * v2[2] + v0[0] * v1[1] * v2[2]);
690 
691  // calculate the moments
692  // using the fast recursive method of Koehl (2012)
693  // essentially building a set of trinomial pyramids, one layer at a time
694 
695  // base case
696  S[0][0][prevlayer] = 1.0;
697  D[0][0][prevlayer] = 1.0;
698  C[0][0][prevlayer] = 1.0;
699  moments[0] += ONE_SIXTH * sixv;
700 
701  // build up successive polynomial orders
702  for (corder = 1, m = 1; corder <= polyorder; ++corder) {
703  for (i = corder; i >= 0; --i)
704  for (j = corder - i; j >= 0; --j, ++m) {
705  k = corder - i - j;
706  C[i][j][curlayer] = 0;
707  D[i][j][curlayer] = 0;
708  S[i][j][curlayer] = 0;
709  if (i > 0) {
710  C[i][j][curlayer] += v2[0] * C[i - 1][j][prevlayer];
711  D[i][j][curlayer] += v1[0] * D[i - 1][j][prevlayer];
712  S[i][j][curlayer] += v0[0] * S[i - 1][j][prevlayer];
713  }
714  if (j > 0) {
715  C[i][j][curlayer] += v2[1] * C[i][j - 1][prevlayer];
716  D[i][j][curlayer] += v1[1] * D[i][j - 1][prevlayer];
717  S[i][j][curlayer] += v0[1] * S[i][j - 1][prevlayer];
718  }
719  if (k > 0) {
720  C[i][j][curlayer] += v2[2] * C[i][j][prevlayer];
721  D[i][j][curlayer] += v1[2] * D[i][j][prevlayer];
722  S[i][j][curlayer] += v0[2] * S[i][j][prevlayer];
723  }
724  D[i][j][curlayer] += C[i][j][curlayer];
725  S[i][j][curlayer] += D[i][j][curlayer];
726  moments[m] += sixv * S[i][j][curlayer];
727  }
728  curlayer = 1 - curlayer;
729  prevlayer = 1 - prevlayer;
730  }
731 
732  // move to the next edge
733  for (np = 0; np < 3; ++np)
734  if (poly.verts[vnext].pnbrs[np] == vcur) break;
735  vcur = vnext;
736  pnext = (np + 1) % 3;
737  emarks[vcur][pnext] = 1;
738  vnext = poly.verts[vcur].pnbrs[pnext];
739  }
740  }
741 
742  // reuse C to recursively compute the leading multinomial coefficients
743  C[0][0][prevlayer] = 1.0;
744  for (corder = 1, m = 1; corder <= polyorder; ++corder) {
745  for (i = corder; i >= 0; --i)
746  for (j = corder - i; j >= 0; --j, ++m) {
747  k = corder - i - j;
748  C[i][j][curlayer] = 0.0;
749  if (i > 0) C[i][j][curlayer] += C[i - 1][j][prevlayer];
750  if (j > 0) C[i][j][curlayer] += C[i][j - 1][prevlayer];
751  if (k > 0) C[i][j][curlayer] += C[i][j][prevlayer];
752  moments[m] /=
753  C[i][j][curlayer] * (corder + 1) * (corder + 2) * (corder + 3);
754  }
755  curlayer = 1 - curlayer;
756  prevlayer = 1 - prevlayer;
757  }
758 }
759 
782 template <Int polyorder>
783 R3D_INLINE void reduce(Polytope<2> const& poly, Real* moments) {
784  if (poly.nverts <= 0) return;
785 
786  // var declarations
787  Int vcur, vnext, m, i, j, corder;
788  Real twoa;
789  Vector<2> v0, v1;
790 
791  // zero the moments
792  for (m = 0; m < num_moments_2d(polyorder); ++m) moments[m] = 0.0;
793 
794  // Storage for coefficients
795  // keep two layers of the triangle of coefficients
796  Int prevlayer = 0;
797  Int curlayer = 1;
798  Real D[polyorder + 1][2];
799  Real C[polyorder + 1][2];
800 
801  // iterate over edges and compute a sum over simplices
802  for (vcur = 0; vcur < poly.nverts; ++vcur) {
803  vnext = poly.verts[vcur].pnbrs[0];
804  v0 = poly.verts[vcur].pos;
805  v1 = poly.verts[vnext].pos;
806  twoa = (v0[0] * v1[1] - v0[1] * v1[0]);
807 
808  // calculate the moments
809  // using the fast recursive method of Koehl (2012)
810  // essentially building a set of Pascal's triangles, one layer at a time
811 
812  // base case
813  D[0][prevlayer] = 1.0;
814  C[0][prevlayer] = 1.0;
815  moments[0] += 0.5 * twoa;
816 
817  // build up successive polynomial orders
818  for (corder = 1, m = 1; corder <= polyorder; ++corder) {
819  for (i = corder; i >= 0; --i, ++m) {
820  j = corder - i;
821  C[i][curlayer] = 0;
822  D[i][curlayer] = 0;
823  if (i > 0) {
824  C[i][curlayer] += v1[0] * C[i - 1][prevlayer];
825  D[i][curlayer] += v0[0] * D[i - 1][prevlayer];
826  }
827  if (j > 0) {
828  C[i][curlayer] += v1[1] * C[i][prevlayer];
829  D[i][curlayer] += v0[1] * D[i][prevlayer];
830  }
831  D[i][curlayer] += C[i][curlayer];
832  moments[m] += twoa * D[i][curlayer];
833  }
834  curlayer = 1 - curlayer;
835  prevlayer = 1 - prevlayer;
836  }
837  }
838 
839  // reuse C to recursively compute the leading multinomial coefficients
840  C[0][prevlayer] = 1.0;
841  for (corder = 1, m = 1; corder <= polyorder; ++corder) {
842  for (i = corder; i >= 0; --i, ++m) {
843  j = corder - i;
844  C[i][curlayer] = 0.0;
845  if (i > 0) C[i][curlayer] += C[i - 1][prevlayer];
846  if (j > 0) C[i][curlayer] += C[i][prevlayer];
847  moments[m] /= C[i][curlayer] * (corder + 1) * (corder + 2);
848  }
849  curlayer = 1 - curlayer;
850  prevlayer = 1 - prevlayer;
851  }
852 }
853 
854 template <Int dim, Int order>
855 struct Polynomial {
856  enum { nterms = NumMoments<dim, order>::value };
857  Real coeffs[nterms];
858 };
859 
860 template <Int dim, Int order>
861 R3D_INLINE Real integrate(
862  Polytope<dim> const& polytope, Polynomial<dim, order> polynomial) {
863  Real moments[decltype(polynomial)::nterms] = {};
864  reduce<order>(polytope, moments);
865  Real result = 0;
866  for (Int i = 0; i < decltype(polynomial)::nterms; ++i)
867  result += moments[i] * polynomial.coeffs[i];
868  return result;
869 }
870 
871 /* Cop-out: instead of figuring out how to implement
872  integrate() for 1D edges, just hardcode the
873  length measurement */
874 R3D_INLINE Real measure(Polytope<1> const& polytope) {
875  return std::abs(polytope.verts[1].pos[0] - polytope.verts[0].pos[0]);
876 }
877 
878 R3D_INLINE Real measure(Polytope<2> const& polytope) {
879  return integrate(polytope, Polynomial<2, 0>{{1}});
880 }
881 
882 R3D_INLINE Real measure(Polytope<3> const& polytope) {
883  return integrate(polytope, Polynomial<3, 0>{{1}});
884 }
885 
886 template <Int dim>
887 R3D_INLINE void intersect_simplices(Polytope<dim>& poly,
888  Few<Vector<dim>, dim + 1> verts0, Few<Vector<dim>, dim + 1> verts1) {
889  init(poly, verts0);
890  auto faces1 = faces_from_verts(verts1);
891  clip(poly, faces1);
892 }
893 
918 R3D_INLINE void init_poly(Polytope<3>& poly, Vector<3>* vertices, Int numverts,
919  Int** faceinds, Int* numvertsperface, Int numfaces) {
920  // dummy vars
921  Int v, vprev, vcur, vnext, f, np;
922 
923  // count up the number of faces per vertex
924  // and act accordingly
925  Int eperv[R3D_MAX_VERTS] = {0};
926  Int maxeperv = 0;
927  for (f = 0; f < numfaces; ++f)
928  for (v = 0; v < numvertsperface[f]; ++v) ++eperv[faceinds[f][v]];
929  for (v = 0; v < numverts; ++v)
930  if (eperv[v] > maxeperv) maxeperv = eperv[v];
931 
932  // clear the poly
933  poly.nverts = 0;
934 
935  if (maxeperv == 3) {
936  // simple case with no need for duplicate vertices
937 
938  // read in vertex locations
939  poly.nverts = numverts;
940  for (v = 0; v < poly.nverts; ++v) {
941  poly.verts[v].pos = vertices[v];
942  for (np = 0; np < 3; ++np) poly.verts[v].pnbrs[np] = R3D_MAX_VERTS;
943  }
944 
945  // build graph connectivity by correctly orienting half-edges for each
946  // vertex
947  for (f = 0; f < numfaces; ++f) {
948  for (v = 0; v < numvertsperface[f]; ++v) {
949  vprev = faceinds[f][v];
950  vcur = faceinds[f][(v + 1) % numvertsperface[f]];
951  vnext = faceinds[f][(v + 2) % numvertsperface[f]];
952  for (np = 0; np < 3; ++np) {
953  if (poly.verts[vcur].pnbrs[np] == vprev) {
954  poly.verts[vcur].pnbrs[(np + 2) % 3] = vnext;
955  break;
956  } else if (poly.verts[vcur].pnbrs[np] == vnext) {
957  poly.verts[vcur].pnbrs[(np + 1) % 3] = vprev;
958  break;
959  }
960  }
961  if (np == 3) {
962  poly.verts[vcur].pnbrs[1] = vprev;
963  poly.verts[vcur].pnbrs[0] = vnext;
964  }
965  }
966  }
967  } else {
968  // we need to create duplicate, degenerate vertices to account for more than
969  // three edges per vertex. This is complicated.
970 
971  // need more variables
972  Int v0, v1, v00, v11, numunclipped;
973 
974  // we need a few extra buffers to handle the necessary operations
975  Vertex<3> vbtmp[3 * R3D_MAX_VERTS];
976  Int vstart[R3D_MAX_VERTS];
977 
978  // build vertex mappings to degenerate duplicates
979  // and read in vertex locations
980  poly.nverts = 0;
981  for (v = 0; v < numverts; ++v) {
982  vstart[v] = poly.nverts;
983  for (vcur = 0; vcur < eperv[v]; ++vcur) {
984  vbtmp[poly.nverts].pos = vertices[v];
985  for (np = 0; np < 3; ++np) vbtmp[poly.nverts].pnbrs[np] = R3D_MAX_VERTS;
986  ++(poly.nverts);
987  }
988  }
989 
990  // fill in connectivity for all duplicates
991  {
992  Int util[3 * R3D_MAX_VERTS] = {0};
993  for (f = 0; f < numfaces; ++f) {
994  for (v = 0; v < numvertsperface[f]; ++v) {
995  vprev = faceinds[f][v];
996  vcur = faceinds[f][(v + 1) % numvertsperface[f]];
997  vnext = faceinds[f][(v + 2) % numvertsperface[f]];
998  auto vcur_old = vcur;
999  vcur = vstart[vcur] + util[vcur];
1000  util[vcur_old]++;
1001  vbtmp[vcur].pnbrs[1] = vnext;
1002  vbtmp[vcur].pnbrs[2] = vprev;
1003  }
1004  }
1005  }
1006 
1007  // link degenerate duplicates, putting them in the correct order
1008  // use util to mark and avoid double-processing verts
1009  {
1010  Int util[3 * R3D_MAX_VERTS] = {0};
1011  for (v = 0; v < numverts; ++v) {
1012  for (v0 = vstart[v]; v0 < vstart[v] + eperv[v]; ++v0) {
1013  for (v1 = vstart[v]; v1 < vstart[v] + eperv[v]; ++v1) {
1014  if (vbtmp[v0].pnbrs[2] == vbtmp[v1].pnbrs[1] && !util[v0]) {
1015  vbtmp[v0].pnbrs[2] = v1;
1016  vbtmp[v1].pnbrs[0] = v0;
1017  util[v0] = 1;
1018  }
1019  }
1020  }
1021  }
1022  }
1023 
1024  // complete vertex pairs
1025  {
1026  Int util[3 * R3D_MAX_VERTS] = {0};
1027  for (v0 = 0; v0 < numverts; ++v0)
1028  for (v1 = v0 + 1; v1 < numverts; ++v1) {
1029  for (v00 = vstart[v0]; v00 < vstart[v0] + eperv[v0]; ++v00)
1030  for (v11 = vstart[v1]; v11 < vstart[v1] + eperv[v1]; ++v11) {
1031  if (vbtmp[v00].pnbrs[1] == v1 && vbtmp[v11].pnbrs[1] == v0 &&
1032  !util[v00] && !util[v11]) {
1033  vbtmp[v00].pnbrs[1] = v11;
1034  vbtmp[v11].pnbrs[1] = v00;
1035  util[v00] = 1;
1036  util[v11] = 1;
1037  }
1038  }
1039  }
1040  }
1041 
1042  // remove unnecessary dummy vertices
1043  {
1044  Int util[3 * R3D_MAX_VERTS] = {0};
1045  for (v = 0; v < numverts; ++v) {
1046  v0 = vstart[v];
1047  v1 = vbtmp[v0].pnbrs[0];
1048  v00 = vbtmp[v0].pnbrs[2];
1049  v11 = vbtmp[v1].pnbrs[0];
1050  vbtmp[v00].pnbrs[0] = vbtmp[v0].pnbrs[1];
1051  vbtmp[v11].pnbrs[2] = vbtmp[v1].pnbrs[1];
1052  for (np = 0; np < 3; ++np)
1053  if (vbtmp[vbtmp[v0].pnbrs[1]].pnbrs[np] == v0) break;
1054  vbtmp[vbtmp[v0].pnbrs[1]].pnbrs[np] = v00;
1055  for (np = 0; np < 3; ++np)
1056  if (vbtmp[vbtmp[v1].pnbrs[1]].pnbrs[np] == v1) break;
1057  vbtmp[vbtmp[v1].pnbrs[1]].pnbrs[np] = v11;
1058  util[v0] = 1;
1059  util[v1] = 1;
1060  }
1061 
1062  // copy to the real vertbuffer and compress
1063  numunclipped = 0;
1064  for (v = 0; v < poly.nverts; ++v) {
1065  if (!util[v]) {
1066  poly.verts[numunclipped] = vbtmp[v];
1067  util[v] = numunclipped++;
1068  }
1069  }
1070  poly.nverts = numunclipped;
1071  for (v = 0; v < poly.nverts; ++v)
1072  for (np = 0; np < 3; ++np)
1073  poly.verts[v].pnbrs[np] = util[poly.verts[v].pnbrs[np]];
1074  }
1075  }
1076 }
1077 
1093 R3D_INLINE void init_poly(
1094  Polytope<2>& poly, Vector<2>* vertices, Int numverts) {
1095  poly.nverts = numverts;
1096  Int v;
1097  for (v = 0; v < poly.nverts; ++v) {
1098  poly.verts[v].pos = vertices[v];
1099  poly.verts[v].pnbrs[0] = (v + 1) % (poly.nverts);
1100  poly.verts[v].pnbrs[1] = (poly.nverts + v - 1) % (poly.nverts);
1101  }
1102 }
1103 
1126 R3D_INLINE void poly_faces_from_verts(Plane<3>* faces, Vector<3>* vertices,
1127  Int** faceinds, Int* numvertsperface, Int numfaces) {
1128  // dummy vars
1129  Int v, f;
1130  Vector<3> p0, p1, p2;
1131 
1132  // calculate a centroid and a unit normal for each face
1133  for (f = 0; f < numfaces; ++f) {
1134  auto centroid = vector_3(0, 0, 0);
1135  faces[f].n = vector_3(0, 0, 0);
1136 
1137  for (v = 0; v < numvertsperface[f]; ++v) {
1138  // add cross product of edges to the total normal
1139  p0 = vertices[faceinds[f][v]];
1140  p1 = vertices[faceinds[f][(v + 1) % numvertsperface[f]]];
1141  p2 = vertices[faceinds[f][(v + 2) % numvertsperface[f]]];
1142  faces[f].n = faces[f].n + cross(p1 - p0, p2 - p0);
1143 
1144  // add the vertex position to the centroid
1145  centroid = centroid + p0;
1146  }
1147 
1148  // normalize the normals and set the signed distance to origin
1149  centroid = centroid / Real(numvertsperface[f]);
1150  faces[f].n = normalize(faces[f].n);
1151  faces[f].d = -(faces[f].n * centroid);
1152  }
1153 }
1154 
1155 } // end namespace r3d
1156 
1157 #endif
Definition: r3d.hpp:86
Definition: r3d.hpp:70
Definition: r3d.hpp:312
Definition: r3d.hpp:273
Definition: r3d.hpp:600
Definition: r3d.hpp:261
Vector< dim > n
Definition: r3d.hpp:262
Real d
Definition: r3d.hpp:263
Definition: r3d.hpp:855
A polyhedron. Can be convex, nonconvex, even multiply-connected.
Definition: r3d.hpp:294
Int nverts
Definition: r3d.hpp:297
Vertex< dim > verts[max_verts]
Definition: r3d.hpp:296
Definition: r3d.hpp:144
Definition: r3d.hpp:267
Int pnbrs[dim]
Definition: r3d.hpp:268
Vector< dim > pos
Definition: r3d.hpp:269