dust3d/thirdparty/cgal/CGAL-4.13/include/CGAL/Mesh_3/Triangulation_helpers.h

614 lines
19 KiB
C++
Executable File

// Copyright (c) 2009 INRIA Sophia-Antipolis (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$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Stephane Tayeb
//
//******************************************************************************
// File Description :
//******************************************************************************
#ifndef CGAL_MESH_3_TRIANGULATION_HELPERS_H
#define CGAL_MESH_3_TRIANGULATION_HELPERS_H
#include <CGAL/license/Mesh_3.h>
#include <CGAL/enum.h>
#include <CGAL/internal/Has_nested_type_Bare_point.h>
#include <CGAL/Hash_handles_with_or_without_timestamps.h>
#include <boost/mpl/if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/unordered_set.hpp>
#include <boost/utility/enable_if.hpp>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <limits>
#include <utility>
#include <vector>
namespace CGAL {
namespace Mesh_3 {
template<typename Tr>
class Triangulation_helpers
{
typedef typename Tr::Geom_traits Gt;
typedef typename Gt::FT FT;
typedef typename Gt::Vector_3 Vector_3;
// If `Tr` is not a triangulation that has defined Bare_point,
// use Point_3 as defined in the traits class.
typedef typename boost::mpl::eval_if_c<
CGAL::internal::Has_nested_type_Bare_point<Tr>::value,
typename CGAL::internal::Bare_point_type<Tr>,
boost::mpl::identity<typename Gt::Point_3>
>::type Bare_point;
// 'Point' is either a bare point or a weighted point, depending on the triangulation.
// Since 'Triangulation_helpers' can be templated by an unweighted triangulation,
// this is one of the rare cases where we use 'Point'.
typedef typename Tr::Point Point;
typedef typename Tr::Vertex Vertex;
typedef typename Tr::Vertex_handle Vertex_handle;
typedef typename Tr::Cell Cell;
typedef typename Tr::Cell_handle Cell_handle;
typedef typename Tr::Cell_iterator Cell_iterator;
typedef std::vector<Cell_handle> Cell_vector;
/**
* A functor to reset visited flag of each facet of a cell
*/
struct Reset_facet_visited
{
void operator()(const Cell_handle& c) const
{
for ( int i=0; i<4 ; ++i )
c->reset_visited(i);
}
};
/**
* A functor to get the point of a vertex vh, but replacing
* it by m_p when vh == m_vh
*/
struct Point_getter
{
/// When the requested will be about vh, the returned point will be p
/// instead of vh->point()
Point_getter(const Vertex_handle &vh, const Point&p)
: m_vh(vh), m_p(p)
{}
const Point& operator()(const Vertex_handle &vh) const
{
return (vh == m_vh ? m_p : vh->point());
}
private:
const Vertex_handle m_vh;
const Point &m_p;
};
public:
/// Constructor / Destructor
Triangulation_helpers() {}
~Triangulation_helpers() {}
/**
* Returns true if moving \c v to \c p makes no topological
* change in \c tr
*/
bool no_topological_change(Tr& tr,
const Vertex_handle v,
const Vector_3& move,
const Point& p,
Cell_vector& cells_tos) const;
bool no_topological_change__without_set_point(
const Tr& tr,
const Vertex_handle v,
const Point& p,
Cell_vector& cells_tos) const;
bool no_topological_change(Tr& tr,
const Vertex_handle v,
const Vector_3& move,
const Point& p) const;
bool no_topological_change__without_set_point(
const Tr& tr,
const Vertex_handle v,
const Point& p) const;
bool inside_protecting_balls(const Tr& tr,
const Vertex_handle v,
const Bare_point& p) const;
/**
* Returns the squared distance from \c vh to its closest vertex
*
* \pre `vh` is not the infinite vertex
*/
template<typename Tag> // Two versions to distinguish using 'Has_visited_for_vertex_extractor'
FT get_sq_distance_to_closest_vertex(const Tr& tr,
const Vertex_handle& vh,
const Cell_vector& incident_cells,
typename boost::enable_if_c<Tag::value>::type* = NULL) const;
// @todo are the two versions really worth it, I can't tell the difference from a time POV...
template<typename Tag>
FT get_sq_distance_to_closest_vertex(const Tr& tr,
const Vertex_handle& vh,
const Cell_vector& incident_cells,
typename boost::disable_if_c<Tag::value>::type* = NULL) const;
private:
/**
* Returns true if \c v is well_oriented on each cell of \c cell_tos
*/
// For sequential version
bool well_oriented(const Tr& tr,
const Cell_vector& cell_tos) const;
// For parallel version
bool well_oriented(const Tr& tr,
const Cell_vector& cell_tos,
const Point_getter& pg) const;
};
template<typename Tr>
bool
Triangulation_helpers<Tr>::
no_topological_change(Tr& tr,
const Vertex_handle v0,
const Vector_3& move,
const Point& p,
Cell_vector& cells_tos) const
{
if(tr.point(v0) == p)
return true;
// For periodic triangulations, calling this function actually takes longer than
// just removing and re-inserting the point directly because the periodic mesh
// triangulation's side_of_power_sphere() function is somewhat brute-forcy:
// it has to check for 27 copies of the query point to determine correctly the side.
// Thus, we simply return 'false' if the triangulation is a periodic triangulation.
//
// Note that the function was nevertheless adapted to work with periodic triangulation
// so this hack can be disabled if one day 'side_of_power_sphere()' is improved.
if(boost::is_same<typename Tr::Periodic_tag, Tag_true>::value)
return false;
typename Gt::Construct_opposite_vector_3 cov =
tr.geom_traits().construct_opposite_vector_3_object();
bool np = true;
const Point fp = tr.point(v0);
// move the point
tr.set_point(v0, move, p);
if(!well_oriented(tr, cells_tos))
{
// Reset (restore) v0
tr.set_point(v0, cov(move), fp);
return false;
}
// Reset visited tags of facets
std::for_each(cells_tos.begin(), cells_tos.end(), Reset_facet_visited());
for ( typename Cell_vector::iterator cit = cells_tos.begin() ;
cit != cells_tos.end() ;
++cit )
{
Cell_handle c = *cit;
for(int j=0; j<4; j++)
{
// Treat each facet only once
if(c->is_facet_visited(j))
continue;
// Set facet and its mirrored version as visited
Cell_handle cj = c->neighbor(j);
int mj = tr.mirror_index(c, j);
c->set_facet_visited(j);
cj->set_facet_visited(mj);
if(tr.is_infinite(c->vertex(j)))
{
if(tr.side_of_power_sphere(c, tr.point(cj->vertex(mj)), false)
!= CGAL::ON_UNBOUNDED_SIDE)
{
np = false;
break;
}
}
else
{
if(tr.side_of_power_sphere(cj, tr.point(c->vertex(j)), false)
!= CGAL::ON_UNBOUNDED_SIDE)
{
np = false;
break;
}
}
}
}
// Reset (restore) v0
tr.set_point(v0, cov(move), fp);
return np;
}
template<typename Tr>
bool
Triangulation_helpers<Tr>::
no_topological_change__without_set_point(
const Tr& tr,
const Vertex_handle v0,
const Point& p,
Cell_vector& cells_tos) const
{
bool np = true;
Point_getter pg(v0, p);
if(!well_oriented(tr, cells_tos, pg))
{
return false;
}
// Reset visited tags of facets
std::for_each(cells_tos.begin(), cells_tos.end(), Reset_facet_visited());
for ( typename Cell_vector::iterator cit = cells_tos.begin() ;
cit != cells_tos.end() ;
++cit )
{
Cell_handle c = *cit;
for(int j=0; j<4; j++)
{
// Treat each facet only once
if(c->is_facet_visited(j))
continue;
// Set facet and it's mirror's one visited
Cell_handle cj = c->neighbor(j);
int mj = tr.mirror_index(c, j);
c->set_facet_visited(j);
cj->set_facet_visited(mj);
Vertex_handle v1 = c->vertex(j);
if(tr.is_infinite(v1))
{
// Build a copy of c, and replace V0 by a temporary vertex (position "p")
typename Cell_handle::value_type c_copy (*c);
int i_v0;
typename Vertex_handle::value_type v;
if (c_copy.has_vertex(v0, i_v0))
{
v.set_point(p);
c_copy.set_vertex(i_v0,
Tr::Triangulation_data_structure::Vertex_range::s_iterator_to(v));
}
Cell_handle c_copy_h =
Tr::Triangulation_data_structure::Cell_range::s_iterator_to(c_copy);
if(tr.side_of_power_sphere(c_copy_h, pg(cj->vertex(mj)), false)
!= CGAL::ON_UNBOUNDED_SIDE)
{
np = false;
break;
}
}
else
{
// Build a copy of cj, and replace V0 by a temporary vertex (position "p")
typename Cell_handle::value_type cj_copy (*cj);
int i_v0;
typename Vertex_handle::value_type v;
if (cj_copy.has_vertex(v0, i_v0))
{
v.set_point(p);
cj_copy.set_vertex(i_v0,
Tr::Triangulation_data_structure::Vertex_range::s_iterator_to(v));
}
Cell_handle cj_copy_h =
Tr::Triangulation_data_structure::Cell_range::s_iterator_to(cj_copy);
if(tr.side_of_power_sphere(cj_copy_h, pg(v1), false)
!= CGAL::ON_UNBOUNDED_SIDE)
{
np = false;
break;
}
}
}
}
return np;
}
template<typename Tr>
bool
Triangulation_helpers<Tr>::
no_topological_change(Tr& tr,
const Vertex_handle v0,
const Vector_3& move,
const Point& p) const
{
Cell_vector cells_tos;
cells_tos.reserve(64);
tr.incident_cells(v0, std::back_inserter(cells_tos));
return no_topological_change(tr, v0, move, p, cells_tos);
}
template<typename Tr>
bool
Triangulation_helpers<Tr>::
no_topological_change__without_set_point(
const Tr& tr,
const Vertex_handle v0,
const Point& p) const
{
Cell_vector cells_tos;
cells_tos.reserve(64);
tr.incident_cells(v0, std::back_inserter(cells_tos));
return no_topological_change__without_set_point(tr, v0, p, cells_tos);
}
template<typename Tr>
bool
Triangulation_helpers<Tr>::
inside_protecting_balls(const Tr& tr,
const Vertex_handle v,
const Bare_point& p) const
{
typename Gt::Compare_weighted_squared_radius_3 cwsr =
tr.geom_traits().compare_weighted_squared_radius_3_object();
Vertex_handle nv = tr.nearest_power_vertex(p, v->cell());
const Point& nvwp = tr.point(nv);
if(cwsr(nvwp, FT(0)) == CGAL::SMALLER)
{
typename Tr::Geom_traits::Construct_point_3 cp = tr.geom_traits().construct_point_3_object();
const Point& nvwp = tr.point(nv);
// 'true' if the distance between 'p' and 'nv' is smaller or equal than the weight of 'nv'
return (cwsr(nvwp , - tr.min_squared_distance(p, cp(nvwp))) != CGAL::LARGER);
}
return false;
}
/// Return the squared distance from vh to its closest vertex
/// if `Has_visited_for_vertex_extractor` is `true`
template<typename Tr>
template<typename Tag>
typename Triangulation_helpers<Tr>::FT
Triangulation_helpers<Tr>::
get_sq_distance_to_closest_vertex(const Tr& tr,
const Vertex_handle& vh,
const Cell_vector& incident_cells,
typename boost::enable_if_c<Tag::value>::type*) const
{
CGAL_precondition(!tr.is_infinite(vh));
typedef std::vector<Vertex_handle> Vertex_container;
// There is no need to use tr.min_squared_distance() here because we are computing
// distances between 'v' and a neighbor within their common cell, which means
// that even if we are using a periodic triangulation, the distance is correctly computed.
typename Gt::Compute_squared_distance_3 csqd = tr.geom_traits().compute_squared_distance_3_object();
typename Gt::Construct_point_3 cp = tr.geom_traits().construct_point_3_object();
Vertex_container treated_vertices;
FT min_sq_dist = std::numeric_limits<FT>::infinity();
for(typename Cell_vector::const_iterator cit = incident_cells.begin();
cit != incident_cells.end(); ++cit)
{
const Cell_handle c = (*cit);
const int k = (*cit)->index(vh);
const Point& wpvh = tr.point(c, k);
// For each vertex of the cell
for(int i=1; i<4; ++i)
{
const int n = (k+i)&3;
const Vertex_handle& vn = c->vertex(n);
if(vn == Vertex_handle() ||
tr.is_infinite(vn) ||
vn->visited_for_vertex_extractor)
continue;
vn->visited_for_vertex_extractor = true;
treated_vertices.push_back(vn);
const Point& wpvn = tr.point(c, n);
const FT sq_d = csqd(cp(wpvh), cp(wpvn));
if(sq_d < min_sq_dist)
min_sq_dist = sq_d;
}
}
for(std::size_t i=0; i < treated_vertices.size(); ++i)
treated_vertices[i]->visited_for_vertex_extractor = false;
return min_sq_dist;
}
/// Return the squared distance from vh to its closest vertex
/// if `Has_visited_for_vertex_extractor` is `false`
template<typename Tr>
template<typename Tag>
typename Triangulation_helpers<Tr>::FT
Triangulation_helpers<Tr>::
get_sq_distance_to_closest_vertex(const Tr& tr,
const Vertex_handle& vh,
const Cell_vector& incident_cells,
typename boost::disable_if_c<Tag::value>::type*) const
{
CGAL_precondition(!tr.is_infinite(vh));
typedef CGAL::Hash_handles_with_or_without_timestamps Hash_fct;
typedef boost::unordered_set<Vertex_handle, Hash_fct> Vertex_container;
typedef typename Vertex_container::iterator VC_it;
// There is no need to use tr.min_squared_distance() here because we are computing
// distances between 'v' and a neighbor within their common cell, which means
// that even if we are using a periodic triangulation, the distance is correctly computed.
typename Gt::Compute_squared_distance_3 csqd = tr.geom_traits().compute_squared_distance_3_object();
typename Gt::Construct_point_3 cp = tr.geom_traits().construct_point_3_object();
Vertex_container treated_vertices;
FT min_sq_dist = std::numeric_limits<FT>::infinity();
for(typename Cell_vector::const_iterator cit = incident_cells.begin();
cit != incident_cells.end(); ++cit)
{
const Cell_handle c = (*cit);
const int k = (*cit)->index(vh);
const Point& wpvh = tr.point(c, k);
// For each vertex of the cell
for(int i=1; i<4; ++i)
{
const int n = (k+i)&3;
const Vertex_handle& vn = c->vertex(n);
if(vn == Vertex_handle() ||
tr.is_infinite(vn))
continue;
std::pair<VC_it, bool> is_insert_succesful = treated_vertices.insert(vn);
if(! is_insert_succesful.second) // vertex has already been treated
continue;
const Point& wpvn = tr.point(c, n);
const FT sq_d = csqd(cp(wpvh), cp(wpvn));
if(sq_d < min_sq_dist)
min_sq_dist = sq_d;
}
}
return min_sq_dist;
}
/// This function well_oriented is called by no_topological_change after the
/// position of the vertex has been (tentatively) modified.
template<typename Tr>
bool
Triangulation_helpers<Tr>::
well_oriented(const Tr& tr,
const Cell_vector& cells_tos) const
{
typedef typename Tr::Geom_traits Gt;
typename Gt::Orientation_3 orientation = tr.geom_traits().orientation_3_object();
typename Gt::Construct_point_3 cp = tr.geom_traits().construct_point_3_object();
typename Cell_vector::const_iterator it = cells_tos.begin();
for( ; it != cells_tos.end() ; ++it)
{
Cell_handle c = *it;
if( tr.is_infinite(c) )
{
int iv = c->index(tr.infinite_vertex());
Cell_handle cj = c->neighbor(iv);
int mj = tr.mirror_index(c, iv);
const Point& mjwp = tr.point(cj, mj);
const Point& fwp1 = tr.point(c, (iv+1)&3);
const Point& fwp2 = tr.point(c, (iv+2)&3);
const Point& fwp3 = tr.point(c, (iv+3)&3);
if(orientation(cp(mjwp), cp(fwp1), cp(fwp2), cp(fwp3)) != CGAL::NEGATIVE)
return false;
}
else
{
const Point& cwp0 = tr.point(c, 0);
const Point& cwp1 = tr.point(c, 1);
const Point& cwp2 = tr.point(c, 2);
const Point& cwp3 = tr.point(c, 3);
if(orientation(cp(cwp0), cp(cwp1), cp(cwp2), cp(cwp3)) != CGAL::POSITIVE)
return false;
}
}
return true;
}
/// Another version for the parallel version
/// Here, the set_point is not done before, but we use a Point_getter instance
/// to get the point of a vertex.
template<typename Tr>
bool
Triangulation_helpers<Tr>::
well_oriented(const Tr& tr,
const Cell_vector& cells_tos,
const Point_getter& pg) const
{
typedef typename Tr::Geom_traits Gt;
typename Gt::Orientation_3 orientation = tr.geom_traits().orientation_3_object();
typename Gt::Construct_point_3 cp = tr.geom_traits().construct_point_3_object();
typename Cell_vector::const_iterator it = cells_tos.begin();
for( ; it != cells_tos.end() ; ++it)
{
Cell_handle c = *it;
if( tr.is_infinite(c) )
{
int iv = c->index(tr.infinite_vertex());
Cell_handle cj = c->neighbor(iv);
int mj = tr.mirror_index(c, iv);
if(orientation(cp(pg(cj->vertex(mj))),
cp(pg(c->vertex((iv+1)&3))),
cp(pg(c->vertex((iv+2)&3))),
cp(pg(c->vertex((iv+3)&3)))) != CGAL::NEGATIVE)
return false;
}
else if(orientation(cp(pg(c->vertex(0))),
cp(pg(c->vertex(1))),
cp(pg(c->vertex(2))),
cp(pg(c->vertex(3)))) != CGAL::POSITIVE)
return false;
}
return true;
}
} // end namespace Mesh_3
} //namespace CGAL
#endif // CGAL_MESH_3_TRIANGULATION_HELPERS_H