Merge remote-tracking branch 'cgal/6.0.x-branch'

This commit is contained in:
Sébastien Loriot 2025-03-24 11:55:32 +01:00
commit 6257109821
3 changed files with 127 additions and 30 deletions

View File

@ -611,9 +611,11 @@ bool build_triangulation_from_file(std::istream& is,
continue;
}
if(line == "Vertices")
if(line.find("Vertices") != std::string::npos)
{
is >> nv;
if(verbose)
std::cerr << "Reading "<< nv << " vertices" << std::endl;
for(int i=0; i<nv; ++i)
{
typename Tr::Geom_traits::FT x,y,z;
@ -627,11 +629,15 @@ bool build_triangulation_from_file(std::istream& is,
}
}
if(line == "Triangles")
if(line.find("Triangles") != std::string::npos)
{
bool has_negative_surface_patch_ids = false;
typename Tr::Cell::Surface_patch_index max_surface_patch_id = 0;
is >> nf;
if(verbose)
std::cerr << "Reading "<< nf << " triangles" << std::endl;
for(int i=0; i<nf; ++i)
{
int n[3];
@ -680,9 +686,13 @@ bool build_triangulation_from_file(std::istream& is,
}
}
if(line == "Tetrahedra")
if(line.find("Tetrahedra") != std::string::npos)
{
is >> ntet;
if(verbose)
std::cerr << "Reading "<< ntet << " tetrahedra" << std::endl;
for(int i=0; i<ntet; ++i)
{
int n[4];

View File

@ -106,7 +106,7 @@ void facets_in_complex_3_to_triangle_soup(const C3T3& c3t3,
resize(f, 3);
std::size_t i = 0;
for(typename Tr::Vertex_handle v : c3t3.triangulation().vertices(Facet(c, s)))
for(typename Tr::Vertex_handle v : c3t3.triangulation().vertices(fit))
{
CGAL_assertion(v != typename Tr::Vertex_handle());
CGAL_assertion(!c3t3.triangulation().is_infinite(v));
@ -128,12 +128,12 @@ void facets_in_complex_3_to_triangle_soup(const C3T3& c3t3,
if(export_all_facets)
{
if((cell_sdi > opp_sdi) == (s%2 == 1))
if(cell_sdi > opp_sdi)
std::swap(f[0], f[1]);
}
else
{
if(((cell_sdi == sd_index) == (s%2 == 1)) == normals_point_outside_of_the_subdomain)
if( (cell_sdi == sd_index) == normals_point_outside_of_the_subdomain)
std::swap(f[0], f[1]);
}

View File

@ -38,6 +38,85 @@ namespace Tetrahedral_remeshing
{
namespace internal
{
template<typename C3t3>
bool positive_orientation_after_edge_split(const typename C3t3::Edge& e,
const typename C3t3::Cell_handle circ,
const typename C3t3::Triangulation::Geom_traits::Point_3& steiner,
const C3t3&)
{
using Point = typename C3t3::Triangulation::Geom_traits::Point_3;
const auto v1 = e.first->vertex(e.second);
const auto v2 = e.first->vertex(e.third);
std::array<Point, 4> pts = {point(circ->vertex(0)->point()),
point(circ->vertex(1)->point()),
point(circ->vertex(2)->point()),
point(circ->vertex(3)->point())};
// 1st half-cell
const int i1 = circ->index(v1);
const Point p1 = pts[i1];
pts[i1] = steiner;
if(CGAL::orientation(pts[0], pts[1], pts[2], pts[3]) != CGAL::POSITIVE)
return false;
// 2nd half-cell
pts[i1] = p1;
pts[circ->index(v2)] = steiner;
if(CGAL::orientation(pts[0], pts[1], pts[2], pts[3]) != CGAL::POSITIVE)
return false;
return true;
}
template <typename C3t3>
std::optional<typename C3t3::Triangulation::Geom_traits::Point_3>
construct_steiner_point(const typename C3t3::Edge& e,
const C3t3& c3t3)
{
using Cell_circulator = typename C3t3::Triangulation::Cell_circulator;
using Cell_handle = typename C3t3::Triangulation::Cell_handle;
using Point = typename C3t3::Triangulation::Geom_traits::Point_3;
using FT = typename C3t3::Triangulation::Geom_traits::FT;
const auto& gt = c3t3.triangulation().geom_traits();
const auto& tr = c3t3.triangulation();
const auto& p1 = point(e.first->vertex(e.second)->point());
const auto& p2 = point(e.first->vertex(e.third)->point());
const auto vec = gt.construct_vector_3_object()(p1, p2);
const std::array<FT, 6> coeff = {0.33, 0.66, //1/3 and 2/3
0.3, 0.7, // 0.5 +/- 0.2
0.25, 0.75}; // 0.5 +/- 0.25
std::size_t attempt_id = 0;
while(attempt_id < coeff.size())
{
Point steiner = gt.construct_translated_point_3_object()(
p1, gt.construct_scaled_vector_3_object()(vec, coeff[attempt_id]));
++attempt_id;
bool steiner_successful = true;
Cell_circulator circ = tr.incident_cells(e);
Cell_circulator end = circ;
do
{
Cell_handle c = circ;
if(!positive_orientation_after_edge_split(e, c, steiner, c3t3))
{
steiner_successful = false;
break;
}
} while(++circ != end);
if(steiner_successful)
return steiner;
}
return std::nullopt;
}
template<typename C3t3, typename CellSelector>
typename C3t3::Vertex_handle split_edge(const typename C3t3::Edge& e,
CellSelector cell_selector,
@ -57,7 +136,7 @@ typename C3t3::Vertex_handle split_edge(const typename C3t3::Edge& e,
const Vertex_handle v1 = e.first->vertex(e.second);
const Vertex_handle v2 = e.first->vertex(e.third);
const Point m = tr.geom_traits().construct_midpoint_3_object()
Point m = tr.geom_traits().construct_midpoint_3_object()
(point(v1->point()), point(v2->point()));
//backup subdomain info of incident cells before making changes
@ -78,8 +157,6 @@ typename C3t3::Vertex_handle split_edge(const typename C3t3::Edge& e,
// remove complex edge before splitting
const Curve_index curve_index = (dimension == 1) ? c3t3.curve_index(e) : Curve_index();
if (dimension == 1)
c3t3.remove_from_complex(e);
struct Cell_info {
Subdomain_index subdomain_index_;
@ -93,39 +170,38 @@ typename C3t3::Vertex_handle split_edge(const typename C3t3::Edge& e,
boost::unordered_map<Facet, Facet_info, boost::hash<Facet>> facets_info;
// check orientation and collect incident cells to avoid circulating twice
bool steiner_point_found = false;
boost::container::small_vector<Cell_handle, 30> inc_cells;
Cell_circulator circ = tr.incident_cells(e);
Cell_circulator end = circ;
do
{
inc_cells.push_back(circ);
if (tr.is_infinite(circ))
if (tr.is_infinite(circ) || steiner_point_found)
{
++circ;
continue;
}
//1st half-cell
std::array<Point, 4> pts = { point(circ->vertex(0)->point()),
point(circ->vertex(1)->point()),
point(circ->vertex(2)->point()),
point(circ->vertex(3)->point()) };
const int i1 = circ->index(v1);
const Point p1 = pts[i1];
pts[i1] = m;
if(CGAL::orientation(pts[0], pts[1], pts[2], pts[3]) != CGAL::POSITIVE)
return Vertex_handle();
//2nd half-cell
pts[i1] = p1;
pts[circ->index(v2)] = m;
if (CGAL::orientation(pts[0], pts[1], pts[2], pts[3]) != CGAL::POSITIVE)
return Vertex_handle();
const Cell_handle c = circ;
if(!positive_orientation_after_edge_split(e, c, m, c3t3))
{
const std::optional<Point> steiner = construct_steiner_point(e, c3t3);
if (steiner != std::nullopt)
{
m = *steiner;
steiner_point_found = true;
}
else
return Vertex_handle();
}
++circ;
}
while (circ != end);
if (dimension == 1)
c3t3.remove_from_complex(e);
for(Cell_handle c : inc_cells)
{
const int index_v1 = c->index(v1);
@ -311,6 +387,9 @@ void split_long_edges(C3T3& c3t3,
#ifdef CGAL_TETRAHEDRAL_REMESHING_DEBUG
debug::dump_edges(long_edges, "long_edges.polylines.txt");
std::ofstream can_be_split_ofs("can_be_split_edges.polylines.txt");
std::ofstream split_failed_ofs("split_failed.polylines.txt");
std::ofstream ofs("midpoints.off");
ofs << "OFF" << std::endl;
ofs << long_edges.size() << " 0 0" << std::endl;
@ -335,7 +414,11 @@ void split_long_edges(C3T3& c3t3,
auto [splittable, _] = can_be_split(edge, c3t3, protect_boundaries, cell_selector);
if (!splittable)
continue;
#ifdef CGAL_TETRAHEDRAL_REMESHING_DEBUG
else
can_be_split_ofs << "2 " << edge.first->vertex(edge.second)->point()
<< " " << edge.first->vertex(edge.third)->point() << std::endl;
#endif
visitor.before_split(tr, edge);
Vertex_handle vh = split_edge(edge, cell_selector, c3t3);
@ -343,6 +426,9 @@ void split_long_edges(C3T3& c3t3,
visitor.after_split(tr, vh);
#ifdef CGAL_TETRAHEDRAL_REMESHING_DEBUG
else
split_failed_ofs << "2 " << edge.first->vertex(edge.second)->point() << " "
<< edge.first->vertex(edge.third)->point() << std::endl;
if (vh != Vertex_handle())
ofs << vh->point() << std::endl;
#endif
@ -364,8 +450,9 @@ void split_long_edges(C3T3& c3t3,
}//end loop on long_edges
#ifdef CGAL_TETRAHEDRAL_REMESHING_DEBUG
if(ofs.is_open())
ofs.close();
if(can_be_split_ofs.is_open()) can_be_split_ofs.close();
if(split_failed_ofs.is_open()) split_failed_ofs.close();
if(ofs.is_open()) ofs.close();
#endif
#ifdef CGAL_TETRAHEDRAL_REMESHING_VERBOSE