SPH
Mesh.cpp
Go to the documentation of this file.
1 #include "post/Mesh.h"
3 #include <map>
4 #include <set>
5 
7 
8 inline std::pair<int, int> makeEdge(const int i1, const int i2) {
9  return std::make_pair(min(i1, i2), max(i1, i2));
10 }
11 
12 bool isMeshClosed(const Mesh& mesh) {
13  std::map<std::pair<int, int>, Array<Size>> edges;
14  for (Size i = 0; i < mesh.faces.size(); ++i) {
15  const Mesh::Face& f = mesh.faces[i];
16  edges[makeEdge(f[0], f[1])].push(i);
17  edges[makeEdge(f[0], f[2])].push(i);
18  edges[makeEdge(f[1], f[2])].push(i);
19  }
20 
21  for (auto& p : edges) {
22  if (p.second.size() != 2) {
23  return false;
24  }
25  }
26  return true;
27 }
28 
29 void refineMesh(Mesh& mesh) {
30  Array<std::set<Size>> vertexNeighs(mesh.vertices.size());
31  for (Size i = 0; i < mesh.faces.size(); ++i) {
32  const Mesh::Face& f = mesh.faces[i];
33  vertexNeighs[f[0]].insert(f[1]);
34  vertexNeighs[f[0]].insert(f[2]);
35  vertexNeighs[f[1]].insert(f[0]);
36  vertexNeighs[f[1]].insert(f[2]);
37  vertexNeighs[f[2]].insert(f[0]);
38  vertexNeighs[f[2]].insert(f[1]);
39  }
40 
41  Array<Vector> grads(mesh.vertices.size());
42  for (Size i = 0; i < mesh.vertices.size(); ++i) {
43  Vector grad = -mesh.vertices[i];
44 
45  for (Size j : vertexNeighs[i]) {
46  grad += mesh.vertices[j] / vertexNeighs[i].size();
47  }
48  grads[i] = grad;
49  }
50 
51  for (Size i = 0; i < mesh.vertices.size(); ++i) {
52  mesh.vertices[i] += 0.5f * grads[i];
53  }
54 }
55 
56 void subdivideMesh(Mesh& mesh) {
57  Array<Mesh::Face> newFaces;
58  for (Mesh::Face& face : mesh.faces) {
59  const Vector p1 = mesh.vertices[face[0]];
60  const Vector p2 = mesh.vertices[face[1]];
61  const Vector p3 = mesh.vertices[face[2]];
62  const Vector p12 = 0.5_f * (p1 + p2);
63  const Vector p13 = 0.5_f * (p1 + p3);
64  const Vector p23 = 0.5_f * (p2 + p3);
65  const Size i2 = face[1];
66  const Size i3 = face[2];
67  const Size i12 = mesh.vertices.size();
68  const Size i13 = i12 + 1;
69  const Size i23 = i12 + 2;
70  mesh.vertices.push(p12);
71  mesh.vertices.push(p13);
72  mesh.vertices.push(p23);
73 
74  newFaces.push(Mesh::Face{ i12, i2, i23 });
75  newFaces.push(Mesh::Face{ i13, i23, i3 });
76  newFaces.push(Mesh::Face{ i13, i12, i23 });
77  face[1] = i12;
78  face[2] = i13;
79  }
80  mesh.faces.pushAll(std::move(newFaces));
81 }
82 
84  Mesh mesh;
85  mesh.faces.resize(triangles.size());
86 
87  // get order of vertices sorted lexicographically
88  Order lexicographicalOrder(triangles.size() * 3);
89  lexicographicalOrder.shuffle([&triangles](const Size i1, const Size i2) {
90  const Vector v1 = triangles[i1 / 3][i1 % 3];
91  const Vector v2 = triangles[i2 / 3][i2 % 3];
92  return lexicographicalLess(v1, v2);
93  });
94 
95  // get inverted permutation: maps index of particle to its position in lexicographically sorted array
96  Order mappingOrder = lexicographicalOrder.getInverted();
97 
98  // holds indices of vertices already used, maps index in input array to index in output array
99  Array<Size> insertedVerticesIdxs(triangles.size() * 3);
100  insertedVerticesIdxs.fill(Size(-1));
101 
102  for (Size i = 0; i < triangles.size(); ++i) {
103  const Triangle& tri = triangles[i];
104  for (Size j = 0; j < 3; ++j) {
105  // get order in sorted array
106  const Size idxInSorted = mappingOrder[3 * i + j];
107 
108  bool vertexFound = false;
109 
110  auto check = [&](const Size k) {
111  const Size idxInInput = lexicographicalOrder[k];
112  const Vector v = triangles[idxInInput / 3][idxInInput % 3];
113  if (almostEqual(tri[j], v, eps)) {
114  if (insertedVerticesIdxs[idxInInput] != Size(-1)) {
115  // this vertex was already found; just push the index
116  mesh.faces[i][j] = insertedVerticesIdxs[idxInInput];
117  // also update the index of this verted (not really needed, might speed things up)
118  insertedVerticesIdxs[3 * i + j] = insertedVerticesIdxs[idxInInput];
119  vertexFound = true;
120  return false;
121  } else {
122  // same vertex, but also not used, keep going
123  return true;
124  }
125  } else {
126  // different vertex
127  return false;
128  }
129  };
130  // look for equal (or almost equal) vertices higher in order and check whether we used them
131  for (Size k = idxInSorted + 1; k < lexicographicalOrder.size(); ++k) {
132  if (!check(k)) {
133  break;
134  }
135  }
136  // also look for vertices lower in order (use signed k!)
137  if (!vertexFound) {
138  for (int k = idxInSorted - 1; k >= 0; --k) {
139  if (!check(k)) {
140  break;
141  }
142  }
143  }
144 
145  if (!vertexFound) {
146  // update the map
147  insertedVerticesIdxs[3 * i + j] = mesh.vertices.size();
148 
149  // add the current vertex and its index
150  mesh.faces[i][j] = mesh.vertices.size();
151  mesh.vertices.push(tri[j]);
152  }
153  }
154  }
155 
156  // remove degenerate faces
157  Array<Size> toRemove;
158  for (Size i = 0; i < mesh.faces.size(); ++i) {
159  const Mesh::Face& f = mesh.faces[i];
160  if (f[0] == f[1] || f[1] == f[2] || f[0] == f[2]) {
161  toRemove.push(i);
162  }
163  }
164  mesh.faces.remove(toRemove);
165 
166  return mesh;
167 }
168 
170  Array<Triangle> triangles(mesh.faces.size());
171  for (Size i = 0; i < mesh.faces.size(); ++i) {
172  triangles[i] = Triangle(mesh.vertices[mesh.faces[i][0]],
173  mesh.vertices[mesh.faces[i][1]],
174  mesh.vertices[mesh.faces[i][2]]);
175  }
176  return triangles;
177 }
178 
INLINE bool almostEqual(const AffineMatrix &m1, const AffineMatrix &m2, const Float eps=EPS)
Definition: AffineMatrix.h:278
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
Definition: Globals.h:13
constexpr INLINE T max(const T &f1, const T &f2)
Definition: MathBasic.h:20
NAMESPACE_SPH_BEGIN constexpr INLINE T min(const T &f1, const T &f2)
Minimum & Maximum value.
Definition: MathBasic.h:15
void refineMesh(Mesh &mesh)
Improves mesh quality using edge flips (valence equalization) and tangential relaxation.
Definition: Mesh.cpp:29
bool isMeshClosed(const Mesh &mesh)
Checks if the mesh represents a single closed surface.
Definition: Mesh.cpp:12
void subdivideMesh(Mesh &mesh)
Subdivides all triangles of the mesh using 1-4 scheme.
Definition: Mesh.cpp:56
NAMESPACE_SPH_BEGIN std::pair< int, int > makeEdge(const int i1, const int i2)
Definition: Mesh.cpp:8
Mesh getMeshFromTriangles(ArrayView< const Triangle > triangles, const Float eps)
Converts array of triangles into a mesh.
Definition: Mesh.cpp:83
Array< Triangle > getTrianglesFromMesh(const Mesh &mesh)
Expands the mesh into an array of triangles.
Definition: Mesh.cpp:169
#define NAMESPACE_SPH_END
Definition: Object.h:12
Helper object defining permutation.
INLINE bool lexicographicalLess(const Vector &v1, const Vector &v2)
Compares components of two vectors lexicographically, primary component is z.
Definition: Vector.h:833
Object providing safe access to continuous memory of data.
Definition: ArrayView.h:17
INLINE TCounter size() const
Definition: ArrayView.h:101
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
Definition: Array.h:306
void fill(const T &t)
Sets all elements of the array to given value.
Definition: Array.h:187
void insert(const TCounter position, U &&value)
Inserts a new element to given position in the array.
Definition: Array.h:345
INLINE TCounter size() const noexcept
Definition: Array.h:193
Permutation, i.e. (discrete) invertible function int->int.
Definition: Order.h:18
INLINE Size size() const
Definition: Order.h:88
void shuffle(TBinaryPredicate &&predicate)
Shuffles the order using a binary predicate.
Definition: Order.h:47
Order getInverted() const
Returns the inverted order.
Definition: Order.h:52
Triangle.h.
Definition: Triangle.h:14
Definition: Mesh.h:7
Array< Vector > vertices
Definition: Mesh.h:8
Array< Face > faces
Definition: Mesh.h:47