ug4
Loading...
Searching...
No Matches
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
41namespace ug{
42
43inline 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
60inline 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;
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
92inline bool QuadDiagonalIsValid(const vector3& c0, const vector3& c1,
93 const vector3& c2, const vector3& c3)
94{
95 vector3 n0, n1;
98 return VecDot(n0, n1) > SMALL;
99}
100
101
102template <class TVrtIter, class TAAPos>
103void 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
166template <class TVrtIter, class TAAPos>
167void 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
332 poly[i1],
333 poly[i2]),
334 g.get_face(fd0));
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 size_t num_vertices() const
Definition grid_base_objects.h:488
virtual Vertex * vertex(size_t index) const
Definition grid_base_objects.h:486
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
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
PointerConstArray< Face * > secure_container
Definition grid.h:146