diff --git a/Mesh_3/doc/Mesh_3/CGAL/Mesh_complex_3_in_triangulation_3.h b/Mesh_3/doc/Mesh_3/CGAL/Mesh_complex_3_in_triangulation_3.h index 6104673fe32..0ec666384e5 100644 --- a/Mesh_3/doc/Mesh_3/CGAL/Mesh_complex_3_in_triangulation_3.h +++ b/Mesh_3/doc/Mesh_3/CGAL/Mesh_complex_3_in_triangulation_3.h @@ -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 */ diff --git a/Mesh_3/include/CGAL/Mesh_complex_3_in_triangulation_3.h b/Mesh_3/include/CGAL/Mesh_complex_3_in_triangulation_3.h index 0205a07fe66..3f00cc48f06 100644 --- a/Mesh_3/include/CGAL/Mesh_complex_3_in_triangulation_3.h +++ b/Mesh_3/include/CGAL/Mesh_complex_3_in_triangulation_3.h @@ -38,6 +38,7 @@ #include #include #include +#include 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 diff --git a/Mesh_3/include/CGAL/internal/Mesh_3/Boundary_of_subdomain_of_complex_3_in_triangulation_3_to_off.h b/Mesh_3/include/CGAL/internal/Mesh_3/Boundary_of_subdomain_of_complex_3_in_triangulation_3_to_off.h new file mode 100644 index 00000000000..8fc67a56520 --- /dev/null +++ b/Mesh_3/include/CGAL/internal/Mesh_3/Boundary_of_subdomain_of_complex_3_in_triangulation_3_to_off.h @@ -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 +#include + +#include + +namespace CGAL { + +namespace internal{ + +namespace mesh_3_export{ +template +std::size_t get_vertex_index(Vertex_handle v,std::map& V,std::size_t& inum,std::stringstream& vertex_buffer){ + std::pair::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 +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 V; + + std::size_t inum = 0; + std::size_t nfacets = 0; + cpp0x::array 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 +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 V; + + std::size_t inum = 0; + std::size_t nfacets = 0; + cpp0x::array 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 diff --git a/Mesh_3/test/Mesh_3/CMakeLists.txt b/Mesh_3/test/Mesh_3/CMakeLists.txt index 6fcde2058ef..ef893683917 100644 --- a/Mesh_3/test/Mesh_3/CMakeLists.txt +++ b/Mesh_3/test/Mesh_3/CMakeLists.txt @@ -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() diff --git a/Mesh_3/test/Mesh_3/test_c3t3_extract_subdomains_boundaries.cpp b/Mesh_3/test/Mesh_3/test_c3t3_extract_subdomains_boundaries.cpp new file mode 100644 index 00000000000..6986dd9bf11 --- /dev/null +++ b/Mesh_3/test/Mesh_3/test_c3t3_extract_subdomains_boundaries.cpp @@ -0,0 +1,97 @@ +#include + +#include +#include +#include + +#include +#include +#include + +#include + +using namespace CGAL::parameters; + +// Domain +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::FT FT; + +template +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 +class FT_to_point_function_wrapper : public std::unary_function +{ + 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 Function; +typedef CGAL::Implicit_multi_domain_to_labeling_function_wrapper + Function_wrapper; +typedef Function_wrapper::Function_vector Function_vector; +typedef CGAL::Labeled_mesh_domain_3 Mesh_domain; + +// Triangulation +typedef CGAL::Mesh_triangulation_3::type Tr; +typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; + +// Mesh Criteria +typedef CGAL::Mesh_criteria_3 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(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; +} diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index 5e8214357d1..bd931d49176 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -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 ) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_mesh_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_mesh_3_plugin.cpp index 7b2a167ec10..c37865a9bc1 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_mesh_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_mesh_3_plugin.cpp @@ -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()) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_mesh_3_plugin_cgal_code.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_mesh_3_plugin_cgal_code.cpp index f31c12c8ae6..0812962bf6d 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_mesh_3_plugin_cgal_code.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_mesh_3_plugin_cgal_code.cpp @@ -10,10 +10,14 @@ #include #include +#include +#include #include +#include #include +#include typedef CGAL::Polyhedral_mesh_domain_with_features_3 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(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,