DGtal 1.4.2
Loading...
Searching...
No Matches
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
43template <typename Point>
44inline
45bool
46DGtal::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
64template <typename Point>
65inline
66void
67DGtal::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
100template <typename Point>
101inline
102bool
103DGtal::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
116template <typename Point>
117inline
118void
119DGtal::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
133template <typename Point>
134inline
135void
136DGtal::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
152template < typename RealPoint, typename RealVector >
153inline
154void
155DGtal::MeshHelpers::surfaceMesh2Mesh
156( const SurfaceMesh< RealPoint, RealVector >& smesh,
157Mesh< 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
175template < typename DigitalSurfaceContainer,
176 typename CellEmbedder,
177 typename VertexMap >
178inline
179void
180DGtal::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
230template < typename DigitalSurfaceContainer,
231 typename CellEmbedder,
232 typename VertexMap >
233inline
234void
235DGtal::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
273template < typename DigitalSurfaceContainer,
274 typename CellEmbedder,
275 typename CellMap >
276inline
277bool
278DGtal::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
318template < typename DigitalSurfaceContainer,
319typename CellEmbedder,
320typename CellMap >
321inline
322bool
323DGtal::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}
367template <typename Point>
368bool
369DGtal::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
390template <typename Point>
391bool
392DGtal::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
413inline
414bool
415DGtal::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
437template <typename TTriangulatedOrPolygonalSurface>
438bool
439DGtal::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