cgal/Mesh_3/include/CGAL/Mesh_3/Triangulation_helpers.h

428 lines
11 KiB
C++

// 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$
//
//
// 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 <vector>
#include <CGAL/squared_distance_3.h>
namespace CGAL {
namespace Mesh_3 {
template<typename Tr>
class Triangulation_helpers
{
typedef typename Tr::Geom_traits Gt;
typedef typename Gt::Point_3 Point_3;
typedef typename Tr::Vertex_handle Vertex_handle;
typedef typename Tr::Cell_handle Cell_handle;
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_3&p)
: m_vh(vh), m_p(p)
{}
const Point_3& operator()(const Vertex_handle &vh) const
{
return (vh == m_vh ? m_p : vh->point());
}
private:
const Vertex_handle m_vh;
const Point_3 &m_p;
};
public:
/// Constructor / Destructor
Triangulation_helpers() {}
~Triangulation_helpers() {}
/**
* Moves point from \c v to \c p.
*/
void move_point(Tr& tr,
const Vertex_handle& v,
const Point_3& p) const;
/**
* Returns true if moving \c v to \c p makes no topological
* change in \c tr
*/
bool no_topological_change(const Tr& tr,
const Vertex_handle& v,
const Point_3& p,
Cell_vector& cells_tos) const;
bool no_topological_change__without_set_point(
const Tr& tr,
const Vertex_handle& v,
const Point_3& p,
Cell_vector& cells_tos) const;
bool no_topological_change(const Tr& tr,
const Vertex_handle& v,
const Point_3& p) const;
bool no_topological_change__without_set_point(
const Tr& tr,
const Vertex_handle& v,
const Point_3& p) const;
bool inside_protecting_balls(const Tr& tr,
const Vertex_handle& v,
const Point_3& p) 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>
void
Triangulation_helpers<Tr>::
move_point(Tr& tr,
const Vertex_handle& v,
const Point_3& p) const
{
if ( no_topological_change(tr, v, p) )
v->set_point(p);
else
{
tr.insert(p);
tr.remove(v);
}
}
template<typename Tr>
bool
Triangulation_helpers<Tr>::
no_topological_change(const Tr& tr,
const Vertex_handle& v0,
const Point_3& p,
Cell_vector& cells_tos) const
{
bool np = true;
Point_3 fp = v0->point();
v0->set_point(p);
if(!well_oriented(tr, cells_tos))
{
// Reset (restore) v0
v0->set_point(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 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))
{
if(tr.side_of_power_sphere(c, cj->vertex(mj)->point(), false)
!= CGAL::ON_UNBOUNDED_SIDE)
{
np = false;
break;
}
}
else
{
if(tr.side_of_power_sphere(cj, v1->point(), false)
!= CGAL::ON_UNBOUNDED_SIDE)
{
np = false;
break;
}
}
}
}
// Reset (restore) v0
v0->set_point(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_3& 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(const Tr& tr,
const Vertex_handle& v0,
const Point_3& 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, 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_3& 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 Point_3& p) const
{
Vertex_handle nv = tr.nearest_power_vertex(p, v->cell());
if(nv->point().weight() > 0)
return Gt().compare_squared_distance_3_object()(p, nv->point(),
nv->point().weight()) != CGAL::LARGER;
return false;
}
/// This function well_oriented is called by no_topological_change after a
/// v->set_point(p)
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 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(cj->vertex(mj)->point(),
c->vertex((iv+1)&3)->point(),
c->vertex((iv+2)&3)->point(),
c->vertex((iv+3)&3)->point()) != CGAL::NEGATIVE)
return false;
}
else if(orientation(c->vertex(0)->point(),
c->vertex(1)->point(),
c->vertex(2)->point(),
c->vertex(3)->point()) != 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 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(pg(cj->vertex(mj)),
pg(c->vertex((iv+1)&3)),
pg(c->vertex((iv+2)&3)),
pg(c->vertex((iv+3)&3))) != CGAL::NEGATIVE)
return false;
}
else if(orientation(pg(c->vertex(0)),
pg(c->vertex(1)),
pg(c->vertex(2)),
pg(c->vertex(3))) != CGAL::POSITIVE)
return false;
}
return true;
}
} // end namespace Mesh_3
} //namespace CGAL
#endif // CGAL_MESH_3_TRIANGULATION_HELPERS_H