Line data Source code
1 : /*
2 : * Copyright (c) 2009-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 : #include "extrude.h"
34 : #include "common/util/hash.h"
35 : #include "lib_grid/algorithms/orientation_util.h"
36 : #include "lib_grid/algorithms/geom_obj_util/face_util.h"
37 : #include "lib_grid/algorithms/geom_obj_util/volume_util.h"
38 :
39 : using namespace std;
40 :
41 : namespace ug
42 : {
43 :
44 0 : static bool ExtrusionHelper_CheckOrientation(Volume* v, Grid::VertexAttachmentAccessor<Attachment<vector1> >& aaPos)
45 : {
46 0 : UG_THROW("Can't check orientation of a degenerated volume element!");
47 : return false;
48 : }
49 :
50 0 : static bool ExtrusionHelper_CheckOrientation(Volume* v, Grid::VertexAttachmentAccessor<Attachment<vector2> >& aaPos)
51 : {
52 0 : UG_THROW("Can't check orientation of a degenerated volume element!");
53 : return false;
54 : }
55 :
56 : static bool ExtrusionHelper_CheckOrientation(Volume* v, Grid::VertexAttachmentAccessor<Attachment<vector3> >& aaPos)
57 : {
58 0 : return CheckOrientation(v, aaPos);
59 : }
60 :
61 : ////////////////////////////////////////////////////////////////////////
62 : // Extrude
63 : template <class vector_t>
64 0 : void Extrude(Grid& grid,
65 : std::vector<Vertex*>* pvVerticesInOut,
66 : std::vector<Edge*>* pvEdgesInOut,
67 : std::vector<Face*>* pvFacesInOut,
68 : const vector_t& direction,
69 : uint extrusionOptions,
70 : Attachment<vector_t>& aPos,
71 : std::vector<Volume*>* pvVolsOut)
72 : {
73 : UG_DLOG(LIB_GRID, 0, "extruding...\n");
74 :
75 0 : if(!grid.has_vertex_attachment(aPos))
76 0 : grid.attach_to_vertices(aPos);
77 :
78 : Grid::VertexAttachmentAccessor<Attachment<vector_t> > aaPos(grid, aPos);
79 :
80 0 : Extrude(grid, pvVerticesInOut, pvEdgesInOut, pvFacesInOut,
81 : direction, aaPos, extrusionOptions, pvVolsOut);
82 0 : }
83 :
84 : template <class TAAPos>
85 0 : void Extrude(Grid& grid,
86 : std::vector<Vertex*>* pvVerticesInOut,
87 : std::vector<Edge*>* pvEdgesInOut,
88 : std::vector<Face*>* pvFacesInOut,
89 : const typename TAAPos::ValueType& direction,
90 : TAAPos aaPos,
91 : uint extrusionOptions,
92 : std::vector<Volume*>* pvVolsOut)
93 : {
94 0 : if(pvVolsOut)
95 : pvVolsOut->clear();
96 :
97 : //TODO: find a better guess.
98 : // first we'll determine the rough size of the hash.
99 : // we'll simply add all vertices, edges and faces.
100 : uint hashSize = 10;
101 : uint numNewFaces = 0;// the number of faces that are generated directly in this method (autogeneration during volume-extrude is not regarded).
102 0 : if(pvVerticesInOut)
103 0 : hashSize += pvVerticesInOut->size();
104 0 : if(pvEdgesInOut){
105 0 : hashSize += pvEdgesInOut->size();
106 : numNewFaces += pvEdgesInOut->size();
107 : }
108 0 : if(pvFacesInOut){
109 0 : hashSize += pvFacesInOut->size();
110 0 : numNewFaces += pvFacesInOut->size();
111 : }
112 :
113 0 : if(hashSize == 0)
114 0 : return;
115 :
116 : // the hash:
117 : typedef Hash<uint, Vertex*> VertexHash;
118 0 : VertexHash vrtHash(hashSize);
119 : vrtHash.reserve(hashSize);
120 :
121 : // we'll record created faces in this vector, since we have to fix the
122 : // orientation later on (only if pvEdgesInOut has been specified).
123 : vector<Face*> vNewFaces;
124 : bool bRecordNewFaces = false;
125 0 : if((pvEdgesInOut != NULL) && (extrusionOptions & EO_CREATE_FACES))
126 : {
127 0 : if(!pvEdgesInOut->empty()){
128 : bRecordNewFaces = true;
129 0 : vNewFaces.resize(numNewFaces);
130 : }
131 : }
132 :
133 : size_t newFaceCount = 0;
134 : // if faces are extruded we want them in the first section of vNewFaces (they shall define the orientation).
135 : // Thats why we start in the second section in this case.
136 0 : if(pvFacesInOut)
137 : newFaceCount = pvFacesInOut->size();
138 :
139 : // first we'll extrude all vertices. For each a new edge will be created.
140 0 : if(pvVerticesInOut)
141 : {
142 : UG_DLOG(LIB_GRID, 1, " extruding vertices: " << pvVerticesInOut->size() << endl);
143 : vector<Vertex*>& vVertices = *pvVerticesInOut;
144 0 : for(uint i = 0; i < vVertices.size(); ++i)
145 : {
146 0 : Vertex* vOld = vVertices[i];
147 : // create a new vertex and store it in the hash.
148 : // use the attachment_data_index of the old one as key.
149 : // WARNING: this is only secure as long as nobody calls defragment while the hash is active!
150 0 : Vertex* v = *grid.create<RegularVertex>(vOld);
151 0 : vrtHash.insert(grid.get_attachment_data_index(vOld), v);
152 :
153 : // calculate new position
154 : aaPos[v] = aaPos[vOld];
155 : VecAdd(aaPos[v], aaPos[v], direction);
156 :
157 : // create an edge between both vertices.
158 0 : grid.create<RegularEdge>(EdgeDescriptor(vOld, v), vOld);
159 :
160 : // overwrite the vertex in pvVerticesInOut
161 0 : vVertices[i] = v;
162 : }
163 : UG_DLOG(LIB_GRID, 1, " extruding vertices done.\n");
164 : }
165 :
166 : // now extrude edges.
167 0 : if(pvEdgesInOut)
168 : {
169 : UG_DLOG(LIB_GRID, 1, " extruding edges: " << pvEdgesInOut->size() << endl);
170 : vector<Edge*>& vEdges = *pvEdgesInOut;
171 0 : for(uint i = 0; i < vEdges.size(); ++i)
172 : {
173 0 : Edge* e = vEdges[i];
174 :
175 : // check for both boundary points whether the new vertices have already been created.
176 : // if not then create them here and store them.
177 : Vertex* v[2];
178 :
179 0 : for(uint j = 0; j < 2; ++j)
180 : {
181 0 : if(!vrtHash.get_entry(v[j], grid.get_attachment_data_index(e->vertex(j))))
182 : {
183 0 : v[j] = *grid.create<RegularVertex>(e->vertex(j));
184 0 : vrtHash.insert(grid.get_attachment_data_index(e->vertex(j)), v[j]);
185 : // calculate new position
186 0 : aaPos[v[j]] = aaPos[e->vertex(j)];
187 : VecAdd(aaPos[v[j]], aaPos[v[j]], direction);
188 : }
189 : }
190 :
191 : // both new vertices exist now.
192 : // create the new edge
193 0 : RegularEdge* eNew = *grid.create<RegularEdge>(EdgeDescriptor(v[0], v[1]), e);
194 :
195 : // overwrite the edge in pvEdgesInOut
196 0 : vEdges[i] = eNew;
197 :
198 : // finally create the face.
199 0 : if(extrusionOptions & EO_CREATE_FACES)
200 : {
201 : // create a quadrilateral from the four points.
202 : // the orientation will be done later on.
203 0 : Face* f = *grid.create<Quadrilateral>(QuadrilateralDescriptor(v[0], v[1], e->vertex(1), e->vertex(0)), e);
204 0 : vNewFaces[newFaceCount++] = f;
205 : }
206 : }
207 : UG_DLOG(LIB_GRID, 1, " extrunding edges done.\n");
208 : }
209 :
210 : // now extrude faces.
211 0 : if(pvFacesInOut)
212 : {
213 : UG_DLOG(LIB_GRID, 1, " extruding faces: " << pvFacesInOut->size() << endl);
214 : // fill the first section of vNewFaces
215 : newFaceCount = 0;
216 :
217 : vector<Face*>& vFaces = *pvFacesInOut;
218 0 : for(uint i = 0; i < vFaces.size(); ++i)
219 : {
220 0 : Face* f = vFaces[i];
221 : assert(f->num_vertices() < 5 && "can't deal with faces that have more than 4 vertices!");
222 :
223 : // check for all points whether the new vertices have already been created.
224 : // if not then create them here and store them.
225 : Vertex* v[4];
226 :
227 0 : uint numVrts = f->num_vertices();
228 :
229 0 : for(uint j = 0; j < numVrts; ++j)
230 : {
231 0 : uint oldVrtInd = grid.get_attachment_data_index(f->vertex(j));
232 0 : if(!vrtHash.get_entry(v[j], oldVrtInd)){
233 0 : v[j] = *grid.create<RegularVertex>(f->vertex(j));
234 0 : vrtHash.insert(oldVrtInd, v[j]);
235 : // calculate new position
236 0 : aaPos[v[j]] = aaPos[f->vertex(j)];
237 : VecAdd(aaPos[v[j]], aaPos[v[j]], direction);
238 : }
239 : }
240 :
241 : // all new vertices exist now.
242 : // create the new face
243 : Face* fNew = NULL;
244 0 : Volume* vol = NULL;
245 0 : if(numVrts == 3)
246 : {
247 : UG_DLOG(LIB_GRID, 2, " " << i << ": creating tri...\n");
248 0 : fNew = *grid.create<Triangle>(TriangleDescriptor(v[0], v[1], v[2]), f);
249 :
250 : // create the volume
251 0 : if(extrusionOptions & EO_CREATE_VOLUMES)
252 : {
253 0 : Prism prism(f->vertex(0), f->vertex(1), f->vertex(2),
254 0 : fNew->vertex(0), fNew->vertex(1), fNew->vertex(2));
255 :
256 : // check the orientation and create the prism
257 0 : if (!ExtrusionHelper_CheckOrientation(&prism, aaPos)){
258 0 : VolumeDescriptor vd;
259 0 : prism.get_flipped_orientation(vd);
260 0 : vol = *grid.create_by_cloning(&prism, vd, f);
261 : }
262 : else
263 0 : vol = *grid.create_by_cloning(&prism, prism, f);
264 :
265 : }
266 : }
267 0 : else if(numVrts == 4)
268 : {
269 : UG_DLOG(LIB_GRID, 2, " " << i << ": creating quad...\n");
270 0 : fNew = *grid.create<Quadrilateral>(QuadrilateralDescriptor(v[0], v[1], v[2], v[3]), f);
271 :
272 : // create the volume
273 0 : if(extrusionOptions & EO_CREATE_VOLUMES)
274 : {
275 0 : Hexahedron hex(f->vertex(0), f->vertex(1), f->vertex(2), f->vertex(3),
276 0 : fNew->vertex(0), fNew->vertex(1), fNew->vertex(2), fNew->vertex(3));
277 :
278 : // check the orientation and create the hexahedron
279 0 : if(!ExtrusionHelper_CheckOrientation(&hex, aaPos)){
280 0 : VolumeDescriptor vd;
281 0 : hex.get_flipped_orientation(vd);
282 0 : vol = *grid.create_by_cloning(&hex, vd, f);
283 : }
284 : else
285 0 : vol = *grid.create_by_cloning(&hex, hex, f);
286 : }
287 : }
288 : else{
289 : assert(!"face has bad number of vertices!");
290 : }
291 :
292 0 : if(fNew){
293 : // overwrite the face in pvFacesInOut
294 0 : vFaces[i] = fNew;
295 : // store the face in vNewFaces - but only if we have
296 : // to re-orientate them later on.
297 0 : if(bRecordNewFaces){
298 : UG_DLOG(LIB_GRID, 2, " storing face for reordering...\n");
299 0 : vNewFaces[newFaceCount++] = fNew;
300 : }
301 : }
302 :
303 0 : if(pvVolsOut && vol)
304 0 : pvVolsOut->push_back(vol);
305 : }
306 : UG_DLOG(LIB_GRID, 1, " extruding faces done.\n");
307 : }
308 :
309 : // if faces were extruded from edges, we have to fix the orientation now
310 : // if(bRecordNewFaces){
311 : // UG_DLOG(LIB_GRID, 1, " reordering faces...\n");
312 : // FixFaceOrientation(grid, vNewFaces.begin(), vNewFaces.end());
313 : // UG_DLOG(LIB_GRID, 1, " reordering faces done.\n");
314 : // }
315 0 : }
316 :
317 : template void Extrude<vector1>(Grid&,
318 : std::vector<Vertex*>*,
319 : std::vector<Edge*>*,
320 : std::vector<Face*>*,
321 : const vector1&,
322 : uint,
323 : Attachment<vector1>&,
324 : std::vector<Volume*>*);
325 :
326 : template void Extrude<vector2>(Grid&,
327 : std::vector<Vertex*>*,
328 : std::vector<Edge*>*,
329 : std::vector<Face*>*,
330 : const vector2&,
331 : uint,
332 : Attachment<vector2>&,
333 : std::vector<Volume*>*);
334 :
335 : template void Extrude<vector3>(Grid&,
336 : std::vector<Vertex*>*,
337 : std::vector<Edge*>*,
338 : std::vector<Face*>*,
339 : const vector3&,
340 : uint,
341 : Attachment<vector3>&,
342 : std::vector<Volume*>*);
343 :
344 : template void Extrude<Grid::VertexAttachmentAccessor<Attachment<vector1> > >(
345 : Grid&,
346 : std::vector<Vertex*>*,
347 : std::vector<Edge*>*,
348 : std::vector<Face*>*,
349 : const vector1&,
350 : Grid::VertexAttachmentAccessor<Attachment<vector1> >,
351 : uint,
352 : std::vector<Volume*>*);
353 :
354 : template void Extrude<Grid::VertexAttachmentAccessor<Attachment<vector2> > >(
355 : Grid&,
356 : std::vector<Vertex*>*,
357 : std::vector<Edge*>*,
358 : std::vector<Face*>*,
359 : const vector2&,
360 : Grid::VertexAttachmentAccessor<Attachment<vector2> >,
361 : uint,
362 : std::vector<Volume*>*);
363 :
364 : template void Extrude<Grid::VertexAttachmentAccessor<Attachment<vector3> > >(
365 : Grid&,
366 : std::vector<Vertex*>*,
367 : std::vector<Edge*>*,
368 : std::vector<Face*>*,
369 : const vector3&,
370 : Grid::VertexAttachmentAccessor<Attachment<vector3> >,
371 : uint,
372 : std::vector<Volume*>*);
373 : }// end of namespace
|