DGtal 1.3.0
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
42template <typename Point>
43inline
44bool
45DGtal::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
63template <typename Point>
64inline
65void
66DGtal::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
99template <typename Point>
100inline
101bool
102DGtal::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
115template <typename Point>
116inline
117void
118DGtal::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
132template <typename Point>
133inline
134void
135DGtal::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
151template < typename RealPoint, typename RealVector >
152inline
153void
154DGtal::MeshHelpers::surfaceMesh2Mesh
155( const SurfaceMesh< RealPoint, RealVector >& smesh,
156Mesh< 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
174template < typename DigitalSurfaceContainer,
175 typename CellEmbedder,
176 typename VertexMap >
177inline
178void
179DGtal::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
229template < typename DigitalSurfaceContainer,
230 typename CellEmbedder,
231 typename VertexMap >
232inline
233void
234DGtal::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
272template < typename DigitalSurfaceContainer,
273 typename CellEmbedder,
274 typename CellMap >
275inline
276bool
277DGtal::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
317template < typename DigitalSurfaceContainer,
318typename CellEmbedder,
319typename CellMap >
320inline
321bool
322DGtal::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}
366template <typename Point>
367bool
368DGtal::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
389template <typename Point>
390bool
391DGtal::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
412inline
413bool
414DGtal::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
436template <typename TTriangulatedOrPolygonalSurface>
437bool
438DGtal::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