1 /** @file gsMesh.hpp
2
3 @brief Provides implementation of the Mesh class.
4
5 This file is part of the G+Smo library.
6
7 This Source Code Form is subject to the terms of the Mozilla Public
8 License, v. 2.0. If a copy of the MPL was not distributed with this
9 file, You can obtain one at http://mozilla.org/MPL/2.0/.
10
11 Author(s): A. Mantzaflaris, D. Mayer
12 */
13
14 #pragma once
15
16 #include <gsCore/gsBasis.h>
17 #include <gsUtils/gsCombinatorics.h>
18 #include <gsCore/gsDomainIterator.h>
19
20 namespace gismo
21 {
22
23 template<class T>
~gsMesh()24 gsMesh<T>::~gsMesh()
25 {
26 //gsInfo << "delete gsMesh\n";
27 freeAll(m_vertex);
28 freeAll(m_face);
29 }
30
31 template<class T>
gsMesh(const gsBasis<T> & basis,int midPts)32 gsMesh<T>::gsMesh(const gsBasis<T> & basis, int midPts)
33 : MeshElement()
34 {
35 const unsigned d = basis.dim();
36
37 typedef typename gsMesh<T>::VertexHandle vtx;
38 typename gsBasis<T>::domainIter domIter = basis.makeDomainIterator();
39
40 // variables for iterating over a cube (element is a cube)
41 const gsVector<unsigned> zeros = gsVector<unsigned>::Zero(d);
42 const gsVector<unsigned> ones = gsVector<unsigned>::Ones(d);
43 gsVector<unsigned> cur;
44
45 // maps integer representation of a vertex into pointer to the
46 // vertex coordinates
47 std::vector<vtx> map(1ULL<<d);
48
49 // neighbour[i] are integer representations of certain neighbours of
50 // vertex i (i counts in lexicographics order over all vertices)
51 std::vector<std::vector<unsigned> > neighbour(1ULL<<d,
52 std::vector<unsigned>() );
53
54 cur.setZero(d);
55 int counter = 0;
56 do
57 {
58 // set neighbour
59 for (unsigned dim = 0; dim < d; dim++)
60 {
61 if (cur(dim) == 0)
62 {
63 const unsigned tmp = counter | (1<< dim) ;
64 neighbour[counter].push_back(tmp);
65 }
66 }
67 counter++;
68
69 } while (nextCubePoint<gsVector<unsigned> >(cur, zeros, ones));
70
71 gsVector<T> vv(d);
72
73 for (; domIter->good(); domIter->next())
74 {
75 const gsVector<T>& low = domIter->lowerCorner();
76 const gsVector<T>& upp = domIter->upperCorner();
77 const T vol = domIter->volume();
78
79 vv.setZero();
80 cur.setZero();
81 counter = 0;
82
83 // Add points to the mesh.
84 do
85 {
86 // Get the appropriate coordinate of a point.
87 for (unsigned dim = 0; dim < d; dim++)
88 {
89 vv(dim) = ( cur(dim) ? upp(dim) : low(dim) );
90 }
91
92 vtx v = addVertex(vv);
93 v->data = vol;
94 map[counter++] = v;
95
96 } while (nextCubePoint<gsVector<unsigned> >(cur, zeros, ones));
97
98
99 // Add edges to the mesh (connect points).
100 for (size_t index = 0; index != neighbour.size(); index++)
101 {
102 const std::vector<unsigned> & v = neighbour[index];
103
104 for (size_t ngh = 0; ngh != v.size(); ngh++)
105 {
106 // Add more vertices for better physical resolution.
107 addLine( map[index], map[v[ngh]], midPts );
108 //addEdge( map[index], map[v[ngh]] );
109 }
110 }
111
112 // idea: instead of edges add the faces to the mesh
113 // addFace( mesh.vertex.back(),
114 // *(vertex.end()-3),
115 // *(vertex.end()-4),
116 // *(vertex.end()-2)
117 // );
118 }
119 }
120
121
122 template<class T>
addVertex(scalar_t const & x,scalar_t const & y,scalar_t const & z)123 typename gsMesh<T>::VertexHandle gsMesh<T>::addVertex(scalar_t const& x, scalar_t const& y, scalar_t const& z)
124 {
125 VertexHandle v = this->makeVertex(x,y,z);
126 v->setId(m_vertex.size());
127 m_vertex.push_back(v );
128 return v;
129 }
130
131
132 template<class T>
addVertex(gsVector<T> const & u)133 typename gsMesh<T>::VertexHandle gsMesh<T>::addVertex(gsVector<T> const & u)
134 {
135 VertexHandle v = this->makeVertex(u);
136 v->setId(m_vertex.size());
137 m_vertex.push_back(v);
138 return v;
139 }
140
141
142 template<class T>
addEdge(VertexHandle v0,VertexHandle v1)143 void gsMesh<T>::addEdge(VertexHandle v0, VertexHandle v1)
144 {
145 m_edge.push_back( Edge(v0,v1) );
146 }
147
148
149 template<class T>
addEdge(int const vind0,int const vind1)150 void gsMesh<T>::addEdge(int const vind0, int const vind1)
151 {
152 GISMO_ASSERT( (size_t)vind0 < numVertices(), "Invalid vertex index "
153 << vind0 << "(numVertices="<< numVertices() <<").");
154 GISMO_ASSERT( (size_t)vind1 < numVertices(), "Invalid vertex index "
155 << vind1 << "(numVertices="<< numVertices() <<").");
156
157 addEdge(m_vertex[vind0], m_vertex[vind1]);
158 }
159
160
161 template<class T>
addEdge(gsVector<T> const & u0,gsVector<T> const & u1)162 void gsMesh<T>::addEdge(gsVector<T> const & u0,
163 gsVector<T> const & u1 )
164 {
165 addEdge( addVertex(u0), addVertex(u1) );
166 }
167
168
169 template<class T>
addFace(std::vector<VertexHandle> const & vert)170 typename gsMesh<T>::FaceHandle gsMesh<T>::addFace(std::vector<VertexHandle> const & vert)
171 {
172 FaceHandle f = this->makeFace( vert );
173 f->setId(m_face.size());
174 m_face.push_back(f);
175 return f;
176 }
177
178
179 template<class T>
addFace(VertexHandle const & v0,VertexHandle const & v1,VertexHandle const & v2)180 typename gsMesh<T>::FaceHandle gsMesh<T>::addFace(VertexHandle const & v0, VertexHandle const & v1,
181 VertexHandle const & v2)
182 {
183 FaceHandle f = this->makeFace( v0, v1, v2 );
184 f->setId(m_face.size());
185 m_face.push_back(f);
186 return f;
187 }
188
189
190 template<class T>
addFace(VertexHandle const & v0,VertexHandle const & v1,VertexHandle const & v2,VertexHandle const & v3)191 typename gsMesh<T>::FaceHandle gsMesh<T>::addFace(VertexHandle const & v0, VertexHandle const & v1,
192 VertexHandle const & v2, VertexHandle const & v3)
193 {
194 FaceHandle f = this->makeFace( v0,v1,v2,v3 );
195 f->setId(m_face.size());
196 m_face.push_back(f);
197 return f;
198 }
199
200
201 template<class T>
addFace(std::vector<int> const & vert)202 typename gsMesh<T>::FaceHandle gsMesh<T>::addFace(std::vector<int> const & vert)
203 {
204 std::vector<VertexHandle> pvert; //(vert.size() );
205 pvert.reserve(vert.size());
206 for ( std::vector<int>::const_iterator it = vert.begin();
207 it!= vert.end(); ++it )
208 pvert.push_back( m_vertex[*it] );
209
210 FaceHandle f = this->makeFace( pvert );
211 f->setId(m_face.size());
212 m_face.push_back(f);
213 return f;
214 }
215
216
217 template<class T>
addFace(const int v0,const int v1,const int v2)218 typename gsMesh<T>::FaceHandle gsMesh<T>::addFace(const int v0, const int v1, const int v2)
219 {
220 FaceHandle f = this->makeFace( m_vertex[v0],m_vertex[v1],m_vertex[v2] );
221 f->setId(m_face.size());
222 m_face.push_back(f);
223 return f;
224 }
225
226
227 template<class T>
addFace(const int v0,const int v1,const int v2,const int v3)228 typename gsMesh<T>::FaceHandle gsMesh<T>::addFace(const int v0, const int v1, const int v2, const int v3)
229 {
230 FaceHandle f = this->makeFace( m_vertex[v0],m_vertex[v1],m_vertex[v2],m_vertex[v3] );
231 f->setId(m_face.size());
232 m_face.push_back(f);
233 return f;
234 }
235
236
237 template<class T>
print(std::ostream & os) const238 std::ostream &gsMesh<T>::print(std::ostream &os) const
239 {
240 os<<"gsMesh with "<<numVertices()<<" vertices, "<<numEdges()<<
241 " edges and "<<numFaces()<<" faces.\n";
242 // for ( typename std::vector<FaceHandle>::const_iterator
243 // it = face.begin(); it!= face.end(); ++it)
244 // os<<" "<< **it ;
245 return os;
246 }
247
248
249 template <class T>
cleanMesh()250 gsMesh<T>& gsMesh<T>::cleanMesh()
251 {
252 gsDebug << "Cleaning the gsMesh\n";
253
254 // This function looks for duplicated vertex coordinates. For each
255 // vector, it chooses a unique vertex having that vector, then makes
256 // sure that the source and target of every edge is one of the chosen
257 // vertices. The old way was more efficient but did not work for
258 // non-manifold solids.
259
260 /*gsDebug << "std::vector<> vertex before cleanMesh\n";
261 for (size_t i = 0; i < m_vertex.size(); ++i)
262 {
263 gsDebug << i << ": " << m_vertex[i] << " id: " << m_vertex[i]->getId() << " " << *m_vertex[i];
264 }
265 gsDebug << "----------------------------------------\n";*/
266
267 // build up the unique map
268 std::vector<size_t> uniquemap;
269 uniquemap.reserve(m_vertex.size());
270 for(size_t i = 0; i < m_vertex.size(); i++)
271 {
272 size_t buddy = i;
273 for(size_t j = 0; j < i; j++)
274 {
275 if(*(m_vertex[i]) == *(m_vertex[j])) // overload compares coords
276 {
277 buddy = j;
278 break;
279 }
280 }
281 uniquemap.push_back(buddy);
282 }
283
284 for(size_t i = 0; i < m_face.size(); i++)
285 {
286 for (size_t j = 0; j < 3; j++)
287 {
288 m_face[i]->vertices[j] = m_vertex[uniquemap[m_face[i]->vertices[j]->getId()]];
289 }
290 }
291
292 for(size_t i = 0; i < m_edge.size(); i++)
293 {
294 m_edge[i].source = m_vertex[uniquemap[m_edge[i].source->getId()]];
295 m_edge[i].target = m_vertex[uniquemap[m_edge[i].target->getId()]];
296 }
297
298 std::set<size_t> uniqueset(uniquemap.begin(), uniquemap.end()); // O(n*log(n))
299 std::vector<VertexHandle> uvertex;
300 uvertex.reserve(uniqueset.size());
301 for(size_t i = 0; i < uniquemap.size(); i++) { // O(n)
302 if(uniqueset.find(i) != uniqueset.end()) // O(log(m)), n >> m
303 {
304 // re-number vertices id by new sequence - should we not do?
305 m_vertex[i]->setId(uvertex.size());
306 uvertex.push_back(m_vertex[i]);
307 }
308 else
309 {
310 delete m_vertex[i];
311 m_vertex[i] = nullptr;
312 }
313 } // O(n*log(n)+O(n)*O(log(m)) ==> O(n*log(n))
314 m_vertex.swap(uvertex);
315
316 return *this;
317 }
318
319 template<class T>
reserve(size_t vertex,size_t face,size_t edge)320 gsMesh<T>& gsMesh<T>::reserve(size_t vertex, size_t face, size_t edge)
321 {
322 m_vertex.reserve(vertex);
323 m_face.reserve(face);
324 m_edge.reserve(edge);
325 return *this;
326 }
327
328 template <class T>
addLine(gsMatrix<T> const & points)329 void gsMesh<T>::addLine(gsMatrix<T> const & points)
330 {
331 const index_t cols = points.cols();
332 if ( cols < 2 ) return;
333
334 const bool zzero = ( points.rows()==2 );
335
336 VertexHandle v1,
337 v0 = addVertex( points(0,0), points(1,0), zzero ? 0 : points(2,0) );
338
339 for ( index_t i = 1; i<cols; ++i)
340 {
341 v1 = addVertex( points(0, i), points(1, i), zzero ? 0 : points(2,0) );
342 addEdge(v0 , v1);
343 v0 = v1;
344 }
345 }
346
347 template <class T>
addLine(VertexHandle v0,VertexHandle v1,int midPts)348 void gsMesh<T>::addLine(VertexHandle v0, VertexHandle v1, int midPts)
349 {
350 const gsVector3d<T> & start = *dynamic_cast<gsVector3d<T>* >(v0);
351 const T h = (*v1 - start).norm() / (midPts + 1);
352 const gsVector3d<T> step = (*v1 - start).normalized();
353
354 VertexHandle last = v0;
355 VertexHandle next;
356 for ( int i = 0; i<midPts; ++i )
357 {
358 next = addVertex(start + i*h*step);
359 addEdge(last, next);
360 last = next;
361 }
362 addEdge(last, v1);
363 }
364
365
366 //template <class T>
367 //gsSolid<T> *
368 //gsMesh<T>::meshToSolid(int kvOuterPoints, int kvAdditionalInnerPoints, bool addInner,
369 // bool plot,std::string name,int meshPoints, T wE, T wI,int closeBoundary,
370 // std::vector<std::vector<VertexHandle> > iPoints,
371 // std::vector<std::vector<VertexHandle> > oPoints,
372 // std::vector< std::vector<std::vector<VertexHandle> > > innerBdrys,
373 // std::vector< std::vector<Vertex> > innerBdrysMassP,
374 // std::vector<std::vector<bool> > oPointsConvexFlag)
375 // {
376 // gsSolid<T> * s1 = new gsSolid<T>();
377 // this->toSolid(*s1,iPoints,oPoints,innerBdrys,innerBdrysMassP,oPointsConvexFlag,kvOuterPoints,kvAdditionalInnerPoints,plot,name,meshPoints,addInner,wE,wI,closeBoundary);
378 // return s1;
379 // }
380
381 };// namespace gismo
382