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