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