294 lines
9.5 KiB
C
294 lines
9.5 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$
|
||
|
// SPDX-License-Identifier: GPL-3.0+
|
||
|
//
|
||
|
//
|
||
|
// Author(s) : Stephane Tayeb
|
||
|
//
|
||
|
//******************************************************************************
|
||
|
// File Description :
|
||
|
//******************************************************************************
|
||
|
|
||
|
#ifndef CGAL_MESH_3_ODT_MOVE_H
|
||
|
#define CGAL_MESH_3_ODT_MOVE_H
|
||
|
|
||
|
#include <CGAL/license/Mesh_3.h>
|
||
|
|
||
|
#include <CGAL/Mesh_3/config.h>
|
||
|
|
||
|
#include <CGAL/Mesh_3/Uniform_sizing_field.h>
|
||
|
|
||
|
#include <string>
|
||
|
|
||
|
namespace CGAL {
|
||
|
|
||
|
namespace Mesh_3 {
|
||
|
|
||
|
template <typename C3T3,
|
||
|
typename SizingField = Uniform_sizing_field<typename C3T3::Triangulation> >
|
||
|
class Odt_move
|
||
|
{
|
||
|
typedef typename C3T3::Triangulation Tr;
|
||
|
typedef typename Tr::Geom_traits Gt;
|
||
|
|
||
|
typedef typename Tr::Vertex_handle Vertex_handle;
|
||
|
typedef typename Tr::Facet Facet;
|
||
|
typedef typename Tr::Cell_handle Cell_handle;
|
||
|
|
||
|
typedef typename Tr::Bare_point Bare_point;
|
||
|
typedef typename Tr::Weighted_point Weighted_point;
|
||
|
|
||
|
typedef typename std::vector<Facet> Facet_vector;
|
||
|
typedef typename std::vector<Cell_handle> Cell_vector;
|
||
|
|
||
|
typedef typename Gt::FT FT;
|
||
|
typedef typename Gt::Vector_3 Vector_3;
|
||
|
|
||
|
public:
|
||
|
typedef SizingField Sizing_field;
|
||
|
|
||
|
Vector_3 operator()(const Vertex_handle& v,
|
||
|
const Cell_vector& incident_cells,
|
||
|
const C3T3& c3t3,
|
||
|
const Sizing_field& sizing_field = Sizing_field()) const
|
||
|
{
|
||
|
// Don't move edge or corner vertices
|
||
|
if ( c3t3.in_dimension(v) < 2 )
|
||
|
{
|
||
|
return CGAL::NULL_VECTOR;
|
||
|
}
|
||
|
|
||
|
// Compute move
|
||
|
const Tr& tr = c3t3.triangulation();
|
||
|
|
||
|
typename Gt::Construct_point_3 cp = tr.geom_traits().construct_point_3_object();
|
||
|
typename Gt::Construct_vector_3 vector = tr.geom_traits().construct_vector_3_object();
|
||
|
|
||
|
Vector_3 move = CGAL::NULL_VECTOR;
|
||
|
FT sum_volume(0);
|
||
|
|
||
|
for ( typename Cell_vector::const_iterator cit = incident_cells.begin() ;
|
||
|
cit != incident_cells.end() ;
|
||
|
++cit )
|
||
|
{
|
||
|
const Cell_handle& cell = *cit;
|
||
|
|
||
|
// Consider only cells of complex
|
||
|
if ( ! c3t3.is_in_complex(cell) )
|
||
|
continue;
|
||
|
|
||
|
// Get points
|
||
|
Bare_point circumcenter = tr.dual(cell);
|
||
|
|
||
|
// Compute move
|
||
|
const Weighted_point& p = tr.point(cell, cell->index(v));
|
||
|
Vector_3 p_circum = vector(cp(p), circumcenter);
|
||
|
FT volume = volume_quadrature(cell, tr, sizing_field);
|
||
|
|
||
|
move = move + p_circum * volume;
|
||
|
sum_volume += volume;
|
||
|
}
|
||
|
|
||
|
// Add boundary terms if needed
|
||
|
if ( c3t3.in_dimension(v) == 2 )
|
||
|
{
|
||
|
// move = move + (1.0 / 12.0) * move_odt_2D(v, c3t3, sizing_field);
|
||
|
}
|
||
|
|
||
|
if ( FT(0) != sum_volume )
|
||
|
return move/sum_volume;
|
||
|
else
|
||
|
return CGAL::NULL_VECTOR;
|
||
|
}
|
||
|
|
||
|
#if defined(CGAL_MESH_3_OPTIMIZER_VERBOSE) \
|
||
|
|| defined (CGAL_MESH_3_EXPORT_PERFORMANCE_DATA)
|
||
|
static std::string name() { return std::string("Odt"); }
|
||
|
#endif
|
||
|
|
||
|
private:
|
||
|
// 1-point at cell centroid
|
||
|
FT volume_quadrature(const Cell_handle& cell,
|
||
|
const Tr& tr,
|
||
|
const Sizing_field& sizing_field) const
|
||
|
{
|
||
|
typename Gt::Construct_centroid_3 centroid = tr.geom_traits().construct_centroid_3_object();
|
||
|
typename Gt::Compute_volume_3 volume = tr.geom_traits().compute_volume_3_object();
|
||
|
|
||
|
Bare_point c = centroid(tr.tetrahedron(cell));
|
||
|
FT s = sizing_field(c, std::make_pair(cell, true));
|
||
|
CGAL_assertion(!is_zero(s));
|
||
|
|
||
|
// Points of cell are positively oriented
|
||
|
FT abs_volume = volume(tr.tetrahedron(cell));
|
||
|
CGAL_assertion(abs_volume >= 0);
|
||
|
|
||
|
return abs_volume / (s*s*s);
|
||
|
}
|
||
|
|
||
|
// /**
|
||
|
// * @class Is_on_c3t3_boundary
|
||
|
// *
|
||
|
// * A functor which returns false if a facet is on the boundary of c3t3
|
||
|
// */
|
||
|
// class Is_not_on_c3t3_boundary
|
||
|
// {
|
||
|
// public:
|
||
|
// Is_not_on_c3t3_boundary(const C3T3& c3t3) : c3t3_(c3t3) { }
|
||
|
//
|
||
|
// bool operator()(const Facet& f) const
|
||
|
// {
|
||
|
// return ( ! c3t3_.is_in_complex(f) ) ||
|
||
|
// ( c3t3_.is_in_complex(f.first) &&
|
||
|
// c3t3_.is_in_complex(f.first->neighbor(f.second)) );
|
||
|
// }
|
||
|
//
|
||
|
// private:
|
||
|
// const C3T3& c3t3_;
|
||
|
// };
|
||
|
//
|
||
|
// // boundary terms
|
||
|
// Vector_3 move_odt_2D(const Vertex_handle& v,
|
||
|
// const C3T3& c3t3,
|
||
|
// const Sizing_field& sizing_field) const
|
||
|
// {
|
||
|
// // Triangulation
|
||
|
// const Tr& tr = c3t3.triangulation();
|
||
|
//
|
||
|
// // Get boundary facets
|
||
|
// Facet_vector incident_facets;
|
||
|
// tr.finite_incident_facets(v, std::back_inserter(incident_facets));
|
||
|
//
|
||
|
// typename Facet_vector::iterator in_c3t3_incident_end =
|
||
|
// std::remove_if(incident_facets.begin(), incident_facets.end(),
|
||
|
// Is_not_on_c3t3_boundary(c3t3));
|
||
|
//
|
||
|
// // Compute boundary terms
|
||
|
// Vector_3 move = CGAL::NULL_VECTOR;
|
||
|
// for(typename Facet_vector::iterator fit = incident_facets.begin();
|
||
|
// fit != in_c3t3_incident_end;
|
||
|
// ++fit)
|
||
|
// {
|
||
|
// CGAL_assertion(c3t3.is_in_complex(*fit));
|
||
|
//
|
||
|
// // Normal
|
||
|
// FT area = area_quadrature(*fit, tr, sizing_field);
|
||
|
// Vector_3 facet_normal = area * normal_outside(*fit, c3t3);
|
||
|
//
|
||
|
// // Sq length
|
||
|
// FT sq_length_sum = sq_length_facet_quadrature(v, *fit, tr, sizing_field);
|
||
|
//
|
||
|
// // Move
|
||
|
// move = move + sq_length_sum * facet_normal;
|
||
|
// }
|
||
|
//
|
||
|
// return move;
|
||
|
// }
|
||
|
//
|
||
|
// // 1-point at facet centroid
|
||
|
// FT area_quadrature(const Facet& facet,
|
||
|
// const Tr& tr,
|
||
|
// const Sizing_field& sizing_field) const
|
||
|
// {
|
||
|
// typename Gt::Compute_area_3 area = tr.geom_traits().compute_area_3_object();
|
||
|
// typename Gt::Construct_centroid_3 centroid = tr.geom_traits().construct_centroid_3_object();
|
||
|
//
|
||
|
// Bare_point c = centroid(tr.triangle(facet));
|
||
|
// FT s = sizing_field(c, facet.first->vertex(0));
|
||
|
//
|
||
|
// return ( area(tr.triangle(facet)) / (s*s) );
|
||
|
// }
|
||
|
//
|
||
|
// // 1-point at segment midpoint
|
||
|
// FT sq_length_quadrature(const int& vertex_index_1,
|
||
|
// const int& vertex_index_2,
|
||
|
// const Cell_handle cell,
|
||
|
// const Tr& tr,
|
||
|
// const Sizing_field& sizing_field) const
|
||
|
// {
|
||
|
// typename Gt::Construct_point_3 cp = tr.geom_traits().construct_point_3_object();
|
||
|
// typename Gt::Construct_midpoint_3 midpoint = tr.geom_traits().construct_midpoint_3_object();
|
||
|
// typename Gt::Compute_squared_distance_3 sq_distance = tr.geom_traits().compute_squared_distance_3_object();
|
||
|
//
|
||
|
// const Weighted_point& wp1 = tr.point(cell, vertex_index_1);
|
||
|
// const Weighted_point& wp2 = tr.point(cell, vertex_index_2);
|
||
|
// const Bare_point& p1 = cp(wp1);
|
||
|
// const Bare_point& p2 = cp(wp2);
|
||
|
//
|
||
|
// Bare_point c = midpoint(p1, p2);
|
||
|
// FT s = sizing_field(c, cell->vertex(vertex_index_1));
|
||
|
//
|
||
|
// return ( sq_distance(p1, p2) / s );
|
||
|
// }
|
||
|
//
|
||
|
// FT sq_length_facet_quadrature(const Vertex_handle& v,
|
||
|
// const Facet& f,
|
||
|
// const Tr& tr,
|
||
|
// const Sizing_field& sizing_field) const
|
||
|
// {
|
||
|
// // get indices
|
||
|
// const int& vertex_index = f.first->index(v);
|
||
|
// int k1 = (vertex_index+1)&3;
|
||
|
// int k2 = (vertex_index+2)&3;
|
||
|
// int k3 = (vertex_index+3)&3;
|
||
|
//
|
||
|
// if ( k2 == f.second ) { std::swap(k1,k2); }
|
||
|
// else if ( k3 == f.second ) { std::swap(k1,k3); }
|
||
|
//
|
||
|
// // Here k1 is opposite vertex index in f.first, facet vertices indices
|
||
|
// // are (vertex_index,k2,k3)
|
||
|
//
|
||
|
// FT sqd_v2 = sq_length_quadrature(vertex_index, k2, f.first, tr, sizing_field);
|
||
|
// FT sqd_v3 = sq_length_quadrature(vertex_index, k3, f.first, tr, sizing_field);
|
||
|
//
|
||
|
// return (sqd_v2 + sqd_v3);
|
||
|
// }
|
||
|
//
|
||
|
// Vector_3 normal_outside(const Facet& f, const C3T3& c3t3) const
|
||
|
// {
|
||
|
// typename Gt::Construct_point_3 cp = c3t3.triangulation().geom_traits().construct_point_3_object();
|
||
|
// typename Gt::Construct_normal_3 normal = c3t3.triangulation().geom_traits().construct_normal_3_object();
|
||
|
//
|
||
|
// const Cell_handle& cell = f.first;
|
||
|
// const int& i = f.second;
|
||
|
//
|
||
|
// int k1 = (i+1)&3;
|
||
|
// int k2 = (i+2)&3;
|
||
|
// int k3 = (i+3)&3;
|
||
|
//
|
||
|
// // Orient normals to the outside of cell
|
||
|
// if ( (i&1) == 1 )
|
||
|
// std::swap(k1,k2);
|
||
|
//
|
||
|
// // Make sure normals are oriented outside
|
||
|
// if ( ! c3t3.is_in_complex(cell) )
|
||
|
// std::swap(k1,k2);
|
||
|
//
|
||
|
// const Weighted_point& wp1 = c3t3.triangulation().point(cell, k1);
|
||
|
// const Weighted_point& wp2 = c3t3.triangulation().point(cell, k2);
|
||
|
// const Weighted_point& wp3 = c3t3.triangulation().point(cell, k3);
|
||
|
//
|
||
|
// return normal(cp(p1), cp(p2), cp(p3));
|
||
|
// }
|
||
|
};
|
||
|
|
||
|
} // end namespace Mesh_3
|
||
|
|
||
|
} //namespace CGAL
|
||
|
|
||
|
#endif // CGAL_MESH_3_ODT_MOVE_H
|