DGtal  1.5.beta
MeshHelpers.ih
1 /**
2  * This program is free software: you can redistribute it and/or modify
3  * it under the terms of the GNU Lesser General Public License as
4  * published by the Free Software Foundation, either version 3 of the
5  * License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program. If not, see <http://www.gnu.org/licenses/>.
14  *
15  **/
16 
17 /**
18  * @file MeshHelpers.ih
19  * @author Jacques-Olivier Lachaud (\c jacques-olivier.lachaud@univ-savoie.fr )
20  * Laboratory of Mathematics (CNRS, UMR 5127), University of Savoie, France
21  *
22  * @date 2017/02/11
23  *
24  * Implementation of inline methods defined in MeshHelpers.h
25  *
26  * This file is part of the DGtal library.
27  */
28 
29 
30 //////////////////////////////////////////////////////////////////////////////
31 #include <cstdlib>
32 #include "DGtal/topology/helpers/Surfaces.h"
33 //////////////////////////////////////////////////////////////////////////////
34 
35 ///////////////////////////////////////////////////////////////////////////////
36 // IMPLEMENTATION of inline methods.
37 ///////////////////////////////////////////////////////////////////////////////
38 
39 ///////////////////////////////////////////////////////////////////////////////
40 // ----------------------- Standard services ------------------------------
41 
42 
43 template <typename Point>
44 inline
45 bool
46 DGtal::MeshHelpers::mesh2TriangulatedSurface
47 ( const Mesh<Point>& mesh,
48  TriangulatedSurface<Point>& trisurf )
49 {
50  trisurf.clear();
51  for ( auto it = mesh.vertexBegin(), itE = mesh.vertexEnd(); it != itE; ++it )
52  trisurf.addVertex( *it );
53  for ( auto it = mesh.faceBegin(), itE = mesh.faceEnd(); it != itE; ++it )
54  {
55  typename Mesh<Point>::MeshFace face = *it;
56  for (unsigned int i = 1; i < face.size() - 1; i++ )
57  {
58  trisurf.addTriangle( face[ 0 ], face[ i ], face[ i+1 ] );
59  }
60  }
61  return trisurf.build();
62 }
63 
64 template <typename Point>
65 inline
66 void
67 DGtal::MeshHelpers::polygonalSurface2TriangulatedSurface
68 ( const PolygonalSurface<Point>& polysurf,
69  TriangulatedSurface<Point>& trisurf,
70  bool centroid )
71 {
72  typedef typename PolygonalSurface<Point>::Index Index;
73  trisurf.clear();
74  for ( Index idx = 0; idx < polysurf.nbVertices(); ++idx )
75  trisurf.addVertex( polysurf.position( idx ) );
76  for ( Index idx = 0; idx < polysurf.nbFaces(); ++idx )
77  {
78  auto vertices = polysurf.verticesAroundFace( idx );
79  const auto nb = vertices.size();
80  if ( nb == 3 || ! centroid ) {
81  for (unsigned int i = 1; i < nb - 1; i++ )
82  trisurf.addTriangle( vertices[ 0 ], vertices[ i ], vertices[ i+1 ] );
83  } else {
84  Point c = polysurf.position( vertices[ 0 ] );
85  for (unsigned int i = 1; i < nb ; i++ )
86  c += polysurf.position( vertices[ i ] );
87  c /= nb;
88  auto idx_c = trisurf.addVertex( c );
89  for (unsigned int i = 0; i < nb; i++ )
90  trisurf.addTriangle( vertices[ i ],
91  vertices[ (i+1) % nb ], idx_c );
92  }
93  }
94  bool ok = trisurf.build();
95  if ( ! ok )
96  trace.error() << "[MeshHelpers::polygonalSurface2TriangulatedSurface]"
97  << " Error building triangulated surface." << std::endl;
98 }
99 
100 template <typename Point>
101 inline
102 bool
103 DGtal::MeshHelpers::mesh2PolygonalSurface
104 ( const Mesh<Point>& mesh,
105  PolygonalSurface<Point>& polysurf )
106 {
107  typedef typename PolygonalSurface<Point>::PolygonalFace PolygonalFace;
108  polysurf.clear();
109  for ( auto it = mesh.vertexBegin(), itE = mesh.vertexEnd(); it != itE; ++it )
110  polysurf.addVertex( *it );
111  for ( auto it = mesh.faceBegin(), itE = mesh.faceEnd(); it != itE; ++it )
112  polysurf.addPolygonalFace( PolygonalFace( it->cbegin(), it->cend() ) );
113  return polysurf.build();
114 }
115 
116 template <typename Point>
117 inline
118 void
119 DGtal::MeshHelpers::triangulatedSurface2Mesh
120 ( const TriangulatedSurface<Point>& trisurf,
121  Mesh<Point>& mesh )
122 {
123  typedef typename TriangulatedSurface<Point>::Index Index;
124  for ( Index idx = 0; idx < trisurf.nbVertices(); ++idx )
125  mesh.addVertex( trisurf.position( idx ) );
126  for ( Index idx = 0; idx < trisurf.nbFaces(); ++idx )
127  {
128  auto vertices = trisurf.verticesAroundFace( idx );
129  mesh.addTriangularFace( vertices[ 0 ], vertices[ 1 ], vertices[ 2 ] );
130  }
131 }
132 
133 template <typename Point>
134 inline
135 void
136 DGtal::MeshHelpers::polygonalSurface2Mesh
137 ( const PolygonalSurface<Point>& polysurf,
138  Mesh<Point>& mesh )
139 {
140  typedef typename Mesh<Point>::MeshFace MeshFace;
141  typedef typename PolygonalSurface<Point>::Index Index;
142  for ( Index idx = 0; idx < polysurf.nbVertices(); ++idx )
143  mesh.addVertex( polysurf.position( idx ) );
144  for ( Index idx = 0; idx < polysurf.nbFaces(); ++idx )
145  {
146  auto vertices = polysurf.verticesAroundFace( idx );
147  MeshFace face( vertices.cbegin(), vertices.cend() );
148  mesh.addFace( face );
149  }
150 }
151 
152 template < typename RealPoint, typename RealVector >
153 inline
154 void
155 DGtal::MeshHelpers::surfaceMesh2Mesh
156 ( const SurfaceMesh< RealPoint, RealVector >& smesh,
157 Mesh< RealPoint >& mesh, const std::vector<Color> &cols )
158 {
159  bool hasColor = cols.size() == smesh.nbFaces();
160  for ( auto&& v : smesh.positions() )
161  mesh.addVertex( v );
162  unsigned int i = 0;
163  for ( auto&& f : smesh.allIncidentVertices() )
164  {
165  typename Mesh< RealPoint >::MeshFace face( f.cbegin(), f.cend() );
166  if (hasColor){
167  mesh.addFace( face, cols[i] );
168  i++;
169  }
170  mesh.addFace( face );
171  }
172 }
173 
174 
175 template < typename DigitalSurfaceContainer,
176  typename CellEmbedder,
177  typename VertexMap >
178 inline
179 void
180 DGtal::MeshHelpers::digitalSurface2DualTriangulatedSurface
181 ( const DigitalSurface<DigitalSurfaceContainer>& dsurf,
182  const CellEmbedder& cembedder,
183  TriangulatedSurface<typename CellEmbedder::Value>& trisurf,
184  VertexMap& vertexmap )
185 {
186  BOOST_CONCEPT_ASSERT(( concepts::CCellEmbedder< CellEmbedder > ));
187  BOOST_CONCEPT_ASSERT(( concepts::CDigitalSurfaceContainer< DigitalSurfaceContainer > ));
188  typedef DigitalSurface< DigitalSurfaceContainer > Surface;
189  typedef typename Surface::KSpace SKSpace;
190  typedef typename Surface::Vertex SVertex;
191  typedef typename Surface::VertexRange SVertexRange;
192  typedef typename CellEmbedder::Value SPoint;
193  typedef typename TriangulatedSurface< SPoint >::Index SIndex;
194  BOOST_STATIC_ASSERT(( SKSpace::dimension == 3 ));
195 
196  trisurf.clear();
197  // Numbers all vertices and add them to the triangulated surface.
198  const SKSpace & K = dsurf.container().space();
199  for ( auto it = dsurf.begin(), it_end = dsurf.end(); it != it_end; ++it )
200  {
201  const SVertex& v = *it;
202  vertexmap[ v ] = trisurf.addVertex( cembedder( K.unsigns( v ) ) );
203  }
204 
205  // Outputs closed faces.
206  auto faces = dsurf.allClosedFaces();
207  for ( auto itf = faces.begin(), itf_end = faces.end(); itf != itf_end; ++itf )
208  {
209  SVertexRange vtcs = dsurf.verticesAroundFace( *itf );
210  if ( vtcs.size() == 3 )
211  trisurf.addTriangle( vertexmap[ vtcs[ 0 ] ],
212  vertexmap[ vtcs[ 1 ] ],
213  vertexmap[ vtcs[ 2 ] ] );
214  else
215  { // We must add a vertex before triangulating.
216  SPoint barycenter;
217  for ( unsigned int i = 0; i < vtcs.size(); ++i )
218  barycenter += cembedder( K.unsigns( vtcs[ i ] ) );
219  barycenter /= vtcs.size();
220  SIndex idx = trisurf.addVertex( barycenter );
221  for ( unsigned int i = 0; i < vtcs.size(); ++i )
222  trisurf.addTriangle( vertexmap[ vtcs[ i ] ],
223  vertexmap[ vtcs[ (i+1) % vtcs.size() ] ],
224  idx );
225  }
226  }
227  trisurf.build();
228 }
229 
230 template < typename DigitalSurfaceContainer,
231  typename CellEmbedder,
232  typename VertexMap >
233 inline
234 void
235 DGtal::MeshHelpers::digitalSurface2DualPolygonalSurface
236 ( const DigitalSurface<DigitalSurfaceContainer>& dsurf,
237  const CellEmbedder& cembedder,
238  PolygonalSurface<typename CellEmbedder::Value>& polysurf,
239  VertexMap& vertexmap )
240 {
241  BOOST_CONCEPT_ASSERT(( concepts::CCellEmbedder< CellEmbedder > ));
242  BOOST_CONCEPT_ASSERT(( concepts::CDigitalSurfaceContainer< DigitalSurfaceContainer > ));
243  typedef DigitalSurface< DigitalSurfaceContainer > Surface;
244  typedef typename Surface::KSpace KSpace;
245  typedef typename Surface::Vertex Vertex;
246  typedef typename Surface::VertexRange VertexRange;
247  typedef typename CellEmbedder::Value Point;
248  typedef typename PolygonalSurface< Point >::PolygonalFace PolygonalFace;
249  BOOST_STATIC_ASSERT(( KSpace::dimension == 3 ));
250 
251  polysurf.clear();
252  // Numbers all vertices and add them to the polygonal surface.
253  const KSpace & K = dsurf.container().space();
254  for ( auto it = dsurf.begin(), it_end = dsurf.end(); it != it_end; ++it )
255  {
256  const Vertex& v = *it;
257  vertexmap[ v ] = polysurf.addVertex( cembedder( K.unsigns( v ) ) );
258  }
259 
260  // Outputs closed faces.
261  auto faces = dsurf.allClosedFaces();
262  for ( auto itf = faces.begin(), itf_end = faces.end(); itf != itf_end; ++itf )
263  {
264  VertexRange vtcs = dsurf.verticesAroundFace( *itf );
265  PolygonalFace face( vtcs.size() );
266  std::transform( vtcs.cbegin(), vtcs.cend(), face.begin(),
267  [ &vertexmap ] ( const Vertex& v ) { return vertexmap[ v ]; } );
268  polysurf.addPolygonalFace( face );
269  }
270  polysurf.build();
271 }
272 
273 template < typename DigitalSurfaceContainer,
274  typename CellEmbedder,
275  typename CellMap >
276 inline
277 bool
278 DGtal::MeshHelpers::digitalSurface2PrimalPolygonalSurface
279 ( const DigitalSurface<DigitalSurfaceContainer>& dsurf,
280  const CellEmbedder& cembedder,
281  PolygonalSurface<typename CellEmbedder::Value>& polysurf,
282  CellMap& cellmap )
283 {
284  BOOST_CONCEPT_ASSERT(( concepts::CCellEmbedder< CellEmbedder > ));
285  BOOST_CONCEPT_ASSERT(( concepts::CDigitalSurfaceContainer< DigitalSurfaceContainer > ));
286  typedef DigitalSurface< DigitalSurfaceContainer > Surface;
287  typedef typename Surface::KSpace KSpace;
288  typedef typename KSpace::Cell Cell;
289  typedef typename CellEmbedder::Value Point;
290  typedef typename PolygonalSurface< Point >::PolygonalFace PolygonalFace;
291  BOOST_STATIC_ASSERT(( KSpace::dimension == 3 ));
292 
293  polysurf.clear();
294  cellmap.clear();
295  // Numbers all vertices and add them to the polygonal surface.
296  const KSpace & K = dsurf.container().space();
297  for ( auto&& s : dsurf ) {
298  auto primal_vertices = Surfaces<KSpace>::getPrimalVertices( K, s, true );
299  for ( auto&& primal_vtx : primal_vertices ) {
300  if ( ! cellmap.count( primal_vtx ) ) {
301  auto p = cembedder( primal_vtx );
302  cellmap[ primal_vtx ] = polysurf.addVertex( p );
303  }
304  }
305  }
306 
307  // Outputs all faces
308  for ( auto&& s : dsurf ) {
309  auto primal_vertices = Surfaces<KSpace>::getPrimalVertices( K, s, true );
310  PolygonalFace face( primal_vertices.size() );
311  std::transform( primal_vertices.cbegin(), primal_vertices.cend(), face.begin(),
312  [ &cellmap ] ( const Cell& v ) { return cellmap[ v ]; } );
313  polysurf.addPolygonalFace( face );
314  }
315  return polysurf.build();
316 }
317 
318 template < typename DigitalSurfaceContainer,
319 typename CellEmbedder,
320 typename CellMap >
321 inline
322 bool
323 DGtal::MeshHelpers::digitalSurface2PrimalSurfaceMesh
324  ( const DigitalSurface<DigitalSurfaceContainer>& dsurf,
325  const CellEmbedder& cembedder,
326  SurfaceMesh<typename CellEmbedder::Value,typename CellEmbedder::Value>& polysurf,
327  CellMap& cellmap )
328 {
329  BOOST_CONCEPT_ASSERT(( concepts::CCellEmbedder< CellEmbedder > ));
330  BOOST_CONCEPT_ASSERT(( concepts::CDigitalSurfaceContainer< DigitalSurfaceContainer > ));
331  typedef DigitalSurface< DigitalSurfaceContainer > Surface;
332  typedef typename Surface::KSpace KSpace;
333  typedef typename KSpace::Cell Cell;
334  typedef typename CellEmbedder::Value Point;
335  typedef typename SurfaceMesh<typename CellEmbedder::Value,typename CellEmbedder::Value>::Vertex Vertex;
336  BOOST_STATIC_ASSERT(( KSpace::dimension == 3 ));
337 
338  cellmap.clear();
339  std::vector<Point> positions;
340  size_t cpt=0;
341  // Numbers all vertices and add them to the polygonal surface.
342  const KSpace & K = dsurf.container().space();
343  for ( auto&& s : dsurf ) {
344  auto primal_vertices = Surfaces<KSpace>::getPrimalVertices( K, s, true );
345  for ( auto&& primal_vtx : primal_vertices ) {
346  if ( ! cellmap.count( primal_vtx ) ) {
347  auto p = cembedder( primal_vtx );
348  positions.emplace_back(p);
349  cellmap[ primal_vtx ] = cpt;
350  ++cpt;
351  }
352  }
353  }
354  std::vector<std::vector<Vertex>> faces;
355  // Outputs all faces
356  for ( auto&& s : dsurf ) {
357  auto primal_vertices = Surfaces<KSpace>::getPrimalVertices( K, s, true );
358  std::vector<Vertex> face( primal_vertices.size() );
359  std::transform( primal_vertices.cbegin(), primal_vertices.cend(), face.begin(),
360  [ &cellmap ] ( const Cell& v ) { return cellmap[ v ]; } );
361  faces.emplace_back( face );
362  }
363  polysurf.init(positions.begin(), positions.end(), faces.begin(), faces.end());
364 
365  return polysurf.isValid();
366 }
367 template <typename Point>
368 bool
369 DGtal::MeshHelpers::exportOBJ
370 ( std::ostream& output,
371  const TriangulatedSurface<Point>& trisurf )
372 {
373  output << "# DGtal::MeshHelpers::exportOBJ(std::ostream&,const TriangulatedSurface<Point>&)" << std::endl;
374  // Outputing vertices
375  for ( auto i : trisurf ) {
376  Point p = trisurf.position( i );
377  output << "v " << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << std::endl;
378  }
379  // Outputing faces
380  auto faces = trisurf.allFaces();
381  for ( auto f : faces ) {
382  output << "f";
383  auto vertices = trisurf.verticesAroundFace( f );
384  for ( auto i : vertices ) output << " " << (i+1);
385  output << std::endl;
386  }
387  return output.good();
388 }
389 
390 template <typename Point>
391 bool
392 DGtal::MeshHelpers::exportOBJ
393 ( std::ostream& output,
394  const PolygonalSurface<Point>& polysurf )
395 {
396  output << "# DGtal::MeshHelpers::exportOBJ(std::ostream&,const PolygonalSurface<Point>&)" << std::endl;
397  // Outputing vertices
398  for ( auto i : polysurf ) {
399  Point p = polysurf.position( i );
400  output << "v " << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << std::endl;
401  }
402  // Outputing faces
403  auto faces = polysurf.allFaces();
404  for ( auto f : faces ) {
405  output << "f";
406  auto vertices = polysurf.verticesAroundFace( f );
407  for ( auto i : vertices ) output << " " << (i+1);
408  output << std::endl;
409  }
410  return output.good();
411 }
412 
413 inline
414 bool
415 DGtal::MeshHelpers::exportMTLNewMaterial
416 ( std::ostream& output_mtl,
417  unsigned long idxMaterial,
418  const Color& ambient_color,
419  const Color& diffuse_color,
420  const Color& specular_color )
421 {
422  output_mtl << "newmtl material_" << idxMaterial << std::endl;
423  output_mtl << "Ka " << ambient_color.red()/255.0
424  << " " << ambient_color.green()/255.0
425  << " " << ambient_color.blue()/255.0 << std::endl;
426  output_mtl << "Kd " << diffuse_color.red()/255.0
427  << " " << diffuse_color.green()/255.0
428  << " " << diffuse_color.blue()/255.0 << std::endl;
429  output_mtl << "Ks " << specular_color.red()/255.0
430  << " " << specular_color.green()/255.0
431  << " " << specular_color.blue()/255.0 << std::endl;
432  if ( diffuse_color.alpha() < 255 )
433  output_mtl << "d " << diffuse_color.alpha()/255.0 << std::endl;
434  return output_mtl.good();
435 }
436 
437 template <typename TTriangulatedOrPolygonalSurface>
438 bool
439 DGtal::MeshHelpers::exportOBJwithFaceNormalAndColor
440 ( std::ostream& output_obj,
441  const std::string& mtl_filename,
442  const TTriangulatedOrPolygonalSurface& polysurf,
443  const std::vector< typename TTriangulatedOrPolygonalSurface::Point >& normals,
444  const std::vector< Color >& diffuse_colors,
445  const Color& ambient_color,
446  const Color& diffuse_color,
447  const Color& specular_color )
448 {
449  output_obj << "# OBJ format" << std::endl;
450  output_obj << "# DGtal::MeshHelpers::exportOBJwithFaceNormalAndColor" << std::endl;
451  output_obj << "o anObject" << std::endl;
452  output_obj << "mtllib " << mtl_filename << std::endl;
453  std::ofstream output_mtl( mtl_filename.c_str() );
454  output_mtl << "# MTL format"<< std::endl;
455  output_mtl << "# generated from MeshWriter from the DGTal library"<< std::endl;
456  // Outputing vertices
457  for ( auto i : polysurf ) {
458  auto p = polysurf.position( i );
459  output_obj << "v " << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << std::endl;
460  }
461  // Outputing faces
462  auto faces = polysurf.allFaces();
463  // Taking care of normals
464  bool has_normals = ( faces.size() == normals.size() );
465  if ( has_normals ) {
466  for ( auto f : faces ) {
467  const auto& p = normals[ f ];
468  output_obj << "vn " << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << std::endl;
469  }
470  }
471  // Taking care of materials
472  bool has_material = ( faces.size() == diffuse_colors.size() );
473  std::map<Color, unsigned int > mapMaterial;
474  unsigned int idxMaterial = 0;
475  if ( has_material ) {
476  for ( auto f : faces ) {
477  Color c = diffuse_colors[ f ];
478  if ( mapMaterial.count( c ) == 0 ) {
479  exportMTLNewMaterial( output_mtl, idxMaterial,
480  ambient_color, c, specular_color );
481  mapMaterial[ c ] = idxMaterial++;
482  }
483  }
484  } else {
485  exportMTLNewMaterial( output_mtl, idxMaterial,
486  ambient_color, diffuse_color, specular_color );
487  }
488  // Taking care of faces
489  for ( auto f : faces ) {
490  output_obj << "usemtl material_"
491  << ( has_material ? mapMaterial[ diffuse_colors[ f ] ] : idxMaterial )
492  << std::endl;
493  output_obj << "f";
494  auto vertices = polysurf.verticesAroundFace( f );
495  if ( has_normals ) {
496  for ( auto i : vertices ) output_obj << " " << (i+1) << "//" << (f+1);
497  } else {
498  for ( auto i : vertices ) output_obj << " " << (i+1);
499  }
500  output_obj << std::endl;
501  }
502  output_mtl.close();
503  return output_obj.good();
504 }
505 
506 
507 // //
508 ///////////////////////////////////////////////////////////////////////////////
509 
510