Merge branch 'Polyhedron_demo-mesh_3_write_c3t3_boundary-GF'

Adding functions to export the boundary of a 3D mesh embedded in a C3T3
  See Features/Small_Features/Mesh_3_output_to_off

Successfully tested in CGAL-4.6-Ic-26
Approved by the interim release manager
This commit is contained in:
Sébastien Loriot 2014-09-29 08:31:07 +02:00
commit d79eeddfb9
8 changed files with 349 additions and 8 deletions

View File

@ -80,6 +80,21 @@ in medit format.
*/
void output_to_medit(std::ofstream& os);
/**
* Outputs the outer boundary of the entire domain with facets oriented outward.
*/
std::ostream& output_boundary_to_off(std::ostream& out) const;
/**
* Outputs the outer boundary of the selected subdomain with facets oriented outward.
*/
std::ostream& output_boundary_to_off(std::ostream& out, Subdomain_index subdomain) const;
/**
* Outputs the surface facets with a consistent orientation at the interface of two subdomains.
*/
std::ostream& output_facets_in_complex_to_off(std::ostream& out) const;
/// @}
}; /* end Mesh_complex_3_in_triangulation_3 */

View File

@ -38,6 +38,7 @@
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/mpl/if.hpp>
#include <CGAL/internal/Mesh_3/Boundary_of_subdomain_of_complex_3_in_triangulation_3_to_off.h>
namespace CGAL {
@ -70,6 +71,7 @@ public:
typedef CurveSegmentIndex Curve_segment_index;
typedef typename Base::Triangulation Triangulation;
typedef typename Base::Subdomain_index Subdomain_index;
using Base::surface_patch_index;
@ -332,6 +334,33 @@ public:
return Corner_index();
}
/**
* Outputs the outer boundary of the entire domain with facets oriented outward.
*/
std::ostream& output_boundary_to_off(std::ostream& out) const
{
internal::output_boundary_of_c3t3_to_off(*this, 0, out, false);
return out;
}
/**
* Outputs the outer boundary of the selected subdomain with facets oriented outward.
*/
std::ostream& output_boundary_to_off(std::ostream& out, Subdomain_index subdomain) const
{
output_boundary_of_c3t3_to_off(*this, subdomain, out);
return out;
}
/**
* Outputs the surface facets with a consistent orientation at the interface of two subdomains.
*/
std::ostream& output_facets_in_complex_to_off(std::ostream& out) const
{
internal::output_facets_in_complex_to_off(*this, out);
return out;
}
/**
* Fills \c out with incident edges (1-dimensional features of \c v.
* OutputIterator value type is std::pair<Vertex_handle,Curve_segment_index>

View File

@ -0,0 +1,136 @@
// Copyright (c) 2008-2014 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL: svn+ssh://sloriot@scm.gforge.inria.fr/svn/cgal/branches/next/Mesh_3/include/CGAL/IO/Complex_3_in_triangulation_3_to_vtk.h $
// $Id: Complex_3_in_triangulation_3_to_vtk.h 67117 2012-01-13 18:14:48Z lrineau $
//
//
// Author(s) : Laurent Rineau and Sebastien Loriot
#ifndef CGAL_INTERNAL_MESH_3_BOUNDARY_OF_SUDDOMAIN_OF_COMPLEX_3_IN_TRIANGULATION_3_TO_OFF_H
#define CGAL_INTERNAL_MESH_3_BOUNDARY_OF_SUDDOMAIN_OF_COMPLEX_3_IN_TRIANGULATION_3_TO_OFF_H
#include <map>
#include <sstream>
#include <CGAL/array.h>
namespace CGAL {
namespace internal{
namespace mesh_3_export{
template <class Vertex_handle>
std::size_t get_vertex_index(Vertex_handle v,std::map<Vertex_handle, std::size_t>& V,std::size_t& inum,std::stringstream& vertex_buffer){
std::pair<typename std::map<Vertex_handle, std::size_t>::iterator,bool> res=
V.insert(std::make_pair(v,inum));
if (res.second){
++inum;
vertex_buffer << res.first->first->point().point() <<"\n"; //point is weighted!
}
return res.first->second;
}
} // end of namespace mesh_3_export
template <typename C3T3>
std::ostream&
output_boundary_of_c3t3_to_off(const C3T3& c3t3,
typename C3T3::Subdomain_index sd_index,
std::ostream& output,
bool normals_point_outside_of_the_subdomain=true)
{
typedef typename C3T3::Triangulation Triangulation;
typedef typename Triangulation::Vertex_handle Vertex_handle;
std::map<Vertex_handle, std::size_t> V;
std::size_t inum = 0;
std::size_t nfacets = 0;
cpp0x::array<std::size_t,3> indices={{0,0,0}};
std::stringstream facet_buffer,vertex_buffer;
for(typename C3T3::Facets_in_complex_iterator
fit = c3t3.facets_in_complex_begin(),
end = c3t3.facets_in_complex_end();
fit != end; ++fit)
{
typename C3T3::Subdomain_index cell_sd=c3t3.subdomain_index(fit->first);
typename C3T3::Subdomain_index opp_sd=c3t3.subdomain_index(fit->first->neighbor(fit->second));
if (cell_sd!=sd_index && opp_sd!=sd_index) continue;
++nfacets;
int j=-1;
for (int i = 0; i < 4; ++i)
if (i != fit->second)
indices[++j]=mesh_3_export::get_vertex_index((*fit).first->vertex(i), V, inum,vertex_buffer);
if ( ( (cell_sd==sd_index) == (fit->second%2 == 1) ) == normals_point_outside_of_the_subdomain )
std::swap(indices[0],indices[1]);
facet_buffer << "3" << " " << indices[0] <<" " << indices[1] <<" " << indices[2] << "\n";
}
output << "OFF " << inum << " " << nfacets << " 0\n";
output << vertex_buffer.str();
output << facet_buffer.str();
return output;
}
template <typename C3T3>
std::ostream&
output_facets_in_complex_to_off(const C3T3& c3t3,
std::ostream& output)
{
typedef typename C3T3::Triangulation Triangulation;
typedef typename Triangulation::Vertex_handle Vertex_handle;
std::map<Vertex_handle, std::size_t> V;
std::size_t inum = 0;
std::size_t nfacets = 0;
cpp0x::array<std::size_t,3> indices={{0,0,0}};
std::stringstream facet_buffer,vertex_buffer;
for(typename C3T3::Facets_in_complex_iterator
fit = c3t3.facets_in_complex_begin(),
end = c3t3.facets_in_complex_end();
fit != end; ++fit)
{
typename C3T3::Subdomain_index cell_sd=c3t3.subdomain_index(fit->first);
typename C3T3::Subdomain_index opp_sd=c3t3.subdomain_index(fit->first->neighbor(fit->second));
++nfacets;
int j=-1;
for (int i = 0; i < 4; ++i)
if (i != fit->second)
indices[++j]=mesh_3_export::get_vertex_index((*fit).first->vertex(i), V, inum,vertex_buffer);
if ( (cell_sd > opp_sd) == (fit->second%2 == 1) ) std::swap(indices[0],indices[1]);
facet_buffer << "3" << " " << indices[0] <<" " << indices[1] <<" " << indices[2] << "\n";
}
output << "OFF " << inum << " " << nfacets << " 0\n";
output << vertex_buffer.str();
output << facet_buffer.str();
return output;
}
} } // end of namespace CGAL::internal
#endif // CGAL_INTERNAL_MESH_3_BOUNDARY_OF_SUDDOMAIN_OF_COMPLEX_3_IN_TRIANGULATION_3_TO_OFF_H

View File

@ -53,6 +53,7 @@ if ( CGAL_FOUND )
create_single_source_cgal_program( "test_meshing_unit_tetrahedron.cpp" )
create_single_source_cgal_program( "test_robust_weighted_circumcenter.cpp" )
create_single_source_cgal_program( "test_meshing_determinism.cpp" )
create_single_source_cgal_program( "test_c3t3_extract_subdomains_boundaries.cpp" )
else()

View File

@ -0,0 +1,97 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Mesh_triangulation_3.h>
#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
#include <CGAL/Mesh_criteria_3.h>
#include <CGAL/Implicit_to_labeling_function_wrapper.h>
#include <CGAL/Labeled_mesh_domain_3.h>
#include <CGAL/make_mesh_3.h>
#include <sstream>
using namespace CGAL::parameters;
// Domain
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::FT FT;
template <int Sq_radius>
double sphere_function (double x, double y, double z) // (c=(0,0,0), r=Sq_radius)
{
double x2=x*x, y2=y*y, z2=z*z;
return (x2+y2+z2)/Sq_radius - 1;
}
template <typename FT, typename P>
class FT_to_point_function_wrapper : public std::unary_function<P, FT>
{
typedef FT (*Implicit_function)(FT, FT, FT);
Implicit_function function;
public:
typedef P Point;
FT_to_point_function_wrapper(Implicit_function f) : function(f) {}
FT operator()(Point p) const { return function(p.x(), p.y(), p.z()); }
};
double torus_function (double x, double y, double z) {
double x2=x*x, y2=y*y, z2=z*z;
double x4=x2*x2, y4=y2*y2, z4=z2*z2;
return x4 + y4 + z4 + 2 *x2* y2 + 2*
x2*z2 + 2*y2* z2 - 5 *x2 + 4* y2 - 5*z2+4;
}
typedef FT_to_point_function_wrapper<K::FT, K::Point_3> Function;
typedef CGAL::Implicit_multi_domain_to_labeling_function_wrapper<Function>
Function_wrapper;
typedef Function_wrapper::Function_vector Function_vector;
typedef CGAL::Labeled_mesh_domain_3<Function_wrapper, K> Mesh_domain;
// Triangulation
typedef CGAL::Mesh_triangulation_3<Mesh_domain>::type Tr;
typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3;
// Mesh Criteria
typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
typedef Mesh_criteria::Facet_criteria Facet_criteria;
typedef Mesh_criteria::Cell_criteria Cell_criteria;
int main()
{
// Define functions
Function f1(&torus_function);
Function f2(&sphere_function<3>);
Function_vector v;
v.push_back(f1);
v.push_back(f2);
// Domain (Warning: Sphere_3 constructor uses square radius !)
Mesh_domain domain(v, K::Sphere_3(CGAL::ORIGIN, 5.*5.), 1e-6);
// Set mesh criteria
Facet_criteria facet_criteria(30, 0.2, 0.02); // angle, size, approximation
Cell_criteria cell_criteria(2., 0.4); // radius-edge ratio, size
Mesh_criteria criteria(facet_criteria, cell_criteria);
// Mesh generation
C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(domain, criteria, no_exude(), no_perturb());
// Output
std::stringstream off_file;
c3t3.output_boundary_to_off(off_file);
assert( off_file.str().size() > 20 );
off_file.str("");
c3t3.output_facets_in_complex_to_off(off_file);
assert( off_file.str().size() > 20 );
for (int i=0;i<4; ++i){
off_file.str("");
c3t3.output_boundary_to_off(off_file,i);
assert( off_file.str().size() > 20 );
}
return 0;
}

View File

@ -301,7 +301,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
polyhedron_demo_plugin(mesh_3_plugin Polyhedron_demo_mesh_3_plugin
Polyhedron_demo_mesh_3_plugin_cgal_code.cpp Scene_c3t3_item.moc
${meshingUI_FILES})
target_link_libraries(mesh_3_plugin scene_polyhedron_item ${QGLVIEWER_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY})
target_link_libraries(mesh_3_plugin scene_polyhedron_item scene_polygon_soup_item ${QGLVIEWER_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY})
else( Boost_VERSION GREATER 103400 )
message(STATUS "warning: the plugin mesh_3_plugin requires Boost>=1.34.1 and will not be compiled.")
endif( Boost_VERSION GREATER 103400 )

View File

@ -22,7 +22,8 @@ Scene_item* cgal_code_mesh_3(const Polyhedron*,
const double approx,
const double tets_sizing,
const double tet_shape,
const bool protect_features);
const bool protect_features,
Scene_interface* scene);
class Polyhedron_demo_mesh_3_plugin :
public QObject,
@ -163,7 +164,8 @@ void Polyhedron_demo_mesh_3_plugin::mesh_3()
approx,
tet_sizing,
radius_edge,
protect_features);
protect_features,
scene);
if(result_item) {
result_item->setName(tr("%1 3d mesh (%2 %3 %4 %5)")
.arg(item->name())

View File

@ -10,10 +10,14 @@
#include <CGAL/Polyhedral_mesh_domain_with_features_3.h>
#include <CGAL/make_mesh_3.h>
#include <Scene_polyhedron_item.h>
#include <Scene_polygon_soup_item.h>
#include <fstream>
#include <sstream>
#include <CGAL/Timer.h>
#include <QMenu>
typedef CGAL::Polyhedral_mesh_domain_with_features_3<Kernel,
Polyhedron> Mesh_domain;
@ -52,8 +56,7 @@ public:
typedef qglviewer::ManipulatedFrame ManipulatedFrame;
Scene_c3t3_item(const C3t3& c3t3)
: c3t3_(c3t3), frame(new ManipulatedFrame())
: c3t3_(c3t3), frame(new ManipulatedFrame()), last_known_scene(NULL)
{}
~Scene_c3t3_item()
@ -274,9 +277,65 @@ private:
return diag * 0.7;
}
C3t3 c3t3_;
public slots:
void export_facets_in_complex()
{
std::stringstream off_sstream;
c3t3().output_facets_in_complex_to_off(off_sstream);
std::string backup = off_sstream.str();
// Try to read .off in a polyhedron
Scene_polyhedron_item* item = new Scene_polyhedron_item();
if(!item->load(off_sstream))
{
delete item;
off_sstream.str(backup);
// Try to read .off in a polygon soup
Scene_polygon_soup_item* soup_item = new Scene_polygon_soup_item;
if(!soup_item->load(off_sstream)) {
delete soup_item;
return;
}
soup_item->setName(QString("%1_%2").arg(this->name()).arg("facets"));
last_known_scene->addItem(soup_item);
}
else{
item->setName(QString("%1_%2").arg(this->name()).arg("facets"));
last_known_scene->addItem(item);
}
}
public:
QMenu* contextMenu()
{
const char* prop_name = "Menu modified by Scene_c3t3_item.";
QMenu* menu = Scene_item::contextMenu();
// Use dynamic properties:
// http://doc.trolltech.com/lastest/qobject.html#property
bool menuChanged = menu->property(prop_name).toBool();
if(!menuChanged) {
QAction* actionExportFacetsInComplex =
menu->addAction(tr("Export facets in complex"));
actionExportFacetsInComplex->setObjectName("actionExportFacetsInComplex");
connect(actionExportFacetsInComplex,
SIGNAL(triggered()),this,
SLOT(export_facets_in_complex()));
}
return menu;
}
void set_scene(Scene_interface* scene){ last_known_scene=scene; }
private:
C3t3 c3t3_;
qglviewer::ManipulatedFrame* frame;
Scene_interface* last_known_scene;
};
Scene_item* cgal_code_mesh_3(const Polyhedron* pMesh,
@ -286,7 +345,8 @@ Scene_item* cgal_code_mesh_3(const Polyhedron* pMesh,
const double approx,
const double tet_sizing,
const double tet_shape,
const bool protect_features)
const bool protect_features,
Scene_interface* scene)
{
if(!pMesh) return 0;
@ -322,13 +382,14 @@ Scene_item* cgal_code_mesh_3(const Polyhedron* pMesh,
Scene_c3t3_item* new_item =
new Scene_c3t3_item(CGAL::make_mesh_3<C3t3>(domain, criteria, features));
new_item->set_scene(scene);
std::cerr << "done (" << timer.time() << " ms, " << new_item->c3t3().triangulation().number_of_vertices() << " vertices)" << std::endl;
if(new_item->c3t3().triangulation().number_of_vertices() > 0)
{
std::ofstream medit_out("out.mesh");
new_item->c3t3().output_to_medit(medit_out);
const Scene_item::Bbox& bbox = new_item->bbox();
new_item->setPosition((float)(bbox.xmin + bbox.xmax)/2.f,
(float)(bbox.ymin + bbox.ymax)/2.f,