863 lines
26 KiB
C++
863 lines
26 KiB
C++
// Copyright (c) 2009-2014 INRIA Sophia-Antipolis (France).
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org).
|
|
//
|
|
// $URL: https://github.com/CGAL/cgal/blob/v5.1/Mesh_3/include/CGAL/Mesh_3/Mesher_3.h $
|
|
// $Id: Mesher_3.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot
|
|
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
|
//
|
|
//
|
|
// Author(s) : Laurent Rineau, Stephane Tayeb, Clement Jamin
|
|
//
|
|
//******************************************************************************
|
|
// File Description :
|
|
// Implements a mesher_3 with two mesher levels : one for facets and one for
|
|
// tets.
|
|
//******************************************************************************
|
|
|
|
#ifndef CGAL_MESH_3_MESHER_3_H
|
|
#define CGAL_MESH_3_MESHER_3_H
|
|
|
|
#include <CGAL/license/Mesh_3.h>
|
|
|
|
#include <CGAL/disable_warnings.h>
|
|
|
|
#include <CGAL/Mesh_3/config.h>
|
|
|
|
#include <CGAL/Mesh_error_code.h>
|
|
|
|
#include <CGAL/Mesh_3/Dump_c3t3.h>
|
|
|
|
#include <CGAL/Mesh_3/Refine_facets_3.h>
|
|
#include <CGAL/Mesh_3/Refine_facets_manifold_base.h>
|
|
#include <CGAL/Mesh_3/Refine_cells_3.h>
|
|
#include <CGAL/Mesh_3/Refine_tets_visitor.h>
|
|
#include <CGAL/Mesher_level_visitors.h>
|
|
#include <CGAL/Kernel_traits.h>
|
|
#include <CGAL/point_generators_3.h>
|
|
#include <CGAL/atomic.h>
|
|
|
|
#ifdef CGAL_MESH_3_USE_OLD_SURFACE_RESTRICTED_DELAUNAY_UPDATE
|
|
#include <CGAL/Surface_mesher/Surface_mesher_visitor.h>
|
|
#endif
|
|
|
|
#include <CGAL/Mesh_3/Concurrent_mesher_config.h>
|
|
#include <CGAL/Real_timer.h>
|
|
|
|
#ifdef CGAL_MESH_3_PROFILING
|
|
#include <CGAL/Mesh_3/Profiling_tools.h>
|
|
#endif
|
|
|
|
#ifdef CGAL_LINKED_WITH_TBB
|
|
# include <thread>
|
|
#endif
|
|
|
|
#include <boost/format.hpp>
|
|
#include <boost/type_traits/is_convertible.hpp>
|
|
#include <string>
|
|
|
|
namespace CGAL {
|
|
namespace Mesh_3 {
|
|
|
|
/************************************************
|
|
// Class Mesher_3_base
|
|
// Two versions: sequential / parallel
|
|
************************************************/
|
|
|
|
// Sequential
|
|
template <typename Tr, typename Concurrency_tag>
|
|
class Mesher_3_base
|
|
{
|
|
protected:
|
|
typedef typename Tr::Lock_data_structure Lock_data_structure;
|
|
|
|
Mesher_3_base(const Bbox_3 &, int) {}
|
|
|
|
Lock_data_structure *get_lock_data_structure() const { return 0; }
|
|
WorksharingDataStructureType *get_worksharing_data_structure() const { return 0; }
|
|
void set_bbox(const Bbox_3 &) {}
|
|
};
|
|
|
|
#ifdef CGAL_LINKED_WITH_TBB
|
|
// Parallel
|
|
template <typename Tr>
|
|
class Mesher_3_base<Tr, Parallel_tag>
|
|
{
|
|
protected:
|
|
typedef typename Tr::Lock_data_structure Lock_data_structure;
|
|
|
|
Mesher_3_base(const Bbox_3 &bbox, int num_grid_cells_per_axis)
|
|
: m_lock_ds(bbox, num_grid_cells_per_axis),
|
|
m_worksharing_ds(bbox)
|
|
{}
|
|
|
|
Lock_data_structure *get_lock_data_structure()
|
|
{
|
|
return &m_lock_ds;
|
|
}
|
|
WorksharingDataStructureType *get_worksharing_data_structure()
|
|
{
|
|
return &m_worksharing_ds;
|
|
}
|
|
const WorksharingDataStructureType *get_worksharing_data_structure() const
|
|
{
|
|
return &m_worksharing_ds;
|
|
}
|
|
|
|
void set_bbox(const Bbox_3 &bbox)
|
|
{
|
|
m_lock_ds.set_bbox(bbox);
|
|
m_worksharing_ds.set_bbox(bbox);
|
|
}
|
|
|
|
/// Lock data structure
|
|
Lock_data_structure m_lock_ds;
|
|
/// Worksharing data structure
|
|
WorksharingDataStructureType m_worksharing_ds;
|
|
};
|
|
#endif // CGAL_LINKED_WITH_TBB
|
|
|
|
|
|
/************************************************
|
|
*
|
|
* Mesher_3 class
|
|
*
|
|
************************************************/
|
|
|
|
template<class C3T3, class MeshCriteria, class MeshDomain>
|
|
class Mesher_3
|
|
: public Mesher_3_base<
|
|
typename C3T3::Triangulation,
|
|
#ifdef CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT
|
|
Sequential_tag
|
|
#else
|
|
typename C3T3::Concurrency_tag
|
|
#endif
|
|
>
|
|
{
|
|
public:
|
|
#ifdef CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT
|
|
typedef Sequential_tag Concurrency_tag;
|
|
#else
|
|
typedef typename C3T3::Concurrency_tag Concurrency_tag;
|
|
#endif
|
|
typedef typename C3T3::Triangulation Triangulation;
|
|
typedef typename Triangulation::Point Point;
|
|
typedef typename Triangulation::Bare_point Bare_point;
|
|
typedef typename Kernel_traits<Point>::Kernel Kernel;
|
|
typedef typename Kernel::Vector_3 Vector;
|
|
typedef typename MeshDomain::Index Index;
|
|
|
|
// Self
|
|
typedef Mesher_3<C3T3, MeshCriteria, MeshDomain> Self;
|
|
#ifdef CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT
|
|
typedef Mesher_3_base<Triangulation, Sequential_tag> Base;
|
|
#else
|
|
typedef Mesher_3_base<Triangulation, typename C3T3::Concurrency_tag> Base;
|
|
#endif
|
|
|
|
using Base::get_lock_data_structure;
|
|
|
|
//-------------------------------------------------------
|
|
// Mesher_levels
|
|
//-------------------------------------------------------
|
|
// typedef Refine_facets_manifold_base<Rf_base> Rf_manifold_base;
|
|
|
|
/// Facets mesher level
|
|
typedef Refine_facets_3<
|
|
Triangulation,
|
|
typename MeshCriteria::Facet_criteria,
|
|
MeshDomain,
|
|
C3T3,
|
|
Null_mesher_level,
|
|
Concurrency_tag,
|
|
Refine_facets_manifold_base
|
|
> Facets_level;
|
|
|
|
/// Cells mesher level
|
|
typedef Refine_cells_3<
|
|
Triangulation,
|
|
typename MeshCriteria::Cell_criteria,
|
|
MeshDomain,
|
|
C3T3,
|
|
Facets_level,
|
|
Concurrency_tag> Cells_level;
|
|
|
|
//-------------------------------------------------------
|
|
// Visitors
|
|
//-------------------------------------------------------
|
|
/// Facets visitor : to update cells when refining surface
|
|
typedef tets::Refine_facets_visitor<
|
|
Triangulation,
|
|
Cells_level,
|
|
Null_mesh_visitor> Facets_visitor;
|
|
|
|
#ifndef CGAL_MESH_3_USE_OLD_SURFACE_RESTRICTED_DELAUNAY_UPDATE
|
|
/// Cells visitor : it just need to know previous level
|
|
typedef Null_mesh_visitor_level<Facets_visitor> Cells_visitor;
|
|
#else
|
|
/// Cells visitor : to update surface (restore restricted Delaunay)
|
|
/// when refining cells
|
|
typedef Surface_mesher::Visitor<
|
|
Triangulation,
|
|
Facets_level,
|
|
Facets_visitor> Cells_visitor;
|
|
#endif
|
|
|
|
/// Constructor
|
|
Mesher_3(C3T3& c3t3,
|
|
const MeshDomain& domain,
|
|
const MeshCriteria& criteria,
|
|
int mesh_topology = 0,
|
|
std::size_t maximal_number_of_vertices = 0,
|
|
Mesh_error_code* error_code = 0
|
|
#ifndef CGAL_NO_ATOMIC
|
|
, CGAL::cpp11::atomic<bool>* stop_ptr = 0
|
|
#endif
|
|
);
|
|
|
|
/// Destructor
|
|
~Mesher_3()
|
|
{
|
|
// The lock data structure is going to be destroyed
|
|
r_c3t3_.triangulation().set_lock_data_structure(nullptr);
|
|
}
|
|
|
|
/// Launch mesh refinement
|
|
double refine_mesh(std::string dump_after_refine_surface_prefix = "");
|
|
|
|
/// Debug
|
|
std::string debug_info() const;
|
|
std::string debug_info_header() const;
|
|
|
|
// Step-by-step methods
|
|
void initialize();
|
|
void fix_c3t3();
|
|
void display_number_of_bad_elements();
|
|
void one_step();
|
|
bool is_algorithm_done();
|
|
|
|
#ifdef CGAL_MESH_3_MESHER_STATUS_ACTIVATED
|
|
struct Mesher_status
|
|
{
|
|
std::size_t vertices, facet_queue, cells_queue;
|
|
|
|
Mesher_status(std::size_t v, std::size_t f, std::size_t c)
|
|
: vertices(v), facet_queue(f), cells_queue(c) {}
|
|
};
|
|
|
|
Mesher_status status() const;
|
|
#endif
|
|
|
|
private:
|
|
/// The oracle
|
|
const MeshDomain& r_oracle_;
|
|
|
|
/// Meshers
|
|
Null_mesher_level null_mesher_;
|
|
Facets_level facets_mesher_;
|
|
Cells_level cells_mesher_;
|
|
|
|
/// Visitors
|
|
Null_mesh_visitor null_visitor_;
|
|
Facets_visitor facets_visitor_;
|
|
Cells_visitor cells_visitor_;
|
|
|
|
/// The container of the resulting mesh
|
|
C3T3& r_c3t3_;
|
|
|
|
enum Refinement_stage {
|
|
NOT_INITIALIZED,
|
|
REFINE_FACETS,
|
|
REFINE_FACETS_AND_EDGES,
|
|
REFINE_FACETS_AND_EDGES_AND_VERTICES,
|
|
REFINE_ALL
|
|
};
|
|
|
|
Refinement_stage refinement_stage;
|
|
|
|
/// Maximal number of vertices
|
|
std::size_t maximal_number_of_vertices_;
|
|
|
|
/// Pointer to the error code
|
|
Mesh_error_code* const error_code_;
|
|
|
|
#ifndef CGAL_NO_ATOMIC
|
|
/// Pointer to the atomic Boolean that can stop the process
|
|
CGAL::cpp11::atomic<bool>* const stop_ptr;
|
|
#endif
|
|
|
|
#ifdef CGAL_LINKED_WITH_TBB
|
|
std::size_t approximate_number_of_vertices(CGAL::Parallel_tag) const {
|
|
# if CGAL_CONCURRENT_COMPACT_CONTAINER_APPROXIMATE_SIZE
|
|
return r_c3t3_.triangulation().tds().vertices().approximate_size();
|
|
# else // not CGAL_CONCURRENT_COMPACT_CONTAINER_APPROXIMATE_SIZE
|
|
CGAL_error_msg(
|
|
"If you want to use the Mesh_3 feature \"maximal_number_of_vertices\"\n"
|
|
"with CGAL::Parallel_tag then you need to recompile the code with the\n"
|
|
"preprocessor macro CGAL_CONCURRENT_COMPACT_CONTAINER_APPROXIMATE_SIZE\n"
|
|
"set to 1. That will induce a performance loss of 3%.\n");
|
|
# endif // not CGAL_CONCURRENT_COMPACT_CONTAINER_APPROXIMATE_SIZE
|
|
}
|
|
#endif // CGAL_LINKED_WITH_TBB
|
|
|
|
std::size_t approximate_number_of_vertices(CGAL::Sequential_tag) const {
|
|
return r_c3t3_.triangulation().number_of_vertices();
|
|
}
|
|
|
|
bool forced_stop() const {
|
|
#ifndef CGAL_NO_ATOMIC
|
|
if(stop_ptr != 0 &&
|
|
stop_ptr->load(CGAL::cpp11::memory_order_acquire) == true)
|
|
{
|
|
if(error_code_ != 0) *error_code_ = CGAL_MESH_3_STOPPED;
|
|
return true;
|
|
}
|
|
#endif // not defined CGAL_NO_ATOMIC
|
|
if(maximal_number_of_vertices_ != 0 &&
|
|
approximate_number_of_vertices(Concurrency_tag()) >= maximal_number_of_vertices_)
|
|
{
|
|
if(error_code_ != 0) {
|
|
*error_code_ = CGAL_MESH_3_MAXIMAL_NUMBER_OF_VERTICES_REACHED;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
// Disabled copy constructor
|
|
Mesher_3(const Self& src);
|
|
// Disabled assignment operator
|
|
Self& operator=(const Self& src);
|
|
|
|
}; // end class Mesher_3
|
|
|
|
|
|
|
|
template<class C3T3, class MC, class MD>
|
|
Mesher_3<C3T3,MC,MD>::Mesher_3(C3T3& c3t3,
|
|
const MD& domain,
|
|
const MC& criteria,
|
|
int mesh_topology,
|
|
std::size_t maximal_number_of_vertices,
|
|
Mesh_error_code* error_code
|
|
#ifndef CGAL_NO_ATOMIC
|
|
, CGAL::cpp11::atomic<bool>* stop_ptr
|
|
#endif
|
|
)
|
|
: Base(c3t3.bbox(),
|
|
Concurrent_mesher_config::get().locking_grid_num_cells_per_axis)
|
|
, r_oracle_(domain)
|
|
, null_mesher_()
|
|
, facets_mesher_(c3t3.triangulation(),
|
|
criteria.facet_criteria_object(),
|
|
domain,
|
|
null_mesher_,
|
|
c3t3,
|
|
mesh_topology,
|
|
maximal_number_of_vertices
|
|
#ifndef CGAL_NO_ATOMIC
|
|
, stop_ptr
|
|
#endif
|
|
)
|
|
, cells_mesher_(c3t3.triangulation(),
|
|
criteria.cell_criteria_object(),
|
|
domain,
|
|
facets_mesher_,
|
|
c3t3,
|
|
maximal_number_of_vertices
|
|
#ifndef CGAL_NO_ATOMIC
|
|
, stop_ptr
|
|
#endif
|
|
)
|
|
, null_visitor_()
|
|
, facets_visitor_(&cells_mesher_, &null_visitor_)
|
|
#ifndef CGAL_MESH_3_USE_OLD_SURFACE_RESTRICTED_DELAUNAY_UPDATE
|
|
, cells_visitor_(facets_visitor_)
|
|
#else
|
|
, cells_visitor_(&facets_mesher_, &facets_visitor_)
|
|
#endif
|
|
, r_c3t3_(c3t3)
|
|
, maximal_number_of_vertices_(maximal_number_of_vertices)
|
|
, error_code_(error_code)
|
|
#ifndef CGAL_NO_ATOMIC
|
|
, stop_ptr(stop_ptr)
|
|
#endif
|
|
{
|
|
facets_mesher_.set_lock_ds(this->get_lock_data_structure());
|
|
facets_mesher_.set_worksharing_ds(this->get_worksharing_data_structure());
|
|
cells_mesher_.set_lock_ds(this->get_lock_data_structure());
|
|
cells_mesher_.set_worksharing_ds(this->get_worksharing_data_structure());
|
|
#ifndef CGAL_NO_ATOMIC
|
|
cells_mesher_.set_stop_pointer(stop_ptr);
|
|
facets_mesher_.set_stop_pointer(stop_ptr);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
template<class C3T3, class MC, class MD>
|
|
double
|
|
Mesher_3<C3T3,MC,MD>::
|
|
refine_mesh(std::string dump_after_refine_surface_prefix)
|
|
{
|
|
CGAL::Real_timer timer;
|
|
timer.start();
|
|
double elapsed_time = 0.;
|
|
|
|
// First surface mesh could modify c3t3 without notifying cells_mesher
|
|
// So we have to ensure that no old cell will be left in c3t3
|
|
// Second, the c3t3 object could have been corrupted since the last call
|
|
// to `refine_mesh`, for example by inserting new vertices in the
|
|
// triangulation.
|
|
r_c3t3_.clear_cells_and_facets_from_c3t3();
|
|
|
|
const Triangulation& r_tr = r_c3t3_.triangulation();
|
|
CGAL_USE(r_tr);
|
|
|
|
#ifndef CGAL_MESH_3_VERBOSE
|
|
// Scan surface and refine it
|
|
initialize();
|
|
|
|
#ifdef CGAL_MESH_3_PROFILING
|
|
std::cerr << "Refining facets..." << std::endl;
|
|
WallClockTimer t;
|
|
#endif
|
|
facets_mesher_.refine(facets_visitor_);
|
|
facets_mesher_.scan_edges();
|
|
refinement_stage = REFINE_FACETS_AND_EDGES;
|
|
facets_mesher_.refine(facets_visitor_);
|
|
facets_mesher_.scan_vertices();
|
|
refinement_stage = REFINE_FACETS_AND_EDGES_AND_VERTICES;
|
|
facets_mesher_.refine(facets_visitor_);
|
|
#ifdef CGAL_MESH_3_PROFILING
|
|
double facet_ref_time = t.elapsed();
|
|
std::cerr << "==== Facet refinement: " << facet_ref_time << " seconds ===="
|
|
<< std::endl << std::endl;
|
|
# ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA
|
|
// If it's parallel but the refinement is forced to sequential, we don't
|
|
// output the value
|
|
# ifndef CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT
|
|
CGAL_MESH_3_SET_PERFORMANCE_DATA("Facets_time", facet_ref_time);
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#if defined(CHECK_AND_DISPLAY_THE_NUMBER_OF_BAD_ELEMENTS_IN_THE_END)
|
|
std::cerr << std::endl
|
|
<< "===============================================================" << std::endl
|
|
<< "=== CHECK_AND_DISPLAY_THE_NUMBER_OF_BAD_ELEMENTS_IN_THE_END ===" << std::endl;
|
|
display_number_of_bad_elements();
|
|
std::cerr
|
|
<< "==============================================================="
|
|
<< std::endl << std::endl;
|
|
#endif
|
|
|
|
// Then activate facet to surface visitor (surface could be
|
|
// refined again if it is encroached)
|
|
facets_visitor_.activate();
|
|
|
|
dump_c3t3(r_c3t3_, dump_after_refine_surface_prefix);
|
|
|
|
if(!forced_stop())
|
|
{
|
|
// Then scan volume and refine it
|
|
cells_mesher_.scan_triangulation();
|
|
refinement_stage = REFINE_ALL;
|
|
#ifdef CGAL_MESH_3_PROFILING
|
|
std::cerr << "Refining cells..." << std::endl;
|
|
t.reset();
|
|
#endif
|
|
cells_mesher_.refine(cells_visitor_);
|
|
#ifdef CGAL_MESH_3_PROFILING
|
|
double cell_ref_time = t.elapsed();
|
|
std::cerr << "==== Cell refinement: " << cell_ref_time << " seconds ===="
|
|
<< std::endl << std::endl;
|
|
# ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA
|
|
// If it's parallel but the refinement is forced to sequential, we don't
|
|
// output the value
|
|
# ifndef CGAL_DEBUG_FORCE_SEQUENTIAL_MESH_REFINEMENT
|
|
CGAL_MESH_3_SET_PERFORMANCE_DATA("Cells_refin_time", cell_ref_time);
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#if defined(CGAL_MESH_3_VERBOSE) || defined(CGAL_MESH_3_PROFILING)
|
|
std::cerr
|
|
<< "Vertices: " << r_c3t3_.triangulation().number_of_vertices() << std::endl
|
|
<< "Facets : " << r_c3t3_.number_of_facets_in_complex() << std::endl
|
|
<< "Tets : " << r_c3t3_.number_of_cells_in_complex() << std::endl;
|
|
#endif
|
|
} // end test of `maximal_number_of_vertices`
|
|
#else // ifdef CGAL_MESH_3_VERBOSE
|
|
std::cerr << "Start surface scan...";
|
|
initialize();
|
|
std::cerr << "end scan. [Bad facets:" << facets_mesher_.size() << "]";
|
|
std::cerr << std::endl << std::endl;
|
|
elapsed_time += timer.time();
|
|
timer.stop(); timer.reset(); timer.start();
|
|
|
|
int nbsteps = 0;
|
|
|
|
std::cerr << "Refining Surface...\n";
|
|
std::cerr << "Legend of the following line: "
|
|
<< "(#vertices,#steps," << cells_mesher_.debug_info_header()
|
|
<< ")\n";
|
|
|
|
std::cerr << "(" << r_tr.number_of_vertices() << ","
|
|
<< nbsteps << "," << cells_mesher_.debug_info() << ")";
|
|
|
|
while ( ! facets_mesher_.is_algorithm_done() &&
|
|
! forced_stop() )
|
|
{
|
|
facets_mesher_.one_step(facets_visitor_);
|
|
std::cerr
|
|
<< boost::format("\r \r"
|
|
"(%1%,%2%,%3%) (%|4$.1f| vertices/s)")
|
|
% r_tr.number_of_vertices()
|
|
% nbsteps % cells_mesher_.debug_info()
|
|
% (nbsteps / timer.time());
|
|
if(refinement_stage == REFINE_FACETS &&
|
|
! forced_stop() &&
|
|
facets_mesher_.is_algorithm_done())
|
|
{
|
|
facets_mesher_.scan_edges();
|
|
refinement_stage = REFINE_FACETS_AND_EDGES;
|
|
}
|
|
if(refinement_stage == REFINE_FACETS_AND_EDGES &&
|
|
! forced_stop() &&
|
|
facets_mesher_.is_algorithm_done())
|
|
{
|
|
facets_mesher_.scan_vertices();
|
|
refinement_stage = REFINE_FACETS_AND_EDGES_AND_VERTICES;
|
|
}
|
|
++nbsteps;
|
|
}
|
|
std::cerr << std::endl;
|
|
std::cerr << "Total refining surface time: " << timer.time() << "s" << std::endl;
|
|
std::cerr << std::endl;
|
|
|
|
CGAL_triangulation_postcondition(r_tr.is_valid());
|
|
|
|
elapsed_time += timer.time();
|
|
timer.stop(); timer.reset(); timer.start();
|
|
nbsteps = 0;
|
|
|
|
facets_visitor_.activate();
|
|
dump_c3t3(r_c3t3_, dump_after_refine_surface_prefix);
|
|
std::cerr << "Start volume scan...";
|
|
cells_mesher_.scan_triangulation();
|
|
refinement_stage = REFINE_ALL;
|
|
std::cerr << "end scan. [Bad tets:" << cells_mesher_.size() << "]";
|
|
std::cerr << std::endl << std::endl;
|
|
elapsed_time += timer.time();
|
|
timer.stop(); timer.reset(); timer.start();
|
|
|
|
std::cerr << "Refining...\n";
|
|
std::cerr << "Legend of the following line: "
|
|
<< "(#vertices,#steps," << cells_mesher_.debug_info_header()
|
|
<< ")\n";
|
|
std::cerr << "(" << r_tr.number_of_vertices() << ","
|
|
<< nbsteps << "," << cells_mesher_.debug_info() << ")";
|
|
|
|
while ( ! cells_mesher_.is_algorithm_done() &&
|
|
! forced_stop() )
|
|
{
|
|
cells_mesher_.one_step(cells_visitor_);
|
|
std::cerr
|
|
<< boost::format("\r \r"
|
|
"(%1%,%2%,%3%) (%|4$.1f| vertices/s)")
|
|
% r_tr.number_of_vertices()
|
|
% nbsteps % cells_mesher_.debug_info()
|
|
% (nbsteps / timer.time());
|
|
++nbsteps;
|
|
}
|
|
std::cerr << std::endl;
|
|
|
|
std::cerr << "Total refining volume time: " << timer.time() << "s" << std::endl;
|
|
std::cerr << "Total refining time: " << timer.time()+elapsed_time << "s" << std::endl;
|
|
std::cerr << std::endl;
|
|
|
|
CGAL_triangulation_postcondition(r_tr.is_valid());
|
|
#endif
|
|
|
|
(void)(forced_stop()); // sets *error_code
|
|
|
|
timer.stop();
|
|
elapsed_time += timer.time();
|
|
|
|
#if defined(CHECK_AND_DISPLAY_THE_NUMBER_OF_BAD_ELEMENTS_IN_THE_END) \
|
|
|| defined(SHOW_REMAINING_BAD_ELEMENT_IN_RED)
|
|
std::cerr << std::endl
|
|
<< "===============================================================" << std::endl
|
|
<< "=== CHECK_AND_DISPLAY_THE_NUMBER_OF_BAD_ELEMENTS_IN_THE_END ===" << std::endl;
|
|
display_number_of_bad_elements();
|
|
std::cerr
|
|
<< "==============================================================="
|
|
<< std::endl << std::endl;
|
|
#endif
|
|
|
|
return elapsed_time;
|
|
}
|
|
|
|
|
|
template<class C3T3, class MC, class MD>
|
|
void
|
|
Mesher_3<C3T3,MC,MD>::
|
|
initialize()
|
|
{
|
|
#ifdef CGAL_MESH_3_PROFILING
|
|
std::cerr << "Initializing... ";
|
|
WallClockTimer t;
|
|
#endif
|
|
//=====================================
|
|
// Bounding box estimation
|
|
//=====================================
|
|
#if defined(CGAL_LINKED_WITH_TBB) || \
|
|
defined(CGAL_SEQUENTIAL_MESH_3_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE)
|
|
|
|
#ifndef CGAL_SEQUENTIAL_MESH_3_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE
|
|
if(boost::is_convertible<Concurrency_tag, Parallel_tag>::value)
|
|
#endif // If that macro is defined, then estimated_bbox must be initialized
|
|
{
|
|
Base::set_bbox(r_oracle_.bbox());
|
|
}
|
|
#endif // CGAL_LINKED_WITH_TBB||"sequential use far sphere"
|
|
|
|
//========================================
|
|
// Initialization: parallel or sequential
|
|
//========================================
|
|
|
|
#ifdef CGAL_LINKED_WITH_TBB
|
|
// Parallel
|
|
if (boost::is_convertible<Concurrency_tag, Parallel_tag>::value)
|
|
{
|
|
// we're not multi-thread, yet
|
|
r_c3t3_.triangulation().set_lock_data_structure(0);
|
|
|
|
# ifndef CGAL_PARALLEL_MESH_3_DO_NOT_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE
|
|
|
|
if (r_c3t3_.number_of_far_points() == 0 && r_c3t3_.number_of_facets() == 0)
|
|
{
|
|
const Bbox_3 &bbox = r_oracle_.bbox();
|
|
|
|
// Compute radius for far sphere
|
|
const double xdelta = bbox.xmax()-bbox.xmin();
|
|
const double ydelta = bbox.ymax()-bbox.ymin();
|
|
const double zdelta = bbox.zmax()-bbox.zmin();
|
|
const double radius = 5. * std::sqrt(xdelta*xdelta +
|
|
ydelta*ydelta +
|
|
zdelta*zdelta);
|
|
const Vector center(
|
|
bbox.xmin() + 0.5*xdelta,
|
|
bbox.ymin() + 0.5*ydelta,
|
|
bbox.zmin() + 0.5*zdelta);
|
|
# ifdef CGAL_CONCURRENT_MESH_3_VERBOSE
|
|
std::cerr << "Adding points on a far sphere (radius = " << radius <<")...";
|
|
# endif
|
|
Random_points_on_sphere_3<Bare_point> random_point(radius);
|
|
const int NUM_PSEUDO_INFINITE_VERTICES = static_cast<int>(
|
|
float(std::thread::hardware_concurrency())
|
|
* Concurrent_mesher_config::get().num_pseudo_infinite_vertices_per_core);
|
|
for (int i = 0 ; i < NUM_PSEUDO_INFINITE_VERTICES ; ++i, ++random_point)
|
|
r_c3t3_.add_far_point(r_c3t3_.triangulation().geom_traits().construct_weighted_point_3_object()
|
|
(r_c3t3_.triangulation().geom_traits().construct_translated_point_3_object()(*random_point, center)));
|
|
|
|
# ifdef CGAL_CONCURRENT_MESH_3_VERBOSE
|
|
std::cerr << "done." << std::endl;
|
|
# endif
|
|
}
|
|
# endif // CGAL_PARALLEL_MESH_3_DO_NOT_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE
|
|
|
|
#ifdef CGAL_MESH_3_PROFILING
|
|
double init_time = t.elapsed();
|
|
std::cerr << "done in " << init_time << " seconds." << std::endl;
|
|
#endif
|
|
|
|
// Scan triangulation
|
|
facets_mesher_.scan_triangulation();
|
|
refinement_stage = REFINE_FACETS;
|
|
|
|
// From now on, we're multi-thread
|
|
r_c3t3_.triangulation().set_lock_data_structure(get_lock_data_structure());
|
|
}
|
|
// Sequential
|
|
else
|
|
#endif // CGAL_LINKED_WITH_TBB
|
|
{
|
|
if (r_c3t3_.number_of_far_points() == 0 &&
|
|
r_c3t3_.number_of_facets() == 0 &&
|
|
(r_c3t3_.triangulation().dimension() < 3
|
|
#ifdef CGAL_SEQUENTIAL_MESH_3_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE
|
|
|| true // in sequential mode, one wants the far points only
|
|
// if the macro
|
|
// `CGAL_SEQUENTIAL_MESH_3_ADD_OUTSIDE_POINTS_ON_A_FAR_SPHERE`
|
|
// is defined, or if the dimension of the
|
|
// triangulation is 2.
|
|
#endif
|
|
)) {
|
|
const Bbox_3 &bbox = r_oracle_.bbox();
|
|
|
|
// Compute radius for far sphere
|
|
const double xdelta = bbox.xmax()-bbox.xmin();
|
|
const double ydelta = bbox.ymax()-bbox.ymin();
|
|
const double zdelta = bbox.zmax()-bbox.zmin();
|
|
const double radius = 5. * std::sqrt(xdelta*xdelta +
|
|
ydelta*ydelta +
|
|
zdelta*zdelta);
|
|
const Vector center(
|
|
bbox.xmin() + 0.5*xdelta,
|
|
bbox.ymin() + 0.5*ydelta,
|
|
bbox.zmin() + 0.5*zdelta);
|
|
# ifdef CGAL_MESH_3_VERBOSE
|
|
std::cerr << "Adding points on a far sphere (radius = " << radius << ")...";
|
|
# endif
|
|
Random_points_on_sphere_3<Bare_point> random_point(radius);
|
|
const int NUM_PSEUDO_INFINITE_VERTICES = 12*2;
|
|
for (int i = 0 ; i < NUM_PSEUDO_INFINITE_VERTICES ; ++i, ++random_point)
|
|
r_c3t3_.add_far_point(r_c3t3_.triangulation().geom_traits().construct_weighted_point_3_object()
|
|
(r_c3t3_.triangulation().geom_traits().construct_translated_point_3_object()(*random_point, center)));
|
|
# ifdef CGAL_MESH_3_VERBOSE
|
|
std::cerr << "done." << std::endl;
|
|
# endif
|
|
}
|
|
|
|
#ifdef CGAL_MESH_3_PROFILING
|
|
double init_time = t.elapsed();
|
|
std::cerr << "done in " << init_time << " seconds." << std::endl;
|
|
#endif
|
|
|
|
// Scan triangulation
|
|
facets_mesher_.scan_triangulation();
|
|
refinement_stage = REFINE_FACETS;
|
|
}
|
|
}
|
|
|
|
|
|
template<class C3T3, class MC, class MD>
|
|
void
|
|
Mesher_3<C3T3,MC,MD>::
|
|
fix_c3t3()
|
|
{
|
|
if ( ! facets_visitor_.is_active() )
|
|
{
|
|
cells_mesher_.scan_triangulation();
|
|
}
|
|
}
|
|
|
|
|
|
template<class C3T3, class MC, class MD>
|
|
void
|
|
Mesher_3<C3T3,MC,MD>::
|
|
display_number_of_bad_elements()
|
|
{
|
|
int nf = facets_mesher_.number_of_bad_elements();
|
|
int nc = cells_mesher_.number_of_bad_elements();
|
|
std::cerr << "Bad facets: " << nf << " - Bad cells: " << nc << std::endl;
|
|
}
|
|
|
|
template<class C3T3, class MC, class MD>
|
|
void
|
|
Mesher_3<C3T3,MC,MD>::
|
|
one_step()
|
|
{
|
|
if ( ! facets_visitor_.is_active() )
|
|
{
|
|
facets_mesher_.one_step(facets_visitor_);
|
|
|
|
if ( facets_mesher_.is_algorithm_done() )
|
|
{
|
|
if(forced_stop()) {
|
|
return;
|
|
}
|
|
|
|
switch(refinement_stage) {
|
|
case REFINE_FACETS:
|
|
facets_mesher_.scan_edges();
|
|
refinement_stage = REFINE_FACETS_AND_EDGES;
|
|
if (!facets_mesher_.is_algorithm_done()) break;
|
|
CGAL_FALLTHROUGH;
|
|
case REFINE_FACETS_AND_EDGES:
|
|
facets_mesher_.scan_vertices();
|
|
refinement_stage = REFINE_FACETS_AND_EDGES_AND_VERTICES;
|
|
if (!facets_mesher_.is_algorithm_done()) break;
|
|
CGAL_FALLTHROUGH;
|
|
default:
|
|
facets_visitor_.activate();
|
|
cells_mesher_.scan_triangulation();
|
|
refinement_stage = REFINE_ALL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CGAL_assertion(refinement_stage == REFINE_ALL);
|
|
cells_mesher_.one_step(cells_visitor_);
|
|
}
|
|
}
|
|
|
|
template<class C3T3, class MC, class MD>
|
|
bool
|
|
Mesher_3<C3T3,MC,MD>::
|
|
is_algorithm_done()
|
|
{
|
|
return cells_mesher_.is_algorithm_done();
|
|
}
|
|
|
|
|
|
#ifdef CGAL_MESH_3_MESHER_STATUS_ACTIVATED
|
|
template<class C3T3, class MC, class MD>
|
|
typename Mesher_3<C3T3,MC,MD>::Mesher_status
|
|
Mesher_3<C3T3,MC,MD>::
|
|
status() const
|
|
{
|
|
#ifdef CGAL_LINKED_WITH_TBB
|
|
if(boost::is_convertible<Concurrency_tag, Parallel_tag>::value) {
|
|
const WorksharingDataStructureType* ws_ds =
|
|
this->get_worksharing_data_structure();
|
|
return Mesher_status(
|
|
# if CGAL_CONCURRENT_COMPACT_CONTAINER_APPROXIMATE_SIZE
|
|
approximate_number_of_vertices(Concurrency_tag()),
|
|
#else
|
|
// not thread-safe, but that is not important
|
|
approximate_number_of_vertices(CGAL::Sequential_tag()),
|
|
#endif
|
|
0,
|
|
ws_ds->approximate_number_of_enqueued_element());
|
|
}
|
|
else
|
|
#endif // with TBB
|
|
{
|
|
return Mesher_status(r_c3t3_.triangulation().number_of_vertices(),
|
|
facets_mesher_.queue_size(),
|
|
cells_mesher_.queue_size());
|
|
}
|
|
}
|
|
#endif
|
|
|
|
template<class C3T3, class MC, class MD>
|
|
inline
|
|
std::string
|
|
Mesher_3<C3T3,MC,MD>::debug_info() const
|
|
{
|
|
return cells_mesher_.debug_info();
|
|
}
|
|
|
|
template<class C3T3, class MC, class MD>
|
|
inline
|
|
std::string
|
|
Mesher_3<C3T3,MC,MD>::debug_info_header() const
|
|
{
|
|
return cells_mesher_.debug_info_header();
|
|
}
|
|
|
|
} // end namespace Mesh_3
|
|
|
|
} // end namespace CGAL
|
|
|
|
#include <CGAL/enable_warnings.h>
|
|
|
|
#endif // CGAL_MESH_3_MESHER_3_H
|