ug4
simplification.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2015: G-CSC, Goethe University Frankfurt
3  * Author: Sebastian Reiter
4  *
5  * This file is part of UG4.
6  *
7  * UG4 is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License version 3 (as published by the
9  * Free Software Foundation) with the following additional attribution
10  * requirements (according to LGPL/GPL v3 §7):
11  *
12  * (1) The following notice must be displayed in the Appropriate Legal Notices
13  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14  *
15  * (2) The following notice must be displayed at a prominent place in the
16  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17  *
18  * (3) The following bibliography is recommended for citation and must be
19  * preserved in all covered files:
20  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21  * parallel geometric multigrid solver on hierarchically distributed grids.
22  * Computing and visualization in science 16, 4 (2013), 151-164"
23  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24  * flexible software system for simulating pde based models on high performance
25  * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30  * GNU Lesser General Public License for more details.
31  */
32 
33 #ifndef __H__UG_simplification
34 #define __H__UG_simplification
35 
36 #include "common/math/ugmath.h"
39 #include "lib_grid/grid/grid.h"
40 
41 namespace ug{
42 
43 inline bool Valence3VertexIsObsolete(const vector3& p, const vector3& c0,
44  const vector3& c1, const vector3& c2,
45  number maxSquaredHeightToBaseAreaRatio)
46 {
47  vector3 proj, n;
49  if(RayTriangleIntersection(proj, c0, c1, c2, p, n)){
50  number hsq = VecDistanceSq(proj, p);
51  number area = TriangleArea(c0, c1, c2);
52 
53  if(area > 0)
54  return (hsq / area) < maxSquaredHeightToBaseAreaRatio;
55  }
56  return false;
57 }
58 
60 inline bool Valence4VertexIsObsolete(const vector3& p, const vector3& c0,
61  const vector3& c1, const vector3& c2,
62  const vector3& c3,
63  number maxSquaredHeightToBaseAreaRatio)
64 {
65  vector3 proj, n, n1, n2;
66  CalculateTriangleNormalNoNormalize(n1, c0, c1, c2);
67  CalculateTriangleNormalNoNormalize(n2, c0, c2, c3);
68 
69  VecAdd(n, n1, n2);
70 
71  if(RayTriangleIntersection(proj, c0, c1, c2, p, n)){
72  number hsq = VecDistanceSq(proj, p);
73  number area = TriangleArea(c0, c1, c2) + TriangleArea(c0, c2, c3);
74 
75  if(area > 0)
76  return (hsq / area) < maxSquaredHeightToBaseAreaRatio;
77  }
78 
79  if(RayTriangleIntersection(proj, c0, c2, c3, p, n)){
80  number hsq = VecDistanceSq(proj, p);
81  number area = TriangleArea(c0, c1, c2) + TriangleArea(c0, c2, c3);
82 
83  if(area > 0)
84  return (hsq / area) < maxSquaredHeightToBaseAreaRatio;
85  }
86 
87  return false;
88 }
89 
91 
92 inline bool QuadDiagonalIsValid(const vector3& c0, const vector3& c1,
93  const vector3& c2, const vector3& c3)
94 {
95  vector3 n0, n1;
96  CalculateTriangleNormalNoNormalize(n0, c0, c1, c2);
97  CalculateTriangleNormalNoNormalize(n1, c0, c2, c3);
98  return VecDot(n0, n1) > SMALL;
99 }
100 
101 
102 template <class TVrtIter, class TAAPos>
103 void ReplaceValence3Vertices(Grid& g, TVrtIter vrtsBegin, TVrtIter vrtsEnd,
104  number maxSquaredHeightToBaseAreaRatio, TAAPos aaPos)
105 {
106  using namespace std;
107 
109  Vertex* conVrts[3];
110 
111  std::vector<Vertex*> candidates;
112 
113  for(TVrtIter iter = vrtsBegin; iter != vrtsEnd;)
114  {
115  Vertex* vrt = *iter;
116  ++iter;
117  g.associated_elements(faces, vrt);
118 
119  if(faces.size() != 3)
120  continue;
121 
122  // get the connected vertices. If there are more or less than 3 connected
123  // vertices, then the connected triangles do not form a valid closed surface patch
124  size_t numConVrts = 0;
125  for(size_t i = 0; i < faces.size(); ++i){
126  Face* f = faces[i];
127  if(f->num_vertices() != 3){
128  numConVrts = 0;
129  break;
130  }
131 
132  int baseInd = GetVertexIndex(f, vrt);
133 
134  for(size_t j = 1; j < 3; ++j){
135  Vertex* cv = f->vertex((baseInd + j) % 3);
136  if(cv != vrt){
137  bool gotOne = false;
138  for(size_t k = 0; k < numConVrts; ++k){
139  if(conVrts[k] == cv){
140  gotOne = true;
141  break;
142  }
143  }
144  if(!gotOne){
145  if(numConVrts < 3)
146  conVrts[numConVrts] = cv;
147  ++numConVrts;
148  }
149  }
150  }
151  }
152 
153  if(numConVrts == 3){
154  if(Valence3VertexIsObsolete(aaPos[vrt], aaPos[conVrts[0]],
155  aaPos[conVrts[1]], aaPos[conVrts[2]],
156  maxSquaredHeightToBaseAreaRatio))
157  {
158  g.create<Triangle>(TriangleDescriptor(conVrts[0], conVrts[1], conVrts[2]), faces[0]);
159  g.erase(vrt);
160  }
161  }
162  }
163 }
164 
165 
166 template <class TVrtIter, class TAAPos>
167 void ReplaceLowValenceVertices(Grid& g, TVrtIter vrtsBegin, TVrtIter vrtsEnd,
168  number maxSquaredHeightToBaseAreaRatio, TAAPos aaPos)
169 {
170  using namespace std;
171 
173  Vertex* conVrts[4];
174 
175 // used for valence-4 only
176  vector<Vertex*> poly;
177  vector<Edge*> conEdges;
178 
179 // when we remove a vertex, the valencies of adjacent vertices change.
180 // We thus operate on two candidate arrays. One which holds all vertices
181 // which are current candidates, and one which records all vertices, which have
182 // not been removed. After each run over alll candidates we compare both arrays.
183 // If they have the same length, we're done. If not, we'll run again over all
184 // new candidates.
185  std::vector<Vertex*> candidates;
186  std::vector<Vertex*> newCandidates;
187 
188  for(TVrtIter iter = vrtsBegin; iter != vrtsEnd; ++iter)
189  newCandidates.push_back(*iter);
190 
191  while(newCandidates.size() != candidates.size())
192  {
193  candidates.swap(newCandidates);
194  newCandidates.clear();
195 
196  for(size_t icand = 0; icand < candidates.size(); ++icand)
197  {
198  Vertex* vrt = candidates[icand];
199 
200  // if vrt will be removed, we'll call 'pop_back'
201  newCandidates.push_back(vrt);
202 
203  g.associated_elements(faces, vrt);
204 
205  if(faces.size() < 3 || faces.size() > 4)
206  continue;
207 
208  // get the connected vertices. If there are more or less than 3 connected
209  // vertices, then the connected triangles do not form a valid closed surface patch
210  size_t numConVrts = 0;
211  for(size_t i = 0; i < faces.size(); ++i){
212  Face* f = faces[i];
213  if(f->num_vertices() != 3){
214  numConVrts = 0;
215  break;
216  }
217 
218  int baseInd = GetVertexIndex(f, vrt);
219 
220  for(size_t j = 1; j < 3; ++j){
221  Vertex* cv = f->vertex((baseInd + j) % 3);
222  if(cv != vrt){
223  bool gotOne = false;
224  for(size_t k = 0; k < numConVrts; ++k){
225  if(conVrts[k] == cv){
226  gotOne = true;
227  break;
228  }
229  }
230  if(!gotOne){
231  if(numConVrts < 4)
232  conVrts[numConVrts] = cv;
233  ++numConVrts;
234  }
235  }
236  }
237  }
238 
239  if(numConVrts != faces.size())
240  continue;
241 
242  if(numConVrts == 3){
243  if(Valence3VertexIsObsolete(aaPos[vrt], aaPos[conVrts[0]],
244  aaPos[conVrts[1]], aaPos[conVrts[2]],
245  maxSquaredHeightToBaseAreaRatio))
246  {
247  // vrt is currently the last entry in newCandidates and has to be removed
248  newCandidates.pop_back();
249  g.create<Triangle>(TriangleDescriptor(conVrts[0], conVrts[1], conVrts[2]), faces[0]);
250  g.erase(vrt);
251  }
252  }
253  else if(numConVrts == 4){
254  conEdges.clear();
255  poly.clear();
256  for(size_t i = 0; i < faces.size(); ++i){
257  std::pair<GridBaseObjectId, int> opObj = faces[i]->get_opposing_object(vrt);
258  if(opObj.first == EDGE){
259  Edge* e = g.get_edge(faces[i], opObj.second);
260  if(e)
261  conEdges.push_back(e);
262  }
263  }
264 
265  if(conEdges.size() != 4)
266  continue;
267 
268  CreatePolyChain(poly, g, conEdges.begin(), conEdges.end());
269 
270  // we first try the better quality-diagonal
271  // If this doesn't work, we'll try the other one.
272  // diag 0: create diagonal between vrts 0,2
273  // diag 1: between vrts 1,3
274  number q[2];
275  for(int diag = 0; diag < 2; ++diag){
276  int i0 = diag;
277  int i1 = (diag + 1);
278  int i2 = (diag + 2);
279  int i3 = (diag + 3) % 4;
280  q[diag] = min(TriangleQuality_Area(aaPos[poly[i0]], aaPos[poly[i1]],
281  aaPos[poly[i2]]),
282  TriangleQuality_Area(aaPos[poly[i0]], aaPos[poly[i2]],
283  aaPos[poly[i3]]));
284  }
285 
286  int firstDiag = 0;
287  if(q[1] > q[0])
288  firstDiag = 1;
289 
290  for(int idiag = 0; idiag < 2; ++idiag){
291  int diag = (firstDiag + idiag) % 2;
292  int i0 = diag;
293  int i1 = (diag + 1);
294  int i2 = (diag + 2);
295  int i3 = (diag + 3) % 4;
296 
297  if(!QuadDiagonalIsValid(aaPos[poly[i0]], aaPos[poly[i1]],
298  aaPos[poly[i2]], aaPos[poly[i3]]))
299  {
300  continue;
301  }
302 
303  if(Valence4VertexIsObsolete(aaPos[vrt],
304  aaPos[poly[i0]],
305  aaPos[poly[i1]],
306  aaPos[poly[i2]],
307  aaPos[poly[i3]],
308  maxSquaredHeightToBaseAreaRatio))
309  {
310  // vrt is currently the last entry in newCandidates and has to be removed
311  newCandidates.pop_back();
312 
313  // FaceDescriptor fd(vrt, poly[i0], poly[i1]);
314  // Face* f1 = g.get_face(fd);
315  // if(!f1){
316  // UG_LOG("num vertices in fd: " << fd.num_vertices() << endl);
317  // UG_LOG("Couldn't find face with corners: "
318  // << aaPos[fd.vertex(0)]
319  // << ", " << aaPos[fd.vertex(1)]
320  // << ", " << aaPos[fd.vertex(2)] << endl);
321 
322  // UG_LOG("Existing faces:\n");
323  // for(FaceIterator iter = g.begin<Face>(); iter != g.end<Face>(); ++iter){
324  // UG_LOG(ElementDebugInfo(g, *iter) << endl);
325  // }
326  // }
327 
328  FaceDescriptor fd0(vrt, poly[i0], poly[i1]);
329  FaceDescriptor fd1(vrt, poly[i2], poly[i3]);
330 
331  g.create<Triangle>(TriangleDescriptor(poly[i0],
332  poly[i1],
333  poly[i2]),
334  g.get_face(fd0));
335  g.create<Triangle>(TriangleDescriptor(poly[i0],
336  poly[i2],
337  poly[i3]),
338  g.get_face(fd1));
339  g.erase(vrt);
340  break;
341  }
342  }
343  }
344  }
345  }
346 }
347 
348 
349 
350 // template <class TAAPosVRT, class TAANormVRT, class TAAIntVRT>
351 // Vertex* TryFlatRegionEdgeCollapse(Grid& grid, Edge* e,
352 // TAAPosVRT& aaPos, TAANormVRT& aaNorm,
353 // TAAIntVRT& aaInt, SubsetHandler* pshMarks = NULL,
354 // EdgeSelector* pCandidates = NULL)
355 // {
356 // if(pshMarks)
357 // {
358 // SubsetHandler& shMarks = *pshMarks;
359 // // collapses are not allowed for fixed edges
360 // if(shMarks.get_subset_index(e) == REM_FIXED)
361 // return NULL;
362 
363 // // if both endpoints of are fixed vertices then
364 // // we may not collapse
365 // int vrtSI[2];
366 // vrtSI[0] = shMarks.get_subset_index(e->vertex(0));
367 // vrtSI[1] = shMarks.get_subset_index(e->vertex(1));
368 
369 // if((vrtSI[0] == REM_FIXED) && (vrtSI[1] == REM_FIXED))
370 // return NULL;
371 
372 // // if both endpoints are somehow marked, e has to be a
373 // // crease edge
374 // if((vrtSI[0] != REM_NONE) && (vrtSI[1] != REM_NONE)
375 // && (shMarks.get_subset_index(e) != REM_CREASE))
376 // return NULL;
377 // }
378 
379 // // check whether the edge can be collapsed
380 // if(!EdgeCollapseIsValid(grid, e))
381 // return NULL;
382 
383 
384 // vector3 edgeNormal;
385 // int numNbrFaces = CalculateNormal(edgeNormal, grid, e, aaPos);
386 // //todo: If the edge is a crease edge, we'll have to check the crease-bending...
387 // //UG_COND_THROW(numNbrFaces > 2, "DEBUG-THROW: CREASES ARE TEMPORARILY NOT SUPPORTED IN COLLAPSE EDGE");
388 // if(numNbrFaces > 2){
389 // UG_LOG("DEBUG: IGNORING NON-MANIFOLD EDGE!\n");
390 // return NULL;
391 // }
392 
393 // // compare the normal of the edge that shall be collapsed with the normals
394 // // of its corners.
395 // number cornerDotThreshold = cos(deg_to_rad<number>(0.1));
396 
397 // number cornerDots[2];
398 // int maxCornerDotInd = 0;
399 // for(size_t i = 0; i < 2; ++i)
400 // cornerDots[i] = VecDot(edgeNormal, aaNorm[e->vertex(i)]);
401 // if(cornerDots[1] > cornerDots[0])
402 // maxCornerDotInd = 1;
403 
404 // if(cornerDots[maxCornerDotInd] < cornerDotThreshold)
405 // return NULL;
406 
407 
408 // // collapse the edge
409 // //todo: When creases are involved,we have to do a better check which vertex to preserve
410 // Vertex* vrt = e->vertex(maxCornerDotInd);
411 // CollapseEdge(grid, e, vrt);
412 
413 // return vrt;
414 // }
415 
416 
417 // template <class TVrtIter, class TAAPos>
418 // void CollapseEdgesInFlatRegions(Grid& g, TVrtIter vrtsBegin, TVrtIter vrtsEnd,
419 // number maxNormalDeviation, TAAPos aaPos)
420 // {
421 
422 // }
423 
424 
425 }// end of namespace
426 
427 #endif //__H__simplification
parameterString p
Base-class for edges.
Definition: grid_base_objects.h:397
Can be queried for the edges and vertices of a face.
Definition: grid_base_objects.h:684
Faces are 2-dimensional objects.
Definition: grid_base_objects.h:510
virtual Vertex * vertex(size_t index) const
Definition: grid_base_objects.h:486
virtual size_t num_vertices() const
Definition: grid_base_objects.h:488
Manages the elements of a grid and their interconnection.
Definition: grid.h:132
Edge * get_edge(Vertex *v1, Vertex *v2)
returns the edge between v1 and v2, if it exists. Returns NULL if not.
Definition: grid.cpp:1069
Face * get_face(const FaceVertices &fv)
returns the face that is described by fv.
Definition: grid.cpp:1135
void erase(GridObject *geomObj)
Definition: grid.cpp:459
geometry_traits< TGeomObj >::iterator begin()
Definition: grid_impl.hpp:164
void associated_elements(traits< Vertex >::secure_container &elemsOut, TElem *e)
Puts all elements of type TAss which are contained in 'e' or which contain 'e' into elemsOut.
Definition: grid_impl.hpp:466
geometry_traits< TGeomObj >::iterator create(GridObject *pParent=NULL)
create a custom element.
Definition: grid_impl.hpp:69
Container which holds an array of pointers.
Definition: pointer_const_array.h:84
size_t size() const
returns the size of the associated array.
Definition: pointer_const_array_impl.hpp:106
only used to initialize a triangle. for all other tasks you should use FaceDescriptor.
Definition: grid_objects_2d.h:78
the most simple form of a face
Definition: grid_objects_2d.h:174
Base-class for all vertex-types.
Definition: grid_base_objects.h:231
bool CreatePolyChain(std::vector< Vertex * > &polyChainOut, Grid &grid, TEdgeIter edgesBegin, TEdgeIter edgesEnd)
given a list of edges, this method collects associated vertices in a polychain
Definition: polychain_util_impl.hpp:127
int GetVertexIndex(EdgeVertices *e, Vertex *v)
returns the index at which vertex v is found in the given edge
Definition: vertex_util.cpp:44
double number
Definition: types.h:124
number TriangleArea(const vector_t &p1, const vector_t &p2, const vector_t &p3)
calculates the are of the triangle defined by p1, p2 and p3
Definition: math_util_impl.hpp:914
bool RayTriangleIntersection(vector_t &vOut, number &bc1Out, number &bc2Out, number &tOut, const vector_t &p0, const vector_t &p1, const vector_t &p2, const vector_t &vFrom, const vector_t &vDir, const number small=SMALL)
calculates the intersection of a ray with a triangle
Definition: math_util_impl.hpp:506
number TriangleQuality_Area(const vector_t &p1, const vector_t &p2, const vector_t &p3)
returns a value between 0 and 1. The higher the better.
Definition: math_util_impl.hpp:940
void CalculateTriangleNormalNoNormalize(vector_t &vOut, const vector_t &v1, const vector_t &v2, const vector_t &v3)
Calculates a triangle-normal in 3d (no normalization is performed).
Definition: math_vector_functions_common_impl.hpp:514
vector_t::value_type VecDistanceSq(const vector_t &v1, const vector_t &v2)
returns the squared distance of two vector_ts.
Definition: math_vector_functions_common_impl.hpp:351
void VecAdd(vector_t &vOut, const vector_t &v1, const vector_t &v2)
adds two MathVector<N>s and stores the result in a third one
Definition: math_vector_functions_common_impl.hpp:185
vector_t::value_type VecDot(const vector_t &v1, const vector_t &v2)
returns the dot-product of two vector_ts
Definition: math_vector_functions_common_impl.hpp:385
Definition: smart_pointer.h:814
the ug namespace
bool Valence3VertexIsObsolete(const vector3 &p, const vector3 &c0, const vector3 &c1, const vector3 &c2, number maxSquaredHeightToBaseAreaRatio)
Definition: simplification.h:43
void ReplaceValence3Vertices(Grid &g, TVrtIter vrtsBegin, TVrtIter vrtsEnd, number maxSquaredHeightToBaseAreaRatio, TAAPos aaPos)
Definition: simplification.h:103
const number SMALL
Definition: math_constants.h:41
void ReplaceLowValenceVertices(Grid &g, TVrtIter vrtsBegin, TVrtIter vrtsEnd, number maxSquaredHeightToBaseAreaRatio, TAAPos aaPos)
Definition: simplification.h:167
bool QuadDiagonalIsValid(const vector3 &c0, const vector3 &c1, const vector3 &c2, const vector3 &c3)
returns true if the normals of the resulting triangles point into the same direction
Definition: simplification.h:92
@ EDGE
Definition: grid_base_objects.h:61
bool Valence4VertexIsObsolete(const vector3 &p, const vector3 &c0, const vector3 &c1, const vector3 &c2, const vector3 &c3, number maxSquaredHeightToBaseAreaRatio)
Definition: simplification.h:60