Merge remote-tracking branch 'cgal/master' into PMP-decimation

This commit is contained in:
Sébastien Loriot 2023-04-04 14:25:17 +02:00
commit cb672d4d90
103 changed files with 11050 additions and 458 deletions

View File

@ -0,0 +1,30 @@
table {
margin-left: auto;
margin-right: auto;
margin-bottom: 24px;
border-spacing: 0;
border-bottom: 2px solid black;
border-top: 2px solid black;
}
table th {
padding: 3px 10px;
background-color: white;
border-top: none;
border-left: none;
border-right: none;
border-bottom: 1px solid black;
}
table td {
padding: 3px 10px;
border-top: none;
border-left: none;
border-bottom: none;
border-right: none;
}
table tr.odd {
background-color: #f0f0f0;
}
table tr.even {
background-color: #e0e0e0;
}

View File

@ -0,0 +1,43 @@
name: List workflow last run
on:
workflow_dispatch:
schedule:
- cron: "0 10 * * 1"
env:
GH_TOKEN: ${{ github.token }}
jobs:
list_workflow:
runs-on: ubuntu-latest
outputs:
messages: ${{ steps.cat_output.outputs.message }}
steps:
- name: checkout
uses: actions/checkout@v3
- name: run script
run: |
chmod +x ./Scripts/developer_scripts/list_cgal_workflows_last_run.sh
./Scripts/developer_scripts/list_cgal_workflows_last_run.sh > output.md
- name: convert markdown to html
run: |
sudo apt-get update && sudo apt-get install -y pandoc
pandoc -f markdown -t html --self-contained --css=.github/workflows/list_workflow_last_run.css -o output.html output.md
- name: set_output
id: cat_output
run: |
delimiter="$(openssl rand -hex 8)"
echo "message<<${delimiter}" >> "${GITHUB_OUTPUT}"
echo "Subject:List workflow run \nContent-Type: text/html; charset=\"UTF-8\"\n" >> "${GITHUB_OUTPUT}"
echo "<html><body>" >> "${GITHUB_OUTPUT}"
cat output.html >> "${GITHUB_OUTPUT}"
echo "</body></html>" >> "${GITHUB_OUTPUT}"
echo "${delimiter}" >> "${GITHUB_OUTPUT}"
call_send_email:
needs: list_workflow
uses: ./.github/workflows/send_email.yml
with:
message: ${{needs.list_workflow.outputs.messages}}
secrets:
email: ${{ secrets.CGAL_SEND_WORKFLOW_LIST_EMAIL_TO }}
private_key: ${{ secrets.CGAL_SEND_WORKFLOW_LIST_EMAIL_SSH_PRIVATE_KEY }}
user: ${{ secrets.CGAL_SEND_WORKFLOW_LIST_EMAIL_SSH_USER }}
host: ${{ secrets.CGAL_SEND_WORKFLOW_LIST_EMAIL_SSH_HOST }}

View File

@ -28,4 +28,4 @@ jobs:
ssh-keyscan -H ${{ secrets.host }} > ~/.ssh/known_hosts
- name: send email via ssh
run: |
echo "${{ inputs.message }}" | ssh ${{ secrets.user }}@${{ secrets.host }} "/sbin/sendmail -t ${{ secrets.email }}"
echo -e '${{ inputs.message }}' | ssh ${{ secrets.user }}@${{ secrets.host }} "/sbin/sendmail -t ${{ secrets.email }}"

View File

@ -85,18 +85,17 @@ public:
typedef Arr_counting_traits_2<Base> Self;
/*! Construct default */
Arr_counting_traits_2() : Base()
template<typename ... Args>
Arr_counting_traits_2(Args ... args) :
Base(args...)
{
clear_counters();
increment();
}
/*! Construct copy */
Arr_counting_traits_2(const Arr_counting_traits_2& other) : Base(other)
{
clear_counters();
increment();
}
/*! Disable copy constructor.
*/
Arr_counting_traits_2(const Arr_counting_traits_2&) = delete;
/*! Obtain the counter of the given operation */
size_t count(Operation_id id) const

View File

@ -272,6 +272,21 @@ before_handle_event(Event* event)
if (m_prev_minus_inf_x_event != nullptr)
m_prev_minus_inf_x_event->set_halfedge_handle(m_lh->next());
m_prev_minus_inf_x_event = event;
// If the event lies also on the top boundary, associate all curve indices
// of subcurves that "see" m_th from below with the top fictitious halfedge
// (m_th->next()).
if (ps_y == ARR_TOP_BOUNDARY) {
if (m_he_ind_map_p != nullptr) {
Indices_list& list_ref = (*m_he_ind_map_p)[m_th];
list_ref.clear();
list_ref.splice(list_ref.end(), m_subcurves_at_ubf);
}
else {
m_subcurves_at_ubf.clear();
}
CGAL_assertion(m_subcurves_at_ubf.empty());
}
return;
case ARR_RIGHT_BOUNDARY:

View File

@ -162,13 +162,18 @@ private:
{ return m_flags & (0x1 << COMPARE_X_NEAR_BOUNDARY_OP); }
public:
/*! Default constructor */
Arr_tracing_traits_2() :
Base()
/*! Construct default */
template<typename ... Args>
Arr_tracing_traits_2(Args ... args) :
Base(args...)
{
enable_all_traces();
}
/*! Disable copy constructor.
*/
Arr_tracing_traits_2(const Arr_tracing_traits_2&) = delete;
/*! Enable the trace of a traits operation
* \param id the operation identifier
*/
@ -650,13 +655,13 @@ public:
/*! A functor that tests whether two x-monotone curves can be merged. */
class Are_mergeable_2 {
private:
typename Base::Are_mergeable_2 m_object;
const Base& m_base_traits;
bool m_enabled;
public:
/*! Construct */
Are_mergeable_2(const Base* base, bool enabled = true) :
m_object(base->are_mergeable_2_object()), m_enabled(enabled) {}
Are_mergeable_2(const Base& base, bool enabled = true) :
m_base_traits(base), m_enabled(enabled) {}
/*! Operate
* \param xcv1 the first curve
@ -667,14 +672,32 @@ public:
*/
bool operator()(const X_monotone_curve_2& xcv1,
const X_monotone_curve_2& xcv2) const
{
if (!m_enabled) return m_object(xcv1, xcv2);
{ return are_mergable_2_impl<Base>(xcv1, xcv2, 0); }
private:
/*! The base does not have Are_mergable_2
*/
template <typename T>
bool are_mergable_2_impl(const X_monotone_curve_2& /* xcv1 */,
const X_monotone_curve_2& /* xcv2 */, long) const {
CGAL_error();
return false;
}
/*! The base does have Are_mergable_2
*/
template <typename T>
auto are_mergable_2_impl(const X_monotone_curve_2& xcv1,
const X_monotone_curve_2& xcv2, int) const ->
decltype(m_base_traits.are_mergeable_2_object().operator()(xcv1, xcv2)) {
auto are_mergeable = m_base_traits.are_mergeable_2_object();
if (! m_enabled) return are_mergeable(xcv1, xcv2);
std::cout << "are_mergeable" << std::endl
<< " xcv1: " << xcv1 << std::endl
<< " xcv2: " << xcv2 << std::endl;
bool are_mergeable = m_object(xcv1, xcv2);
std::cout << " result: " << are_mergeable << std::endl;
return are_mergeable;
bool mergeable = are_mergeable(xcv1, xcv2);
std::cout << " result: " << mergeable << std::endl;
return mergeable;
}
};

View File

@ -3387,7 +3387,7 @@ public:
*/
Comparison_result operator()(const Point_2& p1, const Point_2& p2) const
{
Base base(m_self);
const Base& base = m_self;
return base.compare_xy_2_object()(p1, p2);
}

View File

@ -549,56 +549,56 @@ public:
typedef typename Base::Face_const_handle Face_const_handle;
/*! Default constructor.*/
Arr_extended_dcel_text_formatter() :
Base()
{}
Arr_extended_dcel_text_formatter() : Base() {}
/*! Construct an output formatter. */
Arr_extended_dcel_text_formatter(std::ostream& os) :
Base(os)
{}
Arr_extended_dcel_text_formatter(std::ostream& os) : Base(os) {}
/*! Construct an input formatter. */
Arr_extended_dcel_text_formatter(std::istream& is) :
Base(is)
{}
Arr_extended_dcel_text_formatter(std::istream& is) : Base(is) {}
/*! Write the auxiliary data associated with the given vertex. */
virtual void write_vertex_data(Vertex_const_handle v)
{
this->out() << '\n' << v->data();
}
{ this->out() << '\n' << v->data(); }
/*! Read a vertex-data object and attach it to the given vertex. */
virtual void read_vertex_data(Vertex_handle v)
{
this->in() >> v->data();
virtual void read_vertex_data(Vertex_handle v) {
using Vertex = typename Arrangement_2::Vertex;
using Type = decltype(std::declval<Vertex>().data());
using Data_type = typename std::remove_reference<Type>::type;
Data_type data;
this->in() >> data;
v->set_data(data);
this->_skip_until_EOL();
}
/*! Write the auxiliary data associated with the given halfedge. */
virtual void write_halfedge_data(Halfedge_const_handle he)
{
this->out() << '\n' << he->data();
}
{ this->out() << '\n' << he->data(); }
/*! Read a halfedge-data object and attach it to the given halfedge. */
virtual void read_halfedge_data(Halfedge_handle he)
{
this->in() >> he->data();
virtual void read_halfedge_data(Halfedge_handle he) {
using Halfedge = typename Arrangement_2::Halfedge;
using Type = decltype(std::declval<Halfedge>().data());
using Data_type = typename std::remove_reference<Type>::type;
Data_type data;
this->in() >> data;
he->set_data(data);
this->_skip_until_EOL();
}
/*! Write the auxiliary data associated with the given face. */
virtual void write_face_data(Face_const_handle f)
{
this->out() << f->data() << '\n';
}
{ this->out() << f->data() << '\n'; }
/*! Read a face-data object and attach it to the given face. */
virtual void read_face_data(Face_handle f)
{
this->in() >> f->data();
virtual void read_face_data(Face_handle f) {
using Face = typename Arrangement_2::Face;
using Type = decltype(std::declval<Face>().data());
using Data_type = typename std::remove_reference<Type>::type;
Data_type data;
this->in() >> data;
f->set_data(data);
this->_skip_until_EOL();
}
};

View File

@ -706,6 +706,7 @@ user might encounter.
- `CGAL::Halfedge_around_target_circulator`
- `CGAL::Halfedge_around_face_circulator`
- `CGAL::Vertex_around_target_circulator`
- `CGAL::Vertex_around_face_circulator`
- `CGAL::Face_around_target_circulator`
- `CGAL::Face_around_face_circulator`

View File

@ -201,6 +201,13 @@ bool read_polygon_mesh(const std::string& fname,
* \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.}
* \cgalParamNEnd
*
* \cgalParamNBegin{use_binary_mode}
* \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)}
* \cgalParamType{Boolean}
* \cgalParamDefault{`true`}
* \cgalParamExtra{This parameter is only meaningful for formats that support binary encoding.}
* \cgalParamNEnd
*
* \cgalParamNBegin{verbose}
* \cgalParamDescription{whether extra information is printed when an incident occurs during reading}
* \cgalParamType{Boolean}

View File

@ -980,6 +980,12 @@ faces_around_face(typename boost::graph_traits<Graph>::halfedge_descriptor h, co
return make_range(I(h,g), I(h,g,1));
}
/**
* \ingroup PkgBGLIterators
* A bidirectional circulator with value type `boost::graph_traits<Graph>::%vertex_descriptor` over all vertices incident to the same face or border.
* \tparam Graph must be a model of the concept `HalfedgeGraph`
* \cgalModels `BidirectionalIterator`
*/
template <typename Graph>
class Vertex_around_face_circulator
#ifndef DOXYGEN_RUNNING

View File

@ -1,17 +1 @@
ETH Zurich (Switzerland).
Min_quadrilateral_2
Min_sphere_of_spheres_d
Matrix_search
Approximate_min_ellipsoid_d
Min_ellipse_2
Min_circle_2
Min_sphere_d
Min_annulus_d
Min_quadrilateral_2
Min_sphere_of_spheres_d
Matrix_search
Approximate_min_ellipsoid_d
Min_ellipse_2
Min_circle_2
Min_sphere_d
Min_annulus_d
ETH Zurich (Switzerland).

View File

@ -20,7 +20,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <boost/cstdint.hpp> // for uint32_t, etc.
#include <cstdint> // for uint32_t, etc.
#ifdef CGAL_USE_ZLIB
#include <zlib.h>
@ -562,38 +562,50 @@ struct Word_type_generator<WK_FLOAT, sign, 8>
template <>
struct Word_type_generator<WK_FIXED, SGN_SIGNED, 1>
{
// typedef boost::int8_t type;
// typedef std::int8_t type;
typedef char type;
};
template <>
struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 1>
{
typedef boost::uint8_t type;
typedef std::uint8_t type;
};
template <>
struct Word_type_generator<WK_FIXED, SGN_SIGNED, 2>
{
typedef boost::int16_t type;
typedef std::int16_t type;
};
template <>
struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 2>
{
typedef boost::uint16_t type;
typedef std::uint16_t type;
};
template <>
struct Word_type_generator<WK_FIXED, SGN_SIGNED, 4>
{
typedef boost::int32_t type;
typedef std::int32_t type;
};
template <>
struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 4>
{
typedef boost::uint32_t type;
typedef std::uint32_t type;
};
template <>
struct Word_type_generator<WK_FIXED, SGN_SIGNED, 8>
{
typedef std::int64_t type;
};
template <>
struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 8>
{
typedef std::uint64_t type;
};
template <WORD_KIND wordKind, SIGN sign, std::size_t wdim>

View File

@ -0,0 +1 @@
GeometryFactory (France)

View File

@ -566,6 +566,15 @@ void test_split_attribute_functor_one_dart
Attribute_descriptor_i a1 = amap.template attribute<i>(adart);
if ( found_attributes.is_defined(a1) )
{ // Here the attribute was already present in the hash_map
// We need to call reserve for the cc with index case. Indeed, if the vector
// is reallocated, the reference returned by get_attribute<i>(a1) will be
// invalidated, and the copy will be wrong. Note that there is no overhead
// since the creation of the attribute need one allocation.
amap.template attributes<i>().reserve(amap.template attributes<i>().size()+1);
// Now we are sure that the creation of a new attribute will not imply
// a realloc.
Attribute_descriptor_i a2 = amap.template
create_attribute<i>(amap.template get_attribute<i>(a1));

View File

@ -146,6 +146,8 @@ namespace CGAL {
{ return cit; }
bool is_used(size_type i) const
{ return mmap.mdarts.is_used(i); }
bool owns(size_type i) const
{ return mmap.mdarts.owns(i); }
private:
Self & mmap;
};
@ -286,6 +288,13 @@ namespace CGAL {
{
CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0,
"copy_attribute<i> called but i-attributes are disabled.");
// We need to do a reserve before the emplace in order to avoid a bug of
// invalid reference when the container is reallocated.
std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).reserve
(std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).size()+1);
typename Attribute_descriptor<i>::type res=
std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).emplace(get_attribute<i>(ah));

View File

@ -752,6 +752,9 @@ public:
return false;
}
bool owns(size_type i) const
{ return i<capacity() && is_used(i); }
bool owns_dereferenceable(const_iterator cit) const
{ return cit!=end() && owns(cit); }
@ -764,7 +767,6 @@ public:
void reserve(size_type n)
{
if(capacity_>=n) return;
capacity_=n;
increase_size();
}

View File

@ -0,0 +1 @@
CNRS and LIRIS' Establishments (France)

View File

@ -24,6 +24,8 @@ target_compile_definitions(Combinatorial_map_copy_test_index PUBLIC USE_COMPACT_
target_link_libraries(Combinatorial_map_copy_test_index PUBLIC CGAL CGAL::Data)
cgal_add_compilation_test(Combinatorial_map_copy_test_index)
create_single_source_cgal_program(cmap_test_split_attribute.cpp)
# Link with OpenMesh if possible
find_package(OpenMesh QUIET)
if(TARGET OpenMesh::OpenMesh)

View File

@ -0,0 +1,92 @@
#include <CGAL/Combinatorial_map.h>
#include <CGAL/Cell_attribute.h>
#include <vector>
#include <algorithm>
#include <string>
#include <cstdlib>
struct MyInfo
{
MyInfo() :data(1)
{}
MyInfo(int i) :data(i)
{}
int data;
};
struct Myitem1
{
using Use_index=CGAL::Tag_true; // use indices
using Index_type=std::uint16_t; // 16 bits
template<class CMap>
struct Dart_wrapper
{
typedef CGAL::Cell_attribute<CMap, MyInfo> attrib;
typedef std::tuple<void, void, attrib> Attributes;
};
};
struct Myitem2
{
template<class CMap>
struct Dart_wrapper
{
typedef CGAL::Cell_attribute<CMap, MyInfo> attrib;
typedef std::tuple<void, void, attrib> Attributes;
};
};
using CMap1=CGAL::Combinatorial_map<3,Myitem1>;
using CMap2=CGAL::Combinatorial_map<3,Myitem2>;
#define NB 1000
template<typename CMap>
bool test(const std::string& s)
{
bool res=true;
CMap m;
// 1) create a face and one attribute.
typename CMap::Dart_descriptor dd=m.make_combinatorial_polygon(4);
m.template set_attribute<2>(dd, m.template create_attribute<2>(2));
// 2) Split this face NB times => will create new 2-attributes for new faces
for(std::size_t i=0; i<NB; ++i)
{
typename CMap::Dart_descriptor
newd=m.insert_cell_1_in_cell_2(dd, m.next(m.next(dd)));
if(m.template attribute<2>(newd)==CMap::null_descriptor)
{
std::cout<<"ERROR1: "<<s<<": "
<<"attribute<2>(newd)==CMap::null_descriptor"<<std::endl;
res=false;
}
else if(m.template info<2>(newd).data!=2)
{
std::cout<<"ERROR2: "<<s<<": "<<m.template info<2>(newd).data<<std::endl;
res=false;
}
newd=m.template opposite<2>(newd);
if(m.template attribute<2>(newd)==CMap::null_descriptor)
{
std::cout<<"ERROR3: "<<s<<": "
<<"attribute<2>(newd)==CMap::null_descriptor"<<std::endl;
res=false;
}
else if(m.template info<2>(newd).data!=2)
{
std::cout<<"ERROR4: "<<s<<": "<<m.template info<2>(newd).data<<std::endl;
res=false;
}
}
return res;
}
int main()
{
if(!test<CMap1>("CMap1") || !test<CMap2>("CMap2"))
{ return EXIT_FAILURE; }
return EXIT_SUCCESS;
}

View File

@ -3270,6 +3270,14 @@ pages = "207--221"
year={1998}
}
@techreport{cgal:hssz-gmcabonbc-97,
title={A generalized marching cubes algorithm based on non-binary classifications},
author={H-C. Hege and M. Seebass and D. Stalling and M. Zöckler},
number={SC 97-05},
year={1997}
}
% ----------------------------------------------------------------------------
% END OF BIBFILE
% ----------------------------------------------------------------------------

View File

@ -293,6 +293,13 @@ void GMap_test_split_attribute_functor_one_dart
Attribute_descriptor_i a1 = amap.template attribute<i>(adart);
if ( found_attributes.is_defined(a1) )
{ // Here the attribute was already present in the hash_map
// We need to call reserve for the cc with index case. Indeed, if the vector
// is reallocated, the reference returned by get_attribute<i>(a1) will be
// invalidated, and the copy will be wrong. Note that there is no overhead
// since the creation of the attribute need one allocation.
amap.template attributes<i>().reserve(amap.template attributes<i>().size()+1);
Attribute_descriptor_i a2 = amap.template
create_attribute<i>(amap.template get_attribute<i>(a1));

View File

@ -242,6 +242,13 @@ namespace CGAL {
{
CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0,
"copy_attribute<i> called but i-attributes are disabled.");
// We need to do a reserve before the emplace in order to avoid a bug of
// invalid reference when the container is reallocated.
std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).reserve
(std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).size()+1);
typename Attribute_descriptor<i>::type res=
std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).emplace(get_attribute<i>(ah));

View File

@ -0,0 +1 @@
CNRS and LIRIS' Establishments (France)

View File

@ -18,3 +18,5 @@ add_executable(Generalized_map_test_index Generalized_map_test.cpp ${hfiles})
target_compile_definitions(Generalized_map_test_index PUBLIC USE_COMPACT_CONTAINER_WITH_INDEX)
target_link_libraries(Generalized_map_test_index PUBLIC CGAL CGAL::Data)
cgal_add_compilation_test(Generalized_map_test_index)
create_single_source_cgal_program("gmap_test_split_attribute.cpp")

View File

@ -0,0 +1,92 @@
#include <CGAL/Generalized_map.h>
#include <CGAL/Cell_attribute.h>
#include <vector>
#include <algorithm>
#include <string>
#include <cstdlib>
struct MyInfo
{
MyInfo() :data(1)
{}
MyInfo(int i) :data(i)
{}
int data;
};
struct Myitem1
{
using Use_index=CGAL::Tag_true; // use indices
using Index_type=std::uint16_t; // 16 bits
template<class GMap>
struct Dart_wrapper
{
typedef CGAL::Cell_attribute<GMap, MyInfo> attrib;
typedef std::tuple<void, void, attrib> Attributes;
};
};
struct Myitem2
{
template<class GMap>
struct Dart_wrapper
{
typedef CGAL::Cell_attribute<GMap, MyInfo> attrib;
typedef std::tuple<void, void, attrib> Attributes;
};
};
using GMap1=CGAL::Generalized_map<3,Myitem1>;
using GMap2=CGAL::Generalized_map<3,Myitem2>;
#define NB 1000
template<typename GMap>
bool test(const std::string& s)
{
bool res=true;
GMap m;
// 1) create a face and one attribute.
typename GMap::Dart_descriptor dd=m.make_combinatorial_polygon(4);
m.template set_attribute<2>(dd, m.template create_attribute<2>(2));
// 2) Split this face NB times => will create new 2-attributes for new faces
for(std::size_t i=0; i<NB; ++i)
{
typename GMap::Dart_descriptor
newd=m.insert_cell_1_in_cell_2(dd, m.template alpha<0,1,0>(dd));
if(m.template attribute<2>(newd)==GMap::null_descriptor)
{
std::cout<<"ERROR1: "<<s<<": "
<<"attribute<2>(newd)==GMap::null_descriptor"<<std::endl;
res=false;
}
else if(m.template info<2>(newd).data!=2)
{
std::cout<<"ERROR2: "<<s<<": "<<m.template info<2>(newd).data<<std::endl;
res=false;
}
newd=m.template opposite<2>(newd);
if(m.template attribute<2>(newd)==GMap::null_descriptor)
{
std::cout<<"ERROR3: "<<s<<": "
<<"attribute<2>(newd)==GMap::null_descriptor"<<std::endl;
res=false;
}
else if(m.template info<2>(newd).data!=2)
{
std::cout<<"ERROR4: "<<s<<": "<<m.template info<2>(newd).data<<std::endl;
res=false;
}
}
return res;
}
int main()
{
if(!test<GMap1>("GMap1") || !test<GMap2>("GMap2"))
{ return EXIT_FAILURE; }
return EXIT_SUCCESS;
}

View File

@ -189,8 +189,12 @@ void test_point_generators_d()
if (points[i][0] >0)
g = g + (points[i] - o3);
}
assert( std::fabs( g[0]/nb_g - 3.0/16.0) < 0.01 );
std::cout<<" center of mass 3/16~="<<g[0]/nb_g<<" checked"<<std::endl;
if( std::fabs( g[0]/nb_g - 3.0/16.0) < 0.01 ){
std::cout<<" center of mass 3/16~="<<g[0]/nb_g<<" checked"<<std::endl;
}else{
std::cout << "See Law of large numbers" << std::endl;
}
}
{
// 100 random points in dim 26

View File

@ -43,10 +43,19 @@ CGAL tetrahedral Delaunay refinement algorithm.
- Added the functions `CGAL::Polygon_mesh_processing::remesh_planar_patches()` and
`CGAL::Polygon_mesh_processing::remesh_almost_coplanar_patches()` to retriangulate patches of coplanar faces in a mesh.
- Added a named parameter to `CGAL::Polygon_mesh_processing::smooth_shape()` to disable scaling to compensate volume loss.
### [3D Simplicial Mesh Data Structure](https://doc.cgal.org/5.6/Manual/packages.html#PkgSMDS3) (new package)
- This new package wraps all the existing code that deals with a `MeshComplex_3InTriangulation_3` to describe 3D simplicial meshes, and makes the data structure independent from the tetrahedral mesh generation package.
### [Tetrahedral Mesh Generation](https://doc.cgal.org/5.6/Manual/packages.html#PkgMesh3)
- Added two new named parameters to the named constructor `CGAL::create_labeled_image_mesh_domain()`
for automatic detection and protection
of 1D-curves that lie at the intersection of three or more subdomains,
extracted from labeled images.
### [Shape Detection](https://doc.cgal.org/5.6/Manual/packages.html#PkgShapeDetection) (breaking change, major changes)
- **Breaking change**: The region growing part of the package have been reworked to fix design issues introduced with the handling `FaceGraph` models.
@ -68,6 +77,7 @@ CGAL tetrahedral Delaunay refinement algorithm.
and cylinders in 3D.
### [2D Arrangements](https://doc.cgal.org/5.6/Manual/packages.html#PkgArrangementOnSurface2)
- Fixed some code that handles geodesic-curves on spheres that compare x- and y-coordinates on the boundary of the parameter space. It mainly effected the naive point-location.
### [2D Convex Hulls](https://doc.cgal.org/5.6/Manual/packages.html#PkgConvexHull2)

View File

@ -22,4 +22,4 @@ else()
${CMAKE_BINARY_DIR}/icons/Triangulation_2.qrc)
endif()
qt5_wrap_ui(_CGAL_Qt5_UI_FILES ${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/resources/ImageInterface.ui)
qt5_wrap_ui(_CGAL_Qt5_UI_FILES ${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/ImageInterface.ui)

View File

@ -167,6 +167,8 @@ namespace CGAL {
{ return cit; }
bool is_used(size_type i) const
{ return mmap.mdarts.is_used(i); }
bool owns(size_type i) const
{ return mmap.mdarts.owns(i); }
private:
Self & mmap;
};
@ -307,6 +309,13 @@ namespace CGAL {
{
CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0,
"copy_attribute<i> called but i-attributes are disabled.");
// We need to do a reserve before the emplace in order to avoid a bug of
// invalid reference when the container is reallocated.
std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).reserve
(std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).size()+1);
typename Attribute_descriptor<i>::type res=
std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).emplace(get_attribute<i>(ah));

View File

@ -261,6 +261,13 @@ namespace CGAL {
{
CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0,
"copy_attribute<i> called but i-attributes are disabled.");
// We need to do a reserve before the emplace in order to avoid a bug of
// invalid reference when the container is reallocated.
std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).reserve
(std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).size()+1);
typename Attribute_descriptor<i>::type res=
std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).emplace(get_attribute<i>(ah));

View File

@ -0,0 +1 @@
CNRS and LIRIS' Establishments (France)

View File

@ -32,7 +32,7 @@ TD.error {background-color: rgb(100%,50%,50%)}
TD.na {background-color: white;}
TD.requirements { background-color: rgb(65%,65%,100%) }
TD.ok {background-color: rgb(44%,88%,44%)}
TH.ok {background-color: rgb(44%,88%,44%)}
TH.warning {background-color: rgb(100%,100%,50%)}
TH.third_party_warning {background-color: rgb(75%,100%,50%)}
TH.error {background-color: rgb(100%,50%,50%)}

View File

@ -18,7 +18,9 @@ INPUT += \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_facet_topology.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_vertex_base_3.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_cell_base_3.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Compact_mesh_cell_base_3.h
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Compact_mesh_cell_base_3.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_3/Detect_features_in_image.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_3/Detect_features_on_image_bbox.h
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Mesh Generation"
HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/implicit_domain_3.jpg \

View File

@ -735,7 +735,6 @@ Surface of the output mesh generated with a very small `facet_distance`
without the weights (left, 25563 vertices) and with the weights (right, 19936 vertices).
\cgalFigureEnd
\subsubsection Mesh_3DomainsFrom3DImagesWithCustomInitialization Domains From 3D Images, with a Custom Initialization
The example \ref Mesh_3/mesh_3D_image_with_custom_initialization.cpp is a modification
@ -926,23 +925,27 @@ The first modification is the type of the mesh domain. Instead of being
\snippet Mesh_3/mesh_3D_image_with_features.cpp Domain definition
Then, in the function `%main()`, after the `%domain` object has been created,
a dedicated function computes the 1D-features, and adds them to the domain.
In the %main() function, the domain is created with an additional argument - a
dedicated functor that computes the one-dimensional features, which are then
added to the domain.
\snippet Mesh_3/mesh_3D_image_with_features.cpp Call add_1D_features
\snippet Mesh_3/mesh_3D_image_with_detection_of_features.cpp Domain creation
The function template `%add_1D_features()` is defined in the example
file. It uses non-documented code from \cgal, that should be copy-pasted in
any user-code willing to use similar code. It uses the undocumented
function template `%CGAL::polylines_to_protect` that computes the
1D-features that correspond to the intersection of the bounding box of the
image with the surfaces defined by the image. At the same time, a few other
polylines are added as 1D-features, to protect 1D curves in the interior of
the image. Then, the method
`CGAL::Mesh_domain_with_polyline_features_3::add_features` is called twice
to add the computed 1D-features to the mesh domain.
The `CGAL::Mesh_3::Detect_features_in_image` functor is defined in its own
header file. It computes the one-dimensional features that correspond to the
intersections of the bounding box of the image with the surfaces defined by the
image, as well as polylines that lie at the intersection of three or more
subdomains (including the outside). It then constructs a graph of these polyline
features. The named constructor adds this feature graph to the domain for later
feature protection. The original feature detection algorithm was described in
\cgalCite{cgal:hssz-gmcabonbc-97}, which provides a list of possible voxel
configurations. The feature detection implemented in \cgal generalizes this
description.
\snippet Mesh_3/mesh_3D_image_with_features.cpp Add 1D features
The example \ref Mesh_3/mesh_3D_image_with_features.cpp shows how
user-specified input polylines can further be added as 1D features to the mesh domain.
\snippet Mesh_3/mesh_3D_image_with_features.cpp Domain creation
In the meshing criteria, if 1D features are added to the domain, the user
can define the parameter `edge_size` of the criteria class
@ -970,7 +973,7 @@ protection of the 1D-features.
Left: the mesh without any call to `%add_features()`.
Middle: the mesh with only the 1D-features computed by
`%CGAL::polylines_to_protect()`.
`CGAL::Mesh_3::Detect_features_on_image_bbox()`.
Right: the mesh with added 1D-features in the interior of the bounding box
of the image.

View File

@ -16,6 +16,10 @@
/// \ingroup PkgMesh3Ref
/// The classes in this group are models of domain concepts and their associated classes.
/// \defgroup PkgMesh3FeatureDetection Feature Detection
/// \ingroup PkgMesh3Ref
/// The functors in this group perform polyline features detection in input domains.
/// \defgroup PkgMesh3Functions Mesh Generation Functions
/// \ingroup PkgMesh3Ref
/// The two main functions to generate a mesh are `make_mesh_3()` and `refine_mesh_3()`.
@ -103,6 +107,11 @@ and their associated classes:
- `CGAL::Labeled_image_mesh_domain_3<Image,BGT>` (deprecated)
- `CGAL::Gray_image_mesh_domain_3<Image,BGT,Image_word_type>` (deprecated)
The following functors are available for feature detection:
- `CGAL::Mesh_3::Detect_features_in_image`
- `CGAL::Mesh_3::Detect_features_on_image_bbox`
\cgalCRPSection{Function Templates}
- `CGAL::make_mesh_3()`

View File

@ -4,6 +4,8 @@
\example Mesh_3/mesh_3D_gray_image_with_custom_initialization.cpp
\example Mesh_3/mesh_3D_image_with_features.cpp
\example Mesh_3/mesh_3D_image_with_custom_initialization.cpp
\example Mesh_3/mesh_3D_image_with_detection_of_features.cpp
\example Mesh_3/mesh_3D_image_with_input_features.cpp
\example Mesh_3/mesh_3D_weighted_image.cpp
\example Mesh_3/random_labeled_image.h
\example CGAL/Mesh_3/initialize_triangulation_from_gray_image.h

View File

@ -133,6 +133,12 @@ if(TARGET CGAL::CGAL_ImageIO)
create_single_source_cgal_program("mesh_3D_image_with_features.cpp")
target_link_libraries(mesh_3D_image_with_features PUBLIC CGAL::Eigen3_support)
create_single_source_cgal_program("mesh_3D_image_with_input_features.cpp")
target_link_libraries(mesh_3D_image_with_input_features PUBLIC CGAL::Eigen3_support)
create_single_source_cgal_program("mesh_3D_image_with_detection_of_features.cpp")
target_link_libraries(mesh_3D_image_with_detection_of_features PUBLIC CGAL::Eigen3_support)
if(CGAL_ImageIO_USE_ZLIB)
create_single_source_cgal_program("mesh_optimization_example.cpp")
target_link_libraries(mesh_optimization_example PUBLIC CGAL::Eigen3_support)
@ -185,6 +191,8 @@ if(CGAL_ACTIVATE_CONCURRENT_MESH_3 AND TARGET CGAL::TBB_support)
mesh_3D_image_with_custom_initialization
mesh_3D_gray_image_with_custom_initialization
mesh_3D_image_with_features
mesh_3D_image_with_detection_of_features
mesh_3D_image_with_input_features
mesh_implicit_domains
mesh_implicit_sphere
mesh_implicit_sphere_variable_size

View File

@ -1,5 +1,3 @@
#define CGAL_MESH_3_VERBOSE
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Mesh_triangulation_3.h>

View File

@ -0,0 +1,86 @@
#include <vector>
#include <iostream>
#include <CGAL/Mesh_triangulation_3.h>
#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
#include <CGAL/Mesh_criteria_3.h>
#include <CGAL/make_mesh_3.h>
#include <CGAL/Image_3.h>
/// [Domain definition]
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Mesh_domain_with_polyline_features_3.h>
#include <CGAL/Labeled_mesh_domain_3.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Labeled_mesh_domain_3<K> Image_domain;
typedef CGAL::Mesh_domain_with_polyline_features_3<Image_domain> Mesh_domain;
/// [Domain definition]
#include <CGAL/Mesh_3/Detect_features_in_image.h>
#ifdef CGAL_CONCURRENT_MESH_3
typedef CGAL::Parallel_tag Concurrency_tag;
#else
typedef CGAL::Sequential_tag Concurrency_tag;
#endif
// Triangulation
typedef CGAL::Mesh_triangulation_3<Mesh_domain,CGAL::Default,Concurrency_tag>::type Tr;
typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3;
// Criteria
typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
// To avoid verbose function and named parameters call
namespace params = CGAL::parameters;
int main(int argc, char* argv[])
{
const std::string fname = (argc>1)?argv[1]:CGAL::data_file_path("images/420.inr");
/// [Loads image]
CGAL::Image_3 image;
if(!image.read(fname)){
std::cerr << "Error: Cannot read file " << fname << std::endl;
return EXIT_FAILURE;
}
/// [Loads image]
/// [Domain creation]
Mesh_domain domain
= Mesh_domain::create_labeled_image_mesh_domain(image,
params::features_detector = CGAL::Mesh_3::Detect_features_in_image());
/// [Domain creation]
CGAL::Bbox_3 bbox = domain.bbox();
double diag = CGAL::sqrt(CGAL::square(bbox.xmax() - bbox.xmin()) +
CGAL::square(bbox.ymax() - bbox.ymin()) +
CGAL::square(bbox.zmax() - bbox.zmin()));
double sizing_default = diag * 0.05;
/// [Mesh criteria]
/// Note that `edge_size` is needed with 1D-features
Mesh_criteria criteria(params::edge_size = sizing_default,
params::facet_angle = 30,
params::facet_size = sizing_default,
params::facet_distance = sizing_default / 10,
params::facet_topology = CGAL::FACET_VERTICES_ON_SAME_SURFACE_PATCH,
params::cell_radius_edge_ratio = 0,
params::cell_size = 0
);
/// [Mesh criteria]
/// [Meshing]
C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(domain, criteria,
params::no_exude(),
params::no_perturb());
/// [Meshing]
// Output
CGAL::dump_c3t3(c3t3, "out");
return 0;
}

View File

@ -18,6 +18,8 @@ typedef CGAL::Labeled_mesh_domain_3<K> Image_domain;
typedef CGAL::Mesh_domain_with_polyline_features_3<Image_domain> Mesh_domain;
/// [Domain definition]
#include <CGAL/Mesh_3/Detect_features_on_image_bbox.h>
#ifdef CGAL_CONCURRENT_MESH_3
typedef CGAL::Parallel_tag Concurrency_tag;
#else
@ -34,40 +36,8 @@ typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
namespace params = CGAL::parameters;
/// [Add 1D features]
// Read input features
#include "read_polylines.h"
#include <CGAL/Mesh_3/polylines_to_protect.h> // undocumented header
// Protect the intersection of the object with the box of the image,
// by declaring 1D-features. Note that `CGAL::polylines_to_protect` is
// not documented.
bool add_1D_features(const CGAL::Image_3& image,
Mesh_domain& domain,
const std::string lines_fname)
{
typedef K::Point_3 Point_3;
typedef unsigned char Word_type;
std::vector<std::vector<Point_3> > features_inside;
if(!read_polylines(lines_fname, features_inside)) // see file "read_polylines.h"
{
std::cerr << "Error: Cannot read file " << lines_fname << std::endl;
return false;
}
std::vector<std::vector<Point_3> > polylines_on_bbox;
CGAL::polylines_to_protect<Point_3, Word_type>(image, polylines_on_bbox,
features_inside.begin(),
features_inside.end());
domain.add_features(polylines_on_bbox.begin(), polylines_on_bbox.end());
// It is very important that the polylines from the file `lines_fname`
// contain only polylines in the inside of the box of the image.
domain.add_features(features_inside.begin(), features_inside.end());
return true;
}
/// [Add 1D features]
int main(int argc, char* argv[])
{
@ -79,21 +49,28 @@ int main(int argc, char* argv[])
return EXIT_FAILURE;
}
// Domain
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain(image);
/// Declare 1D-features, see above [Call add_1D_features]
const std::string lines_fname = (argc>2)?argv[2]:CGAL::data_file_path("images/420.polylines.txt");
if(!add_1D_features(image, domain, lines_fname)) {
/// Load 1D-features
const std::string lines_fname = (argc > 2) ? argv[2] : CGAL::data_file_path("images/420.polylines.txt");
std::vector<std::vector<K::Point_3> > features_inside;
if (!read_polylines(lines_fname, features_inside)) // see file "read_polylines.h"
{
std::cerr << "Error: Cannot read file " << lines_fname << std::endl;
return EXIT_FAILURE;
}
/// [Call add_1D_features]
/// [Domain creation]
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain(image,
params::features_detector = CGAL::Mesh_3::Detect_features_on_image_bbox(),
params::input_features = std::cref(features_inside));//use std::cref to avoid a copy
/// [Domain creation]
/// Note that `edge_size` is needed with 1D-features [Mesh criteria]
Mesh_criteria criteria(params::edge_size(6).
facet_angle(30).facet_size(6).facet_distance(4).
cell_radius_edge_ratio(3).cell_size(8));
Mesh_criteria criteria(params::edge_size = 6.,
params::facet_angle = 30,
params::facet_size = 6,
params::facet_distance = 4,
params::cell_radius_edge_ratio = 3,
params::cell_size = 8);
/// [Mesh criteria]
// Meshing
@ -104,5 +81,5 @@ int main(int argc, char* argv[])
CGAL::IO::write_MEDIT(medit_file, c3t3);
medit_file.close();
return 0;
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,82 @@
#include <vector>
#include <iostream>
#include <CGAL/Mesh_triangulation_3.h>
#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
#include <CGAL/Mesh_criteria_3.h>
#include <CGAL/make_mesh_3.h>
#include <CGAL/Image_3.h>
/// [Domain definition]
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Mesh_domain_with_polyline_features_3.h>
#include <CGAL/Labeled_mesh_domain_3.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Labeled_mesh_domain_3<K> Image_domain;
typedef CGAL::Mesh_domain_with_polyline_features_3<Image_domain> Mesh_domain;
/// [Domain definition]
#ifdef CGAL_CONCURRENT_MESH_3
using Concurrency_tag = CGAL::Parallel_tag;
#else
using Concurrency_tag = CGAL::Sequential_tag;
#endif
// Triangulation
typedef CGAL::Mesh_triangulation_3<Mesh_domain,CGAL::Default,Concurrency_tag>::type Tr;
typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3;
// Criteria
typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
namespace params = CGAL::parameters;
#include "read_polylines.h"
int main(int argc, char* argv[])
{
const std::string fname = (argc>1)?argv[1]:CGAL::data_file_path("images/420.inr");
// Loads image
CGAL::Image_3 image;
if(!image.read(fname)){
std::cerr << "Error: Cannot read file " << fname << std::endl;
return EXIT_FAILURE;
}
/// Declare 1D-features
const std::string lines_fname = (argc>2)?argv[2]:CGAL::data_file_path("images/420.polylines.txt");
using Point_3 = K::Point_3;
std::vector<std::vector<Point_3> > features_inside;
if (!read_polylines(lines_fname, features_inside)) // see file "read_polylines.h"
{
std::cerr << "Error: Cannot read file " << lines_fname << std::endl;
return EXIT_FAILURE;
}
/// [Domain creation]
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain(image,
params::input_features = std::cref(features_inside));//use std::cref to avoid a copy
/// [Domain creation]
/// Note that `edge_size` is needed with 1D-features [Mesh criteria]
Mesh_criteria criteria(params::edge_size = 6,
params::facet_angle = 30,
params::facet_size = 6,
params::facet_distance = 4,
params::cell_radius_edge_ratio = 3,
params::cell_size = 8);
/// [Mesh criteria]
// Meshing
C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(domain, criteria);
// Output
std::ofstream medit_file("out.mesh");
CGAL::IO::write_MEDIT(medit_file, c3t3);
medit_file.close();
return EXIT_SUCCESS;
}

View File

@ -24,6 +24,7 @@
#include <CGAL/Labeled_mesh_domain_3.h>
#include <CGAL/Implicit_to_labeling_function_wrapper.h>
#include <CGAL/Mesh_3/Null_subdomain_index.h>
#include <CGAL/Random.h>
namespace CGAL {

View File

@ -26,6 +26,7 @@
#include <CGAL/Random.h>
#include <CGAL/Labeled_mesh_domain_3.h>
#include <CGAL/Mesh_3/Image_to_labeled_function_wrapper.h>
#include <CGAL/Mesh_3/Null_subdomain_index.h>
#include <CGAL/Bbox_3.h>
#include <CGAL/Default.h>

View File

@ -31,6 +31,7 @@
#include <CGAL/Origin.h>
#include <functional>
#include <type_traits>
#include <CGAL/SMDS_3/internal/Handle_IO_for_pair_of_int.h>
#include <CGAL/SMDS_3/internal/indices_management.h>
@ -48,6 +49,11 @@
#endif
#include <boost/optional.hpp>
#include <CGAL/Mesh_3/Null_subdomain_index.h>
#include <CGAL/Mesh_domain_with_polyline_features_3.h>
#include <CGAL/Mesh_3/polylines_to_protect.h>
namespace CGAL {
namespace Mesh_3 {
namespace internal {
@ -117,15 +123,67 @@ namespace internal {
}
};
// Detect_features_in_domain
template<typename Point, typename DetectFunctor>
struct Detect_features_in_domain {
std::vector<std::vector<Point>>
operator()(const CGAL::Image_3& image, DetectFunctor functor) const {
#if defined(BOOST_MSVC) && (BOOST_MSVC < 1910) //before msvc2017
return functor.operator()<Point>(image);
#else
return functor.template operator()<Point>(image);
#endif
}
};
// specialization for `Null_functor`: create the default functor
template<typename Point>
struct Detect_features_in_domain<Point, Null_functor> {
std::vector<std::vector<Point>>
operator()(const CGAL::Image_3&, Null_functor) const {
return std::vector<std::vector<Point>>();
}
};
template<typename Point, typename DetectFunctor>
std::vector<std::vector<Point>>
detect_features(const CGAL::Image_3& image, DetectFunctor functor)
{
Detect_features_in_domain<Point, DetectFunctor> detector;
return detector(image, functor);
}
template<bool WithFeatures>
struct Add_features_in_domain {
template<typename MeshDomain, typename InputFeatureRange, typename DetectFunctor>
void operator()(const CGAL::Image_3&, MeshDomain&, const InputFeatureRange&, DetectFunctor)
{}
};
template<>
struct Add_features_in_domain<true>
{
template<typename MeshDomain, typename InputFeatureRange, typename DetectFunctor>
void operator()(const CGAL::Image_3& image,
MeshDomain& domain,
const InputFeatureRange& input_features,
DetectFunctor functor)
{
using P = typename MeshDomain::Point_3;
auto detected_feature_range
= CGAL::Mesh_3::internal::detect_features<P>(image, functor);
CGAL::merge_and_snap_polylines(image, detected_feature_range, input_features);
if (!input_features.empty())
domain.add_features(input_features.begin(), input_features.end());
domain.add_features(detected_feature_range.begin(), detected_feature_range.end());
}
};
} // end namespace CGAL::Mesh_3::internal
} // end namespace CGAL::Mesh_3
#ifndef DOXYGEN_RUNNING
struct Null_subdomain_index {
template <typename T>
bool operator()(const T& x) const { return 0 == x; }
};
template <typename Subdomain_index>
struct Construct_pair_from_subdomain_indices {
typedef std::pair<Subdomain_index, Subdomain_index> result_type;
@ -539,6 +597,11 @@ public:
* domain to be discretized is the union of voxels that have non-zero
* values.
*
* \returns either a `Labeled_mesh_domain_3`,
* or a `Mesh_domain_with_polyline_features_3<Labeled_mesh_domain_3>`
* depending on whether one or more of the named parameters
* `features_detector` and `input_features` are provided.
*
* \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
* \param image_ the input 3D image.
* \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below:
@ -565,6 +628,34 @@ public:
* bound, relative to the diameter of the box of the image.}
* \cgalParamDefault{FT(1e-3)}
* \cgalParamNEnd
*
* \cgalParamNBegin{features_detector}
* \cgalParamDescription{ a functor that implements
* `std::vector<std::vector<Point>> operator()(const Image_3& img) const`,
* where `%Point` matches the mesh domain point type.
* It returns a range of detected polyline features, which are added
* to the domain for feature protection.
* See \ref PkgMesh3FeatureDetection for a list of available functors.}
* \cgalParamDefault{CGAL::Null_functor()}
* \cgalParamExtra{The return type of the function depends on whether this parameter
or `input_features` are provided or not.}
* \cgalParamExtra{If `weights` is provided, this parameter is ignored}
* \cgalParamNEnd
*
* \cgalParamNBegin{input_features}
* \cgalParamDescription{ a `Range` of polyline features, represented as `Range`s of `Point_3`.
* Polyline features are added to the domain for further feature protection.
* Input polyline features must be different from the detected features
* and can intersect only at vertices, if they do. Otherwise,
* the meshing process may not terminate.}
* \cgalParamDefault{`std::vector<std::vector<Point_3>>()`}
* \cgalParamExtra{The return type of the function depends on whether this parameter
or `input_features` are provided or not.}
* \cgalParamExtra{It is recommended to pass a const-reference for this parameter,
* possibly using `std::cref(polylines_range)` to avoid useless copies.}
* \cgalParamExtra{If `weights` is provided, this parameter is ignored}
* \cgalParamNEnd
*
* \cgalNamedParamsEnd
*
* \cgalHeading{Example}
@ -578,13 +669,24 @@ public:
*
* \snippet Mesh_3/mesh_3D_weighted_image.cpp Domain creation
*
* From the example (\ref Mesh_3/mesh_3D_image_with_detection_of_features.cpp)
* where the features are detected in `image`:
*
* \snippet Mesh_3/mesh_3D_image_with_detection_of_features.cpp Domain creation
*
* From the example (\ref Mesh_3/mesh_3D_image_with_input_features.cpp)
* where the features are provided by the user:
*
* \snippet Mesh_3/mesh_3D_image_with_input_features.cpp Domain creation
*/
template<typename CGAL_NP_TEMPLATE_PARAMETERS>
static Labeled_mesh_domain_3 create_labeled_image_mesh_domain(const CGAL::Image_3& image_, const CGAL_NP_CLASS& np = parameters::default_values())
static auto
create_labeled_image_mesh_domain(const CGAL::Image_3& image_, const CGAL_NP_CLASS& np = parameters::default_values())
{
using parameters::get_parameter;
using parameters::get_parameter_reference;
using parameters::choose_parameter;
auto iso_value_ = choose_parameter(get_parameter(np, internal_np::iso_value_param), 0);
auto value_outside_ = choose_parameter(get_parameter(np, internal_np::voxel_value), 0);
FT relative_error_bound_ = choose_parameter(get_parameter(np, internal_np::error_bound), FT(1e-3));
@ -592,41 +694,62 @@ public:
CGAL::Random* p_rng_ = choose_parameter(get_parameter(np, internal_np::rng), nullptr);
auto null_subdomain_index_ = choose_parameter(get_parameter(np, internal_np::null_subdomain_index_param), Null_functor());
auto construct_surface_patch_index_ = choose_parameter(get_parameter(np, internal_np::surface_patch_index), Null_functor());
const CGAL::Image_3& weights_ = choose_parameter(get_parameter_reference(np, internal_np::weights_param), CGAL::Image_3());
using Image_ref_type = typename internal_np::Lookup_named_param_def<internal_np::weights_param_t,
CGAL_NP_CLASS,
CGAL::Image_3>::reference;
CGAL::Image_3 no_weights;
const Image_ref_type weights_ = choose_parameter(get_parameter_reference(np, internal_np::weights_param), no_weights);
auto features_detector_ = choose_parameter(get_parameter(np, internal_np::features_detector_param), Null_functor());
using Default_input_features = std::vector<std::vector<typename Labeled_mesh_domain_3::Point_3>>;
using Input_features_ref_type = typename internal_np::Lookup_named_param_def<internal_np::input_features_param_t,
CGAL_NP_CLASS,
Default_input_features>::reference;
Default_input_features empty_vec;
Input_features_ref_type input_features_
= choose_parameter(get_parameter_reference(np, internal_np::input_features_param), empty_vec);
CGAL_USE(iso_value_);
namespace p = CGAL::parameters;
auto image_wrapper = weights_.is_valid()
? create_weighted_labeled_image_wrapper(image_,
weights_,
image_values_to_subdomain_indices_,
value_outside_)
: create_labeled_image_wrapper(image_,
image_values_to_subdomain_indices_,
value_outside_);
// warning : keep Return_type consistent with actual return type
const bool no_features
= CGAL::parameters::is_default_parameter<CGAL_NP_CLASS, internal_np::features_detector_param_t>::value
&& CGAL::parameters::is_default_parameter<CGAL_NP_CLASS, internal_np::input_features_param_t>::value;
using Return_type = std::conditional_t <
no_features,
Labeled_mesh_domain_3,
Mesh_domain_with_polyline_features_3<Labeled_mesh_domain_3>
>;
Return_type domain
(p::function = image_wrapper,
p::bounding_object = Mesh_3::internal::compute_bounding_box(image_),
p::relative_error_bound = relative_error_bound_,
p::p_rng = p_rng_,
p::null_subdomain_index =
create_null_subdomain_index(null_subdomain_index_),
p::construct_surface_patch_index =
create_construct_surface_patch_index(construct_surface_patch_index_));
if (weights_.is_valid())
{
return Labeled_mesh_domain_3
(p::function = create_weighted_labeled_image_wrapper
(image_,
weights_,
image_values_to_subdomain_indices_,
value_outside_),
p::bounding_object = Mesh_3::internal::compute_bounding_box(image_),
p::relative_error_bound = relative_error_bound_,
p::p_rng = p_rng_,
p::null_subdomain_index =
create_null_subdomain_index(null_subdomain_index_),
p::construct_surface_patch_index =
create_construct_surface_patch_index(construct_surface_patch_index_));
}
else
{
return Labeled_mesh_domain_3
(p::function = create_labeled_image_wrapper
(image_,
image_values_to_subdomain_indices_,
value_outside_),
p::bounding_object = Mesh_3::internal::compute_bounding_box(image_),
p::relative_error_bound = relative_error_bound_,
p::p_rng = p_rng_,
p::null_subdomain_index =
create_null_subdomain_index(null_subdomain_index_),
p::construct_surface_patch_index =
create_construct_surface_patch_index(construct_surface_patch_index_));
}
return domain;
// features
Mesh_3::internal::Add_features_in_domain<!no_features>()
(image_, domain, input_features_, features_detector_);
return domain;
}
/// @}
@ -686,7 +809,7 @@ public:
}
template<typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT>
static Labeled_mesh_domain_3 create_labeled_image_mesh_domain(const CGAL_NP_CLASS& np)
static auto create_labeled_image_mesh_domain(const CGAL_NP_CLASS& np)
{
static_assert(!parameters::is_default_parameter<CGAL_NP_CLASS, internal_np::image_3_param_t>::value, "Value for required parameter not found");
using parameters::get_parameter_reference;
@ -698,10 +821,10 @@ public:
template<typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_1,
typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_2,
typename ... NP>
static Labeled_mesh_domain_3 create_labeled_image_mesh_domain(const CGAL::Image_3& image_,
const CGAL_NP_CLASS_1& np1,
const CGAL_NP_CLASS_2& np2,
const NP& ... nps)
static auto create_labeled_image_mesh_domain(const CGAL::Image_3& image_,
const CGAL_NP_CLASS_1& np1,
const CGAL_NP_CLASS_2& np2,
const NP& ... nps)
{
return create_labeled_image_mesh_domain(image_, internal_np::combine_named_parameters(np1, np2, nps...));
}
@ -709,9 +832,9 @@ public:
template<typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_1,
typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_2,
typename ... NP>
static Labeled_mesh_domain_3 create_labeled_image_mesh_domain(const CGAL_NP_CLASS_1& np1,
const CGAL_NP_CLASS_2& np2,
const NP& ... nps)
static auto create_labeled_image_mesh_domain(const CGAL_NP_CLASS_1& np1,
const CGAL_NP_CLASS_2& np2,
const NP& ... nps)
{
return create_labeled_image_mesh_domain(internal_np::combine_named_parameters(np1, np2, nps...));
}
@ -904,9 +1027,9 @@ public:
// null(f(p)) means p is outside the domain
Subdomain_index index = (r_domain_.function_)(p);
if ( r_domain_.null(index) )
return Subdomain();
return Subdomain{};
else
return Subdomain(index);
return Subdomain{ index };
}
private:
const Labeled_mesh_domain_3& r_domain_;

View File

@ -791,6 +791,7 @@ public:
Moving_vertices_set& moving_vertices);
void update_restricted_facets();
void update_restricted_cells();
#ifdef CGAL_INTRUSIVE_LIST
template <typename OutdatedCells>
@ -2924,6 +2925,18 @@ update_restricted_facets()
updater(*fit);
}
template <typename C3T3, typename MD>
void
C3T3_helpers<C3T3, MD>::
update_restricted_cells()
{
Update_c3t3 updater(domain_, c3t3_);
for (typename C3T3::Triangulation::Finite_cells_iterator
cit = tr_.finite_cells_begin();
cit != tr_.finite_cells_end(); ++cit)
updater(cit);
}
template <typename C3T3, typename MD>
template <typename OutdatedCellsOutputIterator,
typename DeletedCellsOutputIterator>

View File

@ -0,0 +1,290 @@
// Copyright (c) 2022 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Sebastien Loriot, Jane Tournois
//
//******************************************************************************
//
//******************************************************************************
#ifndef CGAL_MESH_3_DETECT_FEATURES_IN_IMAGE_H
#define CGAL_MESH_3_DETECT_FEATURES_IN_IMAGE_H
#include <CGAL/license/Mesh_3.h>
#include <CGAL/ImageIO.h>
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Mesh_3/features_detection/features_detection.h>
#include <CGAL/Mesh_3/features_detection/coordinates.h>
#include <CGAL/Mesh_3/features_detection/combinations.h>
#include <CGAL/Mesh_3/features_detection/cases_table.h>
#include <CGAL/Mesh_3/features_detection/cube_isometries.h>
#include <CGAL/Mesh_3/features_detection/features_detection_helpers.h>
#include <CGAL/Mesh_3/polylines_to_protect.h>
#include <CGAL/Kernel_traits.h>
#include <vector>
#include <array>
#ifdef CGAL_DEBUG_TRIPLE_LINES
#include <boost/range/join.hpp>
#endif
namespace CGAL
{
namespace Mesh_3
{
namespace internal
{
// Protect the intersection of the object with the box of the image,
// by declaring 1D-features. Note that `CGAL::polylines_to_protect` is
// not documented.
template<typename Word_type, typename P>
std::vector<std::vector<P>>
detect_features_in_image_with_know_word_type(const CGAL::Image_3& image)
{
using Gt = typename CGAL::Kernel_traits<P>::Kernel;
using Point_3 = P;
using Vector_3 = typename Gt::Vector_3;
using Polyline_type = std::vector<Point_3>;
using Polylines = std::vector<Polyline_type>;
CGAL::Mesh_3::Triple_line_extractor<Point_3> lines;
Polylines features_inside;
const double vx = image.vx();
const double vy = image.vy();
const double vz = image.vz();
const double dist_bound = (std::min)(vx, (std::min)(vy, vz)) / 256;
const double sq_dist_bound = dist_bound * dist_bound;
const std::size_t xdim = image.xdim();
const std::size_t ydim = image.ydim();
const std::size_t zdim = image.zdim();
const float tx = image.tx();
const float ty = image.ty();
const float tz = image.tz();
using CGAL::IMAGEIO::static_evaluate;
using Del = CGAL::Delaunay_triangulation_3<Gt>;
using Cell_handle = typename Del::Cell_handle;
using Vertex_handle = typename Del::Vertex_handle;
Del triangulation;
Cell_handle start_cell;
using Word //use unsigned integral Word type to use it as an index
= typename CGAL::IMAGEIO::Word_type_generator<WK_FIXED, SGN_UNSIGNED, sizeof(Word_type)>::type;
using Color_transform = internal::Color_transformation_helper<Word>;
typename Color_transform::type color_transformation;
std::array<Word, 8> inv_color_transformation;
using Permutation = internal::Permutation;
using Coord = internal::Coordinates;
for (std::size_t k = 0, end_k = zdim - 1; k < end_k; ++k)
for (std::size_t j = 0, end_j = ydim - 1; j < end_j; ++j)
for (std::size_t i = 0, end_i = xdim - 1; i < end_i; ++i)
{
Vector_3 translation{ i * vx + tx,
j * vy + ty,
k * vz + tz };
const std::array<Word, 8> cube = {
static_evaluate<Word>(image.image(), i , j , k),
static_evaluate<Word>(image.image(), i + 1, j , k),
static_evaluate<Word>(image.image(), i , j + 1, k),
static_evaluate<Word>(image.image(), i + 1, j + 1, k),
static_evaluate<Word>(image.image(), i , j , k + 1),
static_evaluate<Word>(image.image(), i + 1, j , k + 1),
static_evaluate<Word>(image.image(), i , j + 1, k + 1),
static_evaluate<Word>(image.image(), i + 1, j + 1, k + 1),
}; /// TODO: optimize the access to the image data
bool monocolor = (cube[0] == cube[1]);
for (int i = 2; i < 8; ++i) monocolor = monocolor && (cube[0] == cube[i]);
if (monocolor) continue;
Color_transform::reset(color_transformation);
std::uint8_t nb_color = 0;
for (int i = 0; i < 8; ++i) {
if (!Color_transform::is_valid(color_transformation, cube[i]))
{
color_transformation[cube[i]] = nb_color;
inv_color_transformation[nb_color] = cube[i];
++nb_color;
}
}
std::array<std::uint8_t, 8> reference_cube = {
color_transformation[cube[0]],
color_transformation[cube[1]],
color_transformation[cube[2]],
color_transformation[cube[3]],
color_transformation[cube[4]],
color_transformation[cube[5]],
color_transformation[cube[6]],
color_transformation[cube[7]]
};
auto case_it = internal::find_case(internal::cases, reference_cube);
const bool case_found = (case_it != std::end(internal::cases));
if (case_found) reference_cube = internal::combinations[(*case_it)[8]];
else {
//std::cerr << "Warning: case not found: " << reference_cube << '\n';
CGAL_error();
};
#ifdef CGAL_DEBUG_TRIPLE_LINES
CGAL::Mesh_3::internal::debug_cerr("Cube", cube);
CGAL::Mesh_3::internal::debug_cerr("reference cube", reference_cube);
CGAL::Mesh_3::internal::debug_cerr("with transformation", internal::cube_isometries[(*case_it)[9]]);
#endif // CGAL_DEBUG_TRIPLE_LINES
auto fct_it = lines.create_polylines_fcts.find(reference_cube);
if (fct_it != lines.create_polylines_fcts.end())
{
#ifdef CGAL_DEBUG_TRIPLE_LINES
CGAL::Mesh_3::internal::debug_cerr("Using the function of", Cube(fct_it->first));
#endif // CGAL_DEBUG_TRIPLE_LINES
Polylines cube_features = (fct_it->second)(10);
if (case_found)
{
const Permutation& transformation = internal::cube_isometries[(*case_it)[9]];
Coord a1 = internal::coordinates[transformation[0]];
Coord u = internal::minus(internal::coordinates[transformation[1]], a1);
Coord v = internal::minus(internal::coordinates[transformation[2]], a1);
Coord w = internal::minus(internal::coordinates[transformation[4]], a1);
const Point_3 pa{ a1[0], a1[1], a1[2] };
const Vector_3 vu{ u[0], u[1], u[2] };
const Vector_3 vv{ v[0], v[1], v[2] };
const Vector_3 vw{ w[0], w[1], w[2] };
#ifdef CGAL_DEBUG_TRIPLE_LINES
std::cerr << "pa: " << pa << "\n";
std::cerr << "vu: " << vu << "\n";
std::cerr << "vv: " << vv << "\n";
std::cerr << "vw: " << vw << "\n";
#endif // CGAL_DEBUG_TRIPLE_LINES
for (auto& polyline : cube_features) {
for (auto& point : polyline) {
point = pa
+ point.x() * vu
+ point.y() * vv
+ point.z() * vw;
point = { vx * point.x(),
vy * point.y(),
vz * point.z(), };
point = point + translation;
}
for (int i = 0; i < 2; ++i) {
Point_3& extremity = (i == 0) ? polyline.front() : polyline.back();
Vertex_handle vh = triangulation.nearest_vertex(extremity, start_cell);
if (Vertex_handle() != vh) {
if (squared_distance(vh->point(), extremity) < sq_dist_bound) {
extremity = vh->point();
}
}
vh = triangulation.insert(extremity, start_cell);
start_cell = vh->cell();
}
features_inside.push_back(std::move(polyline));
} // end loop on polylines
} // end case where the transformation is not the identity
} // end if the reference_cube has polylines
}
// call the split_graph_into_polylines, to create long polylines from the
// short polylines that were generated per voxel.
Polylines polylines_inside;
CGAL::polylines_to_protect(polylines_inside,
features_inside.begin(),
features_inside.end());
Polylines polylines_on_bbox;
CGAL::polylines_to_protect<Point_3, Word_type>(image, polylines_on_bbox,
polylines_inside.begin(),
polylines_inside.end());
polylines_inside.insert(polylines_inside.end(),
polylines_on_bbox.begin(),
polylines_on_bbox.end());
#ifdef CGAL_DEBUG_TRIPLE_LINES
std::ofstream output_polylines("out-generated.polylines.txt");
output_polylines.precision(17);
for (auto poly : boost::range::join(polylines_on_bbox, polylines_inside)) {
output_polylines << poly.size();
for (auto p : poly) output_polylines << " " << p;
output_polylines << std::endl;
}
#endif
return polylines_inside;
}
}// namespace internal
/*!
* \ingroup PkgMesh3FeatureDetection
*
* Functor for feature detection in labeled images.
*/
struct Detect_features_in_image
{
public:
/*!
* detects and constructs the polylines that lie at the
* intersection of three or more subdomains.
*
* Each subdomain inside the bounding box
* of the input labeled image is defined as the set of voxels
* with the same value. The outside of the bounding box
* of the image is considered as a subdomain with voxel value
* `value_outside` (see \link CGAL::Labeled_mesh_domain_3::create_labeled_image_mesh_domain `create_labeled_image_mesh_domain()` \endlink
* parameters description). Hence, this function also computes
* intersections with the image bounding box.
*
* \tparam Point class model of `Kernel::Point_3`. It
* must match the triangulation point type.
*
* \param image the input image
*
* \returns a `std::vector<std::vector<Point>>`
* containing the constructed polylines for later feature protection.
*/
template<typename Point>
std::vector<std::vector<Point>>
operator()(const CGAL::Image_3& image) const
{
CGAL_IMAGE_IO_CASE(image.image(),
return (internal::detect_features_in_image_with_know_word_type<Word, Point>(image));
);
CGAL_error_msg("This place should never be reached, because it would mean "
"the image word type is a type that is not handled by "
"CGAL_ImageIO.");
return std::vector<std::vector<Point>>();
}
};
}//end namespace Mesh_3
}//end namespace CGAL
#endif //CGAL_MESH_3_DETECT_FEATURES_IN_IMAGE_H

View File

@ -0,0 +1,100 @@
// Copyright (c) 2022 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Laurent Rineau, Jane Tournois
//
//******************************************************************************
//
//******************************************************************************
#ifndef CGAL_MESH_3_DETECT_FEATURES_ON_IMAGE_BBOX_H
#define CGAL_MESH_3_DETECT_FEATURES_ON_IMAGE_BBOX_H
#include <CGAL/license/Mesh_3.h>
#include <CGAL/Mesh_3/polylines_to_protect.h>
#include <vector>
namespace CGAL
{
namespace Mesh_3
{
namespace internal
{
template<typename Point>
std::vector<std::vector<Point>>
detect_features_on_bbox(const CGAL::Image_3& image)
{
using Point_3 = Point;
using Polyline_type = std::vector<Point_3>;
using Polylines = std::vector<Polyline_type>;
Polylines polylines_on_bbox;
CGAL_IMAGE_IO_CASE(image.image(),
{
(CGAL::polylines_to_protect<Point_3, Word>(image, polylines_on_bbox));
return polylines_on_bbox;
}
);
CGAL_error_msg("This place should never be reached, because it would mean "
"the image word type is a type that is not handled by "
"CGAL_ImageIO.");
return Polylines();
}
}// namespace internal
/*!
* \ingroup PkgMesh3FeatureDetection
*
* Functor for feature detection in labeled images.
*/
struct Detect_features_on_image_bbox
{
public:
/*!
* detects and constructs the polylines that lie at the
* intersection of two or more subdomains and the bounding box
* of the input labeled image.
*
* Each subdomain inside the bounding box
* of the input labeled image is defined as the set of voxels
* with the same value. The outside of the bounding box
* of the image is considered as a subdomain with voxel value
* `value_outside` (see \link CGAL::Labeled_mesh_domain_3::create_labeled_image_mesh_domain `create_labeled_image_mesh_domain()` \endlink
* parameters description). Hence, this function computes
* intersections of "internal" subdomains with the image bounding box.
*
* \tparam Point class model of `Kernel::Point_3`. The point type
* must match the triangulation point type.
*
* \param image the input image
*
* \returns a `std::vector<std::vector<Point>>`
* containing the constructed polylines for later feature protection.
*/
template<typename Point>
std::vector<std::vector<Point>>
operator()(const CGAL::Image_3& image) const
{
return internal::detect_features_on_bbox<Point>(image);
}
};
}//end namespace Mesh_3
}//end namespace CGAL
#endif //CGAL_MESH_3_DETECT_FEATURES_ON_IMAGE_BBOX_H

View File

@ -0,0 +1,29 @@
// Copyright (c) 2015 GeometryFactory
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Laurent Rineau
#ifndef CGAL_MESH_3_NULL_SUBDOMAIN_INDEX
#define CGAL_MESH_3_NULL_SUBDOMAIN_INDEX
#include <CGAL/license/Mesh_3.h>
#ifndef DOXYGEN_RUNNING
namespace CGAL {
struct Null_subdomain_index {
template <typename T>
bool operator()(const T& x) const { return 0 == x; }
};
}
#endif
#endif //CGAL_MESH_3_NULL_SUBDOMAIN_INDEX

View File

@ -57,25 +57,40 @@ public:
IndexToIgnoreIterator end,
const AABBTraits& aabb_traits,
IndexPropertyMap index_map = IndexPropertyMap())
: m_closest_point(hint),
m_closest_point_initialized(true),
set_of_indices(begin, end),
aabb_traits(aabb_traits),
index_map(index_map)
: Filtered_projection_traits(begin, end, aabb_traits, index_map)
{
m_closest_point = hint;
m_closest_point_initialized = true;
}
Filtered_projection_traits(const Point_3& hint,
Index_type index,
const AABBTraits& aabb_traits,
IndexPropertyMap index_map = IndexPropertyMap())
: m_closest_point(hint),
m_closest_point_initialized(true),
set_of_indices(),
aabb_traits(aabb_traits),
index_map(index_map)
: Filtered_projection_traits(index, aabb_traits, index_map)
{
set_of_indices.insert(index);
m_closest_point = hint;
m_closest_point_initialized = true;
}
template <typename IndexToIgnoreIterator>
Filtered_projection_traits(const Point_and_primitive_id& hint,
IndexToIgnoreIterator begin,
IndexToIgnoreIterator end,
const AABBTraits& aabb_traits,
IndexPropertyMap index_map = IndexPropertyMap())
: Filtered_projection_traits(hint.first, begin, end, aabb_traits, index_map)
{
m_closest_primitive = hint.second;
}
Filtered_projection_traits(const Point_and_primitive_id& hint,
Index_type index,
const AABBTraits& aabb_traits,
IndexPropertyMap index_map = IndexPropertyMap())
: Filtered_projection_traits(hint.first, index, aabb_traits, index_map)
{
m_closest_primitive = hint.second;
}
template <typename IndexToIgnoreIterator>
@ -83,8 +98,7 @@ public:
IndexToIgnoreIterator end,
const AABBTraits& aabb_traits,
IndexPropertyMap index_map = IndexPropertyMap())
: m_closest_point_initialized(false),
set_of_indices(begin, end),
: set_of_indices(begin, end),
aabb_traits(aabb_traits),
index_map(index_map)
{
@ -93,12 +107,10 @@ public:
Filtered_projection_traits(Index_type index,
const AABBTraits& aabb_traits,
IndexPropertyMap index_map = IndexPropertyMap())
: m_closest_point_initialized(false),
set_of_indices(),
: set_of_indices({index}),
aabb_traits(aabb_traits),
index_map(index_map)
{
set_of_indices.insert(index);
}
bool go_further() const { return true; }
@ -151,7 +163,7 @@ public:
private:
Point_3 m_closest_point;
typename Primitive::Id m_closest_primitive;
bool m_closest_point_initialized;
bool m_closest_point_initialized = false;
Set_of_indices set_of_indices;
const AABBTraits& aabb_traits;
IndexPropertyMap index_map;

View File

@ -21,6 +21,10 @@
#include "Get_curve_index.h"
#include <CGAL/Mesh_3/Protect_edges_sizing_field.h> // for weight_modifier
#include <cstddef>
#include <memory>
#include <limits>
#include <boost/container/flat_set.hpp>
#if defined(CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY) || defined(CGAL_NO_ASSERTIONS) == 0
# include <sstream>
@ -57,6 +61,8 @@ struct Sizing_field_with_aabb_tree
typedef CGAL::Delaunay_triangulation_3<Kernel_> Dt;
typedef Input_facets_AABB_tree Input_facets_AABB_tree_;
typedef typename Input_facets_AABB_tree_::AABB_traits AABB_traits;
using Point_and_primitive_id = typename AABB_traits::Point_and_primitive_id;
typedef typename Input_facets_AABB_tree_::Primitive Input_facets_AABB_tree_primitive_;
typedef typename MeshDomain::Curves_AABB_tree Input_curves_AABB_tree_;
typedef typename Input_curves_AABB_tree_::Primitive Input_curves_AABB_tree_primitive_;
@ -71,6 +77,22 @@ struct Sizing_field_with_aabb_tree
typename Input_facets_AABB_tree::Primitive>
>::type Facet_patch_id_map;
struct Face_ids_traversal_traits {
using Limits = std::numeric_limits<Patch_index>;
Patch_index min{Limits::max()};
Patch_index max{Limits::lowest()};
Facet_patch_id_map index_map{};
bool go_further() const { return true; }
template <typename T> bool do_intersect(std::nullptr_t, const T&) { return true; }
template <typename P> void intersection(std::nullptr_t, const P& primitive) {
const Patch_index id = get(index_map, primitive.id());
if (id < min) min = id;
if (id > max) max = id;
}
};
Sizing_field_with_aabb_tree
(typename Kernel_::FT d,
const Input_facets_AABB_tree_& aabb_tree,
@ -78,87 +100,127 @@ struct Sizing_field_with_aabb_tree
Get_curve_index get_curve_index = Get_curve_index(),
Facet_patch_id_map facet_patch_id_map = Facet_patch_id_map()
)
: d_(d), aabb_tree(aabb_tree),
domain(domain),
dt(),
get_curve_index(get_curve_index),
facet_patch_id_map(facet_patch_id_map)
: d_ptr{std::make_shared<Private_data>(d,
aabb_tree,
domain,
get_curve_index,
facet_patch_id_map)}
{
if(!d_ptr->aabb_tree.empty()) {
// Initialize the per-patch kd-trees
// - First compute the number of patches and min/max patch ids
Face_ids_traversal_traits traversal_traits;
d_ptr->aabb_tree.traversal(nullptr, traversal_traits);
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
std::cerr << "min: " << traversal_traits.min << ", max: " << traversal_traits.max << '\n';
#endif // CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
d_ptr->min_patch_id = traversal_traits.min;
d_ptr->kd_trees_ptrs.resize(traversal_traits.max - d_ptr->min_patch_id + 1);
using Node = CGAL::AABB_node<AABB_traits>;
using Primitive = typename AABB_traits::Primitive;
using Point_and_primitive_id = typename AABB_traits::Point_and_primitive_id;
std::vector<std::set<Point_and_primitive_id>> vertices_per_patch;
vertices_per_patch.resize(d_ptr->kd_trees_ptrs.size());
// - then fill sets of vertices per patch
auto push_vertex = [&](const auto& primitive) {
const Patch_index id = get(d_ptr->facet_patch_id_map, primitive.id());
const Point_3& p = primitive.reference_point();
vertices_per_patch[id - d_ptr->min_patch_id].emplace(p, primitive.id());
};
struct Visit_all_primitives {
decltype(push_vertex) register_vertex;
bool go_further() const { return true; }
bool do_intersect(std::nullptr_t, const Node&) { return true; }
void intersection(std::nullptr_t, const Primitive& primitive)
{
register_vertex(primitive);
}
} visit_all_primitives{push_vertex};
d_ptr->aabb_tree.traversal(nullptr, visit_all_primitives);
// - then create the kd-trees
for(std::size_t i = 0; i < vertices_per_patch.size(); ++i) {
if(!vertices_per_patch[i].empty()) {
d_ptr->kd_trees_ptrs[i] = std::make_unique<Kd_tree>(vertices_per_patch[i].begin(),
vertices_per_patch[i].end());
}
}
}
{
Corner_index maximal_corner_index = 0;
typedef std::pair<Corner_index, Point_3> Corner_index_and_point;
std::vector<Corner_index_and_point > corners_tmp;
domain.get_corners(std::back_inserter(corners_tmp));
d_ptr->domain.get_corners(std::back_inserter(corners_tmp));
for(const Corner_index_and_point& pair : corners_tmp)
{
// Fill `corners_indices`
if(pair.first > maximal_corner_index) maximal_corner_index = pair.first;
corners_indices.
d_ptr->corners_indices.
insert(typename Corners_indices::value_type(pair.second, pair.first));
}
corners.resize(maximal_corner_index+1);
d_ptr->corners.resize(maximal_corner_index+1);
for(const Corner_index_and_point& pair : corners_tmp)
{
// Fill `corners`
corners[pair.first] = pair.second;
d_ptr->corners[pair.first] = pair.second;
}
}
//fill incidences of corners with curves
corners_incident_curves.resize(corners.size());
for(const typename Corners_indices::value_type& pair :
corners_indices)
{
dt.insert(pair.first);
d_ptr->corners_incident_curves.resize(d_ptr->corners.size());
for(const typename Corners_indices::value_type& pair : d_ptr->corners_indices) {
d_ptr->dt.insert(pair.first);
// Fill `corners_incident_curves[corner_id]`
Curves_ids& incident_curves = corners_incident_curves[pair.second];
domain.get_corner_incident_curves(pair.second,
Curves_ids& incident_curves = d_ptr->corners_incident_curves[pair.second];
d_ptr->domain.get_corner_incident_curves(pair.second,
std::inserter(incident_curves,
incident_curves.end()));
// For each incident loops, insert a point on the loop, as far as
// possible.
for(Curve_index curve_index : incident_curves) {
if(domain.is_loop(curve_index)) {
FT curve_lenght = domain.curve_length(curve_index);
FT curve_length = d_ptr->domain.curve_length(curve_index);
Point_3 other_point =
domain.construct_point_on_curve(pair.first,
curve_index,
curve_lenght / 2);
dt.insert(other_point);
d_ptr->domain.construct_point_on_curve(pair.first,
curve_index,
curve_length / 2);
d_ptr->dt.insert(other_point);
}
}
}
if (aabb_tree.empty())
if (d_ptr->aabb_tree.empty())
return;//there is no surface --> no surface patches
//fill incidences with patches
curves_incident_patches.resize(domain.maximal_curve_index()+1);
corners_incident_patches.resize(corners.size());
d_ptr->curves_incident_patches.resize(domain.maximal_curve_index()+1);
d_ptr->corners_incident_patches.resize(d_ptr->corners.size());
for (Curve_index curve_id = 1;
std::size_t(curve_id) < curves_incident_patches.size();
std::size_t(curve_id) < d_ptr->curves_incident_patches.size();
++curve_id)
{
const typename MeshDomain::Surface_patch_index_set& incident_patches =
domain.get_incidences(curve_id);
d_ptr->domain.get_incidences(curve_id);
// Fill `curves_incident_patches[curve_id]`
curves_incident_patches[curve_id].
d_ptr->curves_incident_patches[curve_id].
insert(boost::container::ordered_unique_range,
incident_patches.begin(), incident_patches.end());
}
for(const typename Corners_indices::value_type& pair :
corners_indices)
{
for(const typename Corners_indices::value_type& pair : d_ptr->corners_indices) {
// Get `corners_incident_curves[corner_id]`
Curves_ids& incident_curves = corners_incident_curves[pair.second];
Curves_ids& incident_curves = d_ptr->corners_incident_curves[pair.second];
// Fill `corners_incident_patches[corner_id]`
Patches_ids& incident_patches = corners_incident_patches[pair.second];
Patches_ids& incident_patches = d_ptr->corners_incident_patches[pair.second];
for(Curve_index curve_index : incident_curves) {
const Patches_ids& curve_incident_patches =
curves_incident_patches[curve_index];
d_ptr->curves_incident_patches[curve_index];
incident_patches.insert(boost::container::ordered_unique_range,
curve_incident_patches.begin(),
curve_incident_patches.end());
@ -166,6 +228,37 @@ struct Sizing_field_with_aabb_tree
}
}
boost::optional<Point_and_primitive_id>
closest_point_on_surfaces(const Point_3& p,
const Patches_ids& patch_ids_to_ignore) const
{
boost::optional<Point_and_primitive_id> result{};
if(d_ptr->aabb_tree.empty()) return result;
for(std::size_t i = 0; i < d_ptr->kd_trees_ptrs.size(); ++i) {
const auto patch_id = static_cast<Patch_index>(i + d_ptr->min_patch_id);
if(patch_ids_to_ignore.find(patch_id) != patch_ids_to_ignore.end()) continue;
if(d_ptr->kd_trees_ptrs[i]) {
const Kd_tree& kd_tree = *d_ptr->kd_trees_ptrs[i];
const Point_and_primitive_id closest_point = kd_tree.closest_point(p);
if(!result || CGAL::compare_distance(p, closest_point.first, result->first) == CGAL::SMALLER)
{
result = closest_point;
}
}
}
if(!result) return result;
CGAL::Mesh_3::Filtered_projection_traits<
AABB_traits,
Facet_patch_id_map
> projection_traits(*result,
patch_ids_to_ignore.begin(), patch_ids_to_ignore.end(),
d_ptr->aabb_tree.traits(),
d_ptr->facet_patch_id_map);
d_ptr->aabb_tree.traversal(p, projection_traits);
result = projection_traits.closest_point_and_primitive();
return result;
}
double operator()(const Point_3& p,
const int dim,
const Index& id) const
@ -177,9 +270,9 @@ struct Sizing_field_with_aabb_tree
<< ", index=#" << CGAL::IO::oformat(id) << "): ";
}
#endif // CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
double result = d_;
double result = d_ptr->d_;
if(dim == 0) {
if(dt.dimension() < 1) {
if(d_ptr->dt.dimension() < 1) {
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
std::cerr << result << "(dt.dimension() < 1)\n";
#endif // CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
@ -189,15 +282,15 @@ struct Sizing_field_with_aabb_tree
typename Dt::Locate_type lt;
int li, lj;
const typename Dt::Cell_handle ch = dt.locate(p, lt, li, lj);
const typename Dt::Cell_handle ch = d_ptr->dt.locate(p, lt, li, lj);
if(lt == Dt::VERTEX) {
// std::cerr << "lt == Dt::VERTEX\n";
const typename Dt::Vertex_handle vh = ch->vertex(li);
std::vector<typename Dt::Vertex_handle> vs;
vs.reserve(32);
dt.finite_adjacent_vertices(vh, std::back_inserter(vs));
d_ptr->dt.finite_adjacent_vertices(vh, std::back_inserter(vs));
CGAL_assertion(!vs.empty());
nearest = dt.point(vs[0]);
nearest = d_ptr->dt.point(vs[0]);
// std::cerr << "sq_dist = " << CGAL::squared_distance(p, nearest)
// << std::endl;
typename Kernel_::Compare_distance_3 compare_dist;
@ -206,44 +299,38 @@ struct Sizing_field_with_aabb_tree
{
// std::cerr << "sq_dist = " << CGAL::squared_distance(p, dt.point(*it))
// << std::endl;
if(compare_dist(p, dt.point(*it), nearest) == CGAL::SMALLER) {
if(compare_dist(p, d_ptr->dt.point(*it), nearest) == CGAL::SMALLER) {
// std::cerr << " nearest!\n";
nearest = dt.point(*it);
nearest = d_ptr->dt.point(*it);
}
}
} else {
// std::cerr << "lt=" << lt << std::endl;
const typename Dt::Vertex_handle vh = dt.nearest_vertex(p, ch);
nearest = dt.point(vh);
const typename Dt::Vertex_handle vh = d_ptr->dt.nearest_vertex(p, ch);
nearest = d_ptr->dt.point(vh);
}
const FT dist = CGAL_NTS sqrt(CGAL::squared_distance( nearest, p));
// std::cerr << (std::min)(dist / FT(1.5), d_) << "\n";
result = (std::min)(dist / FT(2), result);
// now search in the AABB tree
typename Corners_indices::const_iterator ids_it = corners_indices.find(p);
if(ids_it == corners_indices.end()) {
typename Corners_indices::const_iterator ids_it =
d_ptr->corners_indices.find(p);
if(ids_it == d_ptr->corners_indices.end()) {
std::cerr << "ERROR at " << __FILE__ << " line " << __LINE__ << "\n";
}
else if(!aabb_tree.empty()) {
const Patches_ids& ids = corners_incident_patches[ids_it->second];
else if(!d_ptr->aabb_tree.empty()) {
const Patches_ids& ids = d_ptr->corners_incident_patches[ids_it->second];
CGAL_assertion(! ids.empty());
CGAL::Mesh_3::Filtered_projection_traits<
typename Input_facets_AABB_tree_::AABB_traits,
Facet_patch_id_map
> projection_traits(ids.begin(), ids.end(),
aabb_tree.traits(),
facet_patch_id_map);
const auto closest_point_and_primitive = closest_point_on_surfaces(p, ids);
aabb_tree.traversal(p, projection_traits);
if(projection_traits.found()) {
if(closest_point_and_primitive != boost::none) {
result =
(std::min)(0.9 / CGAL::sqrt(CGAL::Mesh_3::internal::weight_modifier) *
CGAL_NTS
sqrt(CGAL::squared_distance(p,
projection_traits.closest_point())),
closest_point_and_primitive->first)),
result);
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
{
@ -258,10 +345,10 @@ struct Sizing_field_with_aabb_tree
"Ids are { ")
% group(setprecision(17),result)
% group(setprecision(17),p)
% CGAL::IO::oformat(get(facet_patch_id_map,
projection_traits.closest_point_and_primitive().second))
% CGAL::IO::oformat(get(d_ptr->facet_patch_id_map,
closest_point_and_primitive->second))
% group(setprecision(17),
projection_traits.closest_point_and_primitive().first);
closest_point_and_primitive->first);
for(Patch_index i : ids) {
s << CGAL::IO::oformat(i) << " ";
}
@ -285,37 +372,33 @@ struct Sizing_field_with_aabb_tree
}
else { // dim == 1
const typename MeshDomain::Curve_index& curve_id =
domain.curve_index(id);
if(!aabb_tree.empty()) {
const Patches_ids& ids = curves_incident_patches[curve_id];
CGAL_assertion(! ids.empty());
d_ptr->domain.curve_index(id);
const Patches_ids& ids = d_ptr->curves_incident_patches[curve_id];
CGAL_assertion(! ids.empty());
if(!d_ptr->aabb_tree.empty()) {
//Compute distance to surface patches
CGAL::Mesh_3::Filtered_projection_traits
<
typename Input_facets_AABB_tree_::AABB_traits
, Facet_patch_id_map
> projection_traits(ids.begin(), ids.end(),
aabb_tree.traits(),
facet_patch_id_map);
aabb_tree.traversal(p, projection_traits);
if(!projection_traits.found()) {
const auto closest_point_and_primitive = closest_point_on_surfaces(p, ids);
if(closest_point_and_primitive == boost::none) {
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
std::cerr << result << " (projection not found)\n";
std::cerr << result << " (projection not found) ids:";
for(Patch_index i : ids) {
std::cerr << " " << CGAL::IO::oformat(i);
}
std::cerr << "\n";
#endif // CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
return result;
}
CGAL_assertion(ids.count(get(facet_patch_id_map,
projection_traits.closest_point_and_primitive().second)) == 0);
CGAL_assertion(ids.count(get(d_ptr->facet_patch_id_map,
closest_point_and_primitive->second)) == 0);
result =
(std::min)(0.9 / CGAL::sqrt(CGAL::Mesh_3::internal::weight_modifier) *
CGAL_NTS
sqrt(CGAL::squared_distance(p,
projection_traits.closest_point())),
closest_point_and_primitive->first)),
result);
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
@ -327,8 +410,8 @@ struct Sizing_field_with_aabb_tree
"Closest face id: %4%\n"
"Ids are { ")
% result % p % curve_id
% CGAL::IO::oformat(get(facet_patch_id_map,
projection_traits.closest_point_and_primitive().second));
% CGAL::IO::oformat(get(d_ptr->facet_patch_id_map,
closest_point_and_primitive->second));
for(Patch_index i : ids) {
s << CGAL::IO::oformat(i) << " ";
}
@ -346,8 +429,8 @@ struct Sizing_field_with_aabb_tree
"Closest face id: %4%\n"
"Ids are { ")
% result % p % curve_id
% CGAL::IO::oformat(get(facet_patch_id_map,
projection_traits.closest_point_and_primitive().second));
% CGAL::IO::oformat(get(d_ptr->facet_patch_id_map,
closest_point_and_primitive->second));
for(Patch_index i : ids) {
s << CGAL::IO::oformat(i) << " ";
}
@ -362,7 +445,7 @@ struct Sizing_field_with_aabb_tree
"Closest face id: %4%\n"
"Ids are { ")
% result % p % curve_id
% projection_traits.closest_point_and_primitive().second->patch_id();
% closest_point_and_primitive->second->patch_id();
for(Patch_index i : ids) {
s << CGAL::IO::oformat(i) << " ";
}
@ -377,25 +460,25 @@ struct Sizing_field_with_aabb_tree
CGAL::Mesh_3::Filtered_projection_traits<typename Input_curves_AABB_tree_::AABB_traits,
Get_curve_index >
curves_projection_traits(curve_id,
domain.curves_aabb_tree().traits(),
get_curve_index);
d_ptr->domain.curves_aabb_tree().traits(),
d_ptr->get_curve_index);
domain.curves_aabb_tree().traversal(p, curves_projection_traits);
d_ptr->domain.curves_aabb_tree().traversal(p, curves_projection_traits);
//Compute distance to the curve on which p lies
typedef typename GeomTraits::Segment_3 Segment_3;
typedef typename GeomTraits::Plane_3 Plane_3;
const typename Input_curves_AABB_tree_::Point_and_primitive_id& ppid
= domain.curves_aabb_tree().closest_point_and_primitive(p);
= d_ptr->domain.curves_aabb_tree().closest_point_and_primitive(p);
Segment_3 curr_segment(*ppid.second.second, *(ppid.second.second + 1));
Plane_3 curr_ortho_plane(p, curr_segment.to_vector()/*normal*/);
Input_curves_AABB_tree_primitive_ curr_prim(ppid.second);
std::vector<Input_curves_AABB_tree_primitive_> prims;
domain.curves_aabb_tree().all_intersected_primitives(curr_ortho_plane,
std::back_inserter(prims));
d_ptr->domain.curves_aabb_tree().
all_intersected_primitives(curr_ortho_plane, std::back_inserter(prims));
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
std::cerr << std::endl;
@ -421,12 +504,12 @@ struct Sizing_field_with_aabb_tree
if (const Point_3* pp = boost::get<Point_3>(&*int_res))
{
FT new_sqd = CGAL::squared_distance(p, *pp);
FT gdist = CGAL::abs(domain.signed_geodesic_distance(p, *pp, curve_id));
FT dist = CGAL::abs(d_ptr->domain.signed_geodesic_distance(p, *pp, curve_id));
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
std::cerr << "Intersection point : Point_3(" << *pp << ") ";
std::cerr << "\n new_sqd = " << new_sqd ;
std::cerr << "\n gdist = " << gdist << "\n";
std::cerr << "\n dist = " << dist << "\n";
#endif
if (new_sqd * 1e10 < CGAL::squared_distance(curr_segment.source(),
curr_segment.target()))
@ -437,7 +520,7 @@ struct Sizing_field_with_aabb_tree
#endif
continue;
}
if (CGAL_NTS sqrt(new_sqd) > 0.9 * gdist)
if (CGAL_NTS sqrt(new_sqd) > 0.9 * dist)
continue;
if (sqd_intersection == -1 || new_sqd < sqd_intersection)
{
@ -468,7 +551,7 @@ struct Sizing_field_with_aabb_tree
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
std::cout << " curve_id = " << curve_id
<< " proj_cid = " << closest_primitive.id().first->first
<< " (" << get(get_curve_index, closest_primitive.id()) << ")"
<< " (" << get(d_ptr->get_curve_index, closest_primitive.id()) << ")"
<< std::endl;
std::cerr << " --- domain.curves_aabb_tree().traversal \n";
#endif // CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
@ -482,7 +565,7 @@ struct Sizing_field_with_aabb_tree
double new_result =
(std::min)(0.45 / CGAL::sqrt(CGAL::Mesh_3::internal::weight_modifier) *
CGAL_NTS sqrt(sqd_intersection),
d_);
d_ptr->d_);
#ifdef CGAL_MESH_3_PROTECTION_HIGH_VERBOSITY
std::cerr << "result = " << result << "\n";
@ -515,17 +598,34 @@ struct Sizing_field_with_aabb_tree
return result;
}
private:
typename Kernel_::FT d_;
const Input_facets_AABB_tree_& aabb_tree;
const MeshDomain& domain;
Dt dt;
Corners corners;
Corners_indices corners_indices;
Curves_incident_patches curves_incident_patches;
Corners_incident_patches corners_incident_patches;
Corners_incident_curves corners_incident_curves;
Get_curve_index get_curve_index;
Facet_patch_id_map facet_patch_id_map;
using Kd_tree = CGAL::AABB_search_tree<AABB_traits>;
struct Private_data {
using FT = typename Kernel_::FT;
Private_data(FT d, const Input_facets_AABB_tree_& aabb_tree,
const MeshDomain& domain,
Get_curve_index get_curve_index,
Facet_patch_id_map facet_patch_id_map)
: d_(d)
, aabb_tree(aabb_tree)
, domain(domain)
, get_curve_index(get_curve_index)
, facet_patch_id_map(facet_patch_id_map)
{}
FT d_;
const Input_facets_AABB_tree_& aabb_tree;
const MeshDomain& domain;
Get_curve_index get_curve_index;
Facet_patch_id_map facet_patch_id_map;
Dt dt{};
Corners corners{};
Corners_indices corners_indices{};
Curves_incident_patches curves_incident_patches{};
Corners_incident_patches corners_incident_patches{};
Corners_incident_curves corners_incident_curves{};
std::vector<std::unique_ptr<Kd_tree>> kd_trees_ptrs{};
Patch_index min_patch_id{};
};
std::shared_ptr<Private_data> d_ptr;
};
#endif // CGAL_MESH_3_SIZING_FIELD_WITH_AABB_TREE_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,235 @@
// Copyright (c) 2022 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Sebastien Loriot
//
//******************************************************************************
//
//******************************************************************************
#ifndef CGAL_MESH_3_FEATURES_DETECTION_COMBINATIONS_H
#define CGAL_MESH_3_FEATURES_DETECTION_COMBINATIONS_H
#include <CGAL/license/Mesh_3.h>
#include <array>
namespace CGAL
{
namespace Mesh_3
{
namespace internal
{
const std::array<std::uint8_t, 8> combinations[]
= {
// 1 color
{0,0,0,0,0,0,0,0}, //0
// 2 colors
{0,0,0,0,0,0,0,1}, //1
{0,0,0,0,0,0,1,1}, //2
// 3 colors
{0,0,0,0,0,0,1,2}, //3
{0,0,0,0,0,1,1,0},
{0,0,0,0,0,1,1,1},
{0,0,0,0,0,1,1,2},
{0,0,0,0,0,1,2,0},
{0,0,0,0,0,1,2,1},
{0,0,0,0,1,1,1,1},
{0,0,0,0,1,1,1,2},
{0,0,0,0,1,1,2,2},
{0,0,0,0,1,2,2,1},
{0,0,0,1,0,1,1,0},
{0,0,0,1,0,1,1,1},
{0,0,0,1,0,1,1,2},
{0,0,0,1,0,1,2,0},
{0,0,0,1,0,1,2,1},
{0,0,0,1,0,1,2,2},
{0,0,0,1,1,0,0,0},
{0,0,0,1,1,0,0,1},
{0,0,0,1,1,0,0,2},
{0,0,0,1,1,0,1,1},
{0,0,0,1,1,0,1,2},
{0,0,0,1,1,0,2,2},
{0,0,0,1,1,1,1,0},
{0,0,0,1,1,1,1,2},
{0,0,0,1,1,1,2,0},
{0,0,0,1,1,1,2,1},
{0,0,0,1,1,1,2,2},
{0,0,0,1,1,2,2,0},
{0,0,0,1,1,2,2,1},
{0,0,0,1,1,2,2,2},
{0,0,0,1,2,0,0,0},
{0,0,0,1,2,0,0,1},
{0,0,0,1,2,0,0,2},
{0,0,0,1,2,0,1,2},
{0,0,0,1,2,0,2,1},
{0,0,0,1,2,1,1,0},
{0,0,0,1,2,1,1,2},
{0,0,0,1,2,1,2,0},
{0,0,0,1,2,1,2,1},
{0,0,0,1,2,1,2,2},
{0,0,0,1,2,2,2,1},
{0,0,1,1,1,1,0,0},
{0,0,1,1,1,1,0,2},
{0,0,1,1,1,1,2,2},
{0,0,1,1,1,2,0,2},
{0,0,1,1,1,2,2,0},
{0,0,1,2,1,2,0,0},
{0,0,1,2,1,2,0,1},
{0,0,1,2,1,2,2,1},
{0,0,1,2,2,1,0,0},
{0,0,1,2,2,1,0,1},
{0,1,1,0,1,0,0,1},
{0,1,1,0,1,0,0,2},
{0,1,1,0,1,2,2,1},
{0,1,1,2,1,2,2,0}, //57
// 4 colors
{0,0,0,0,0,1,2,3}, //58
{0,0,0,0,1,1,2,3},
{0,0,0,0,1,2,2,3},
{0,0,0,1,0,1,2,3},
{0,0,0,1,0,2,3,0},
{0,0,0,1,0,2,3,1},
{0,0,0,1,1,0,2,3},
{0,0,0,1,1,1,2,3},
{0,0,0,1,1,2,2,3},
{0,0,0,1,1,2,3,0},
{0,0,0,1,1,2,3,1},
{0,0,0,1,1,2,3,2},
{0,0,0,1,2,0,0,3},
{0,0,0,1,2,0,1,3},
{0,0,0,1,2,0,2,3},
{0,0,0,1,2,0,3,3},
{0,0,0,1,2,1,1,3},
{0,0,0,1,2,1,2,3},
{0,0,0,1,2,1,3,0},
{0,0,0,1,2,1,3,1},
{0,0,0,1,2,1,3,2},
{0,0,0,1,2,1,3,3},
{0,0,0,1,2,2,2,3},
{0,0,0,1,2,2,3,0},
{0,0,0,1,2,2,3,1},
{0,0,0,1,2,2,3,2},
{0,0,0,1,2,2,3,3},
{0,0,0,1,2,3,3,0},
{0,0,0,1,2,3,3,1},
{0,0,0,1,2,3,3,2},
{0,0,0,1,2,3,3,3},
{0,0,1,1,1,1,2,3},
{0,0,1,1,1,2,0,3},
{0,0,1,1,1,2,2,3},
{0,0,1,1,1,2,3,0},
{0,0,1,1,1,2,3,2},
{0,0,1,1,1,2,3,3},
{0,0,1,1,2,2,3,3},
{0,0,1,1,2,3,2,3},
{0,0,1,1,2,3,3,2},
{0,0,1,2,1,2,0,3},
{0,0,1,2,1,2,2,3},
{0,0,1,2,1,2,3,3},
{0,0,1,2,1,3,0,0},
{0,0,1,2,1,3,0,1},
{0,0,1,2,1,3,0,2},
{0,0,1,2,1,3,2,0},
{0,0,1,2,1,3,2,1},
{0,0,1,2,1,3,2,3},
{0,0,1,2,2,1,0,3},
{0,0,1,2,2,1,1,3},
{0,0,1,2,2,1,3,3},
{0,0,1,2,2,3,0,0},
{0,0,1,2,2,3,0,1},
{0,0,1,2,2,3,0,2},
{0,0,1,2,2,3,1,3},
{0,0,1,2,2,3,3,1},
{0,1,1,0,1,0,2,3},
{0,1,1,0,1,2,2,3},
{0,1,1,0,1,2,3,1},
{0,1,1,0,2,3,3,2},
{0,1,1,2,1,2,2,3},
{0,1,1,2,1,2,3,0},
{0,1,1,2,2,3,3,0},
{0,1,1,2,3,0,2,3},
{0,1,2,3,3,2,1,0}, //123
// 5 colors
{0,0,0,0,1,2,3,4}, //124
{0,0,0,1,0,2,3,4},
{0,0,0,1,1,2,3,4},
{0,0,0,1,2,0,3,4},
{0,0,0,1,2,1,3,4},
{0,0,0,1,2,2,3,4},
{0,0,0,1,2,3,3,4},
{0,0,0,1,2,3,4,0},
{0,0,0,1,2,3,4,1},
{0,0,0,1,2,3,4,2},
{0,0,0,1,2,3,4,3},
{0,0,1,1,1,2,3,4},
{0,0,1,1,2,2,3,4},
{0,0,1,1,2,3,2,4},
{0,0,1,1,2,3,3,4},
{0,0,1,2,1,2,3,4},
{0,0,1,2,1,3,0,4},
{0,0,1,2,1,3,2,4},
{0,0,1,2,1,3,4,0},
{0,0,1,2,1,3,4,1},
{0,0,1,2,1,3,4,2},
{0,0,1,2,1,3,4,4},
{0,0,1,2,2,1,3,4},
{0,0,1,2,2,3,0,4},
{0,0,1,2,2,3,1,4},
{0,0,1,2,2,3,2,4},
{0,0,1,2,2,3,3,4},
{0,0,1,2,2,3,4,4},
{0,0,1,2,3,4,0,0},
{0,0,1,2,3,4,0,1},
{0,0,1,2,3,4,1,4},
{0,0,1,2,3,4,2,1},
{0,0,1,2,3,4,2,3},
{0,1,1,0,1,2,3,4},
{0,1,1,0,2,3,3,4},
{0,1,1,2,1,2,3,4},
{0,1,1,2,1,3,4,0},
{0,1,1,2,1,3,4,1},
{0,1,1,2,2,0,3,4},
{0,1,1,2,2,3,3,4},
{0,1,1,2,2,3,4,0},
{0,1,1,2,3,0,2,4},
{0,1,2,3,3,2,1,4}, //166
// 6 colors
{0,0,0,1,2,3,4,5}, //167
{0,0,1,1,2,3,4,5},
{0,0,1,2,1,3,4,5},
{0,0,1,2,2,3,4,5},
{0,0,1,2,3,4,0,5},
{0,0,1,2,3,4,1,5},
{0,0,1,2,3,4,2,5},
{0,0,1,2,3,4,5,5},
{0,1,1,0,2,3,4,5},
{0,1,1,2,1,3,4,5},
{0,1,1,2,2,3,4,5},
{0,1,1,2,3,0,4,5},
{0,1,1,2,3,4,4,5},
{0,1,1,2,3,4,5,3},
{0,1,2,3,3,2,4,5}, //181
// 7 colors
{0,0,1,2,3,4,5,6}, //182
{0,1,1,2,3,4,5,6},
{0,1,2,3,3,4,5,6}, //184
// 8 colors
{0,1,2,3,4,5,6,7} //185
};
}//end namespace internal
}//end namespace Mesh_3
}//end namespace CGAL
#endif // CGAL_MESH_3_FEATURES_DETECTION_COMBINATIONS_H

View File

@ -0,0 +1,62 @@
// Copyright (c) 2022 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Sebastien Loriot
//
//******************************************************************************
//
//******************************************************************************
#ifndef CGAL_MESH_3_FEATURES_DETECTION_COORDINATES_H
#define CGAL_MESH_3_FEATURES_DETECTION_COORDINATES_H
#include <CGAL/license/Mesh_3.h>
#include <array>
namespace CGAL
{
namespace Mesh_3
{
namespace internal
{
using Coordinates = std::array<int, 3>;
constexpr Coordinates coordinates[8] = { {0, 0, 0},
{1, 0, 0},
{0, 1, 0},
{1, 1, 0},
{0, 0, 1},
{1, 0, 1},
{0, 1, 1},
{1, 1, 1} };
inline Coordinates minus(const Coordinates& b, const Coordinates& a) {
return { b[0] - a[0], b[1] - a[1], b[2] - a[2] };
}
inline Coordinates cross(Coordinates a, Coordinates b) {
return { a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] };
}
inline Coordinates square(Coordinates c) {
return { c[0] * c[0], c[1] * c[1], c[2] * c[2] };
}
inline int dist(Coordinates a, Coordinates b) {
auto s = square(minus(b, a));
return s[0] + s[1] + s[2];
}
}//end namespace internal
}//end namespace Mesh_3
}//end namespace CGAL
#endif // CGAL_MESH_3_FEATURES_DETECTION_COORDINATES_H

View File

@ -0,0 +1,89 @@
// Copyright (c) 2022 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Sebastien Loriot
//
//******************************************************************************
//
//******************************************************************************
#ifndef CGAL_MESH_3_FEATURES_DETECTION_CUBE_ISOMETRIES_H
#define CGAL_MESH_3_FEATURES_DETECTION_CUBE_ISOMETRIES_H
#include <CGAL/license/Mesh_3.h>
#include <array>
namespace CGAL
{
namespace Mesh_3
{
namespace internal
{
using Permutation = std::array<std::uint8_t, 8>;
constexpr Permutation cube_isometries[] = {
{0,1,2,3,4,5,6,7},
{1,0,3,2,5,4,7,6},
{4,5,0,1,6,7,2,3},
{5,4,1,0,7,6,3,2},
{6,7,4,5,2,3,0,1},
{7,6,5,4,3,2,1,0},
{2,3,6,7,0,1,4,5},
{3,2,7,6,1,0,5,4},
{1,5,3,7,0,4,2,6},
{5,1,7,3,4,0,6,2},
{5,4,7,6,1,0,3,2},
{4,5,6,7,0,1,2,3},
{4,0,6,2,5,1,7,3},
{0,4,2,6,1,5,3,7},
{1,3,0,2,5,7,4,6},
{3,1,2,0,7,5,6,4},
{3,2,1,0,7,6,5,4},
{2,3,0,1,6,7,4,5},
{2,0,3,1,6,4,7,5},
{0,2,1,3,4,6,5,7},
{1,0,5,4,3,2,7,6},
{0,1,4,5,2,3,6,7},
{7,3,5,1,6,2,4,0},
{3,7,1,5,2,6,0,4},
{7,6,3,2,5,4,1,0},
{6,7,2,3,4,5,0,1},
{2,6,0,4,3,7,1,5},
{6,2,4,0,7,3,5,1},
{4,6,5,7,0,2,1,3},
{6,4,7,5,2,0,3,1},
{7,5,6,4,3,1,2,0},
{5,7,4,6,1,3,0,2},
{0,4,1,5,2,6,3,7},
{4,0,5,1,6,2,7,3},
{3,1,7,5,2,0,6,4},
{1,3,5,7,0,2,4,6},
{5,7,1,3,4,6,0,2},
{7,5,3,1,6,4,2,0},
{3,7,2,6,1,5,0,4},
{7,3,6,2,5,1,4,0},
{0,2,4,6,1,3,5,7},
{2,0,6,4,3,1,7,5},
{5,1,4,0,7,3,6,2},
{1,5,0,4,3,7,2,6},
{6,2,7,3,4,0,5,1},
{2,6,3,7,0,4,1,5},
{6,4,2,0,7,5,3,1},
{4,6,0,2,5,7,1,3}
};
constexpr int num_isometries = 48;
}//end namespace internal
}//end namespace Mesh_3
}//end namespace CGAL
#endif // CGAL_MESH_3_FEATURES_DETECTION_CUBE_ISOMETRIES_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,72 @@
// Copyright (c) 2022 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Sebastien Loriot, Jane Tournois
//
//******************************************************************************
//
//******************************************************************************
#ifndef CGAL_MESH_3_FEATURES_DETECTION_HELPERS_H
#define CGAL_MESH_3_FEATURES_DETECTION_HELPERS_H
#include <CGAL/license/Mesh_3.h>
#include <string>
namespace CGAL
{
namespace Mesh_3
{
namespace internal
{
template<typename Word_type, bool b = (sizeof(Word_type) > 1)>
struct Color_transformation_helper
{
using type = std::unordered_map<Word_type, std::uint8_t>;
static void reset(type& t)
{
t.clear();
}
static bool is_valid(const type& t, const Word_type& w)
{
return t.find(w) != t.end();
}
};
template<typename Word_type>
struct Color_transformation_helper<Word_type, false>
{
using type = std::array<std::uint8_t, (1 << (sizeof(Word_type) * 8))>;
static void reset(type& t)
{
std::fill(t.begin(), t.end(), 8/*invalid_word*/);
}
static bool is_valid(const type& t, const Word_type& w)
{
return t[w] != 8;/*invalid_word*/
}
};
template<typename Array>
void debug_cerr(const char* title, const Array& tab)
{
std::cerr << title << " [";
for (const auto t : tab)
std::cout << std::to_string(t) << " ";
std::cout << "]" << std::endl;
}
}//end namespace internal
}//end namespace Mesh_3
}//end namespace CGAL
#endif // CGAL_MESH_3_FEATURES_DETECTION_HELPERS_H

View File

@ -309,9 +309,9 @@ CGAL::Image_3 generate_label_weights_with_known_word_type(const CGAL::Image_3& i
* @returns a `CGAL::Image_3` of weights used to build a quality `Labeled_mesh_domain_3`,
* with the same dimensions as `image`
*/
inline
CGAL::Image_3 generate_label_weights(const CGAL::Image_3& image,
const float& sigma)
const float& sigma)
{
CGAL_IMAGE_IO_CASE(image.image(),
return generate_label_weights_with_known_word_type<Word>(image, sigma);

View File

@ -15,7 +15,6 @@
#include <CGAL/license/Mesh_3.h>
#include <vector>
#include <map>
#include <utility> // std::swap
@ -23,17 +22,23 @@
#include <CGAL/tuple.h>
#include <CGAL/Image_3.h>
#include <CGAL/number_utils.h>
#include <CGAL/squared_distance_3.h>
#include <CGAL/boost/graph/split_graph_into_polylines.h>
#include <CGAL/Mesh_3/internal/Graph_manipulations.h>
#include <boost/graph/adjacency_list.hpp>
#include <CGAL/Labeled_mesh_domain_3.h> // for CGAL::Null_subdomain_index
#include <CGAL/number_utils.h>
#include <boost/utility.hpp> // for boost::prior
#include <boost/optional.hpp>
#include <CGAL/Search_traits_3.h>
#include <CGAL/Orthogonal_incremental_neighbor_search.h>
#include <CGAL/Mesh_3/Null_subdomain_index.h>
#include <type_traits>
namespace CGAL {
namespace Mesh_3 {
namespace internal {
@ -1128,6 +1133,63 @@ polylines_to_protect(const CGAL::Image_3& cgal_image,
existing_polylines_end);
}
template <typename PolylineRange1, typename PolylineRange2>
void
merge_and_snap_polylines(const CGAL::Image_3& image,
PolylineRange1& polylines_to_snap,
const PolylineRange2& existing_polylines)
{
static_assert(std::is_same<typename PolylineRange1::value_type::value_type,
typename PolylineRange2::value_type::value_type>::value,
"Polyline ranges should have same point type");
using P = typename PolylineRange1::value_type::value_type;
using K = typename Kernel_traits<P>::Kernel;
using CGAL::internal::polylines_to_protect_namespace::Vertex_info;
using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS,
Vertex_info<P> >;
using vertex_descriptor = typename boost::graph_traits<Graph>::vertex_descriptor;
// build graph of polylines_to_snap
Graph graph;
typedef Mesh_3::internal::Returns_midpoint<K, int> Midpoint_fct;
Mesh_3::internal::Graph_manipulations<Graph,
P,
int,
Midpoint_fct> g_manip(graph);
for (const auto& polyline : polylines_to_snap)
{
if (polyline.size() < 2)
continue;
auto pit = polyline.begin();
while (boost::next(pit) != polyline.end())
{
vertex_descriptor v = g_manip.get_vertex(*pit, false);
vertex_descriptor w = g_manip.get_vertex(*boost::next(pit), false);
g_manip.try_add_edge(v, w);
++pit;
}
}
// snap graph to existing_polylines
snap_graph_vertices(graph,
image.vx(), image.vy(), image.vz(),
boost::begin(existing_polylines), boost::end(existing_polylines),
K());
// rebuild polylines_to_snap
polylines_to_snap.clear();
Mesh_3::Polyline_visitor<P, Graph> visitor(polylines_to_snap, graph);
Less_for_Graph_vertex_descriptors<Graph> less(graph);
const Graph& const_graph = graph;
Mesh_3::Angle_tester<K> angle_tester(90.);
split_graph_into_polylines(const_graph, visitor, angle_tester, less);
}
} // namespace CGAL
#endif // CGAL_MESH_3_POLYLINES_TO_PROTECT_H

View File

@ -232,6 +232,13 @@ struct C3t3_initializer < C3T3, MD, MC, true, CGAL::Tag_true >
if (c3t3.number_of_facets() == 0) {
need_more_init = true;
}
else
{
helper.update_restricted_cells();
if(c3t3.number_of_cells() == 0) {
need_more_init = true;
}
}
}
if(need_more_init) {
init_c3t3(c3t3, domain, criteria,

View File

@ -31,6 +31,7 @@ create_single_source_cgal_program( "test_without_detect_features.cpp" )
if(CGAL_ImageIO_USE_ZLIB)
create_single_source_cgal_program( "test_meshing_3D_image.cpp" )
create_single_source_cgal_program( "test_meshing_3D_image_deprecated.cpp" )
create_single_source_cgal_program( "test_meshing_3D_image_with_features.cpp" )
create_single_source_cgal_program( "test_meshing_3D_gray_image.cpp" )
create_single_source_cgal_program( "test_meshing_3D_gray_image_deprecated.cpp" )
else()
@ -64,6 +65,7 @@ foreach(target
test_without_detect_features
test_meshing_3D_image
test_meshing_3D_image_deprecated
test_meshing_3D_image_with_features
test_meshing_3D_gray_image
test_meshing_3D_gray_image_deprecated
test_meshing_implicit_function

View File

@ -0,0 +1,199 @@
// Copyright (c) 2009 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Stephane Tayeb, Jane Tournois
//
//******************************************************************************
// File Description :
//******************************************************************************
#include "test_meshing_utilities.h"
#include <CGAL/Image_3.h>
#include <CGAL/Labeled_mesh_domain_3.h>
#include <CGAL/Mesh_domain_with_polyline_features_3.h>
#include <CGAL/Mesh_3/Detect_features_in_image.h>
#include <CGAL/Mesh_3/Detect_features_on_image_bbox.h>
#include <CGAL/use.h>
#include <vector>
#include <cstddef>
#include <fstream>
template <typename Point_3>
bool read_polylines(const std::string fname,
std::vector<std::vector<Point_3> >& polylines)
{
std::ifstream ifs(fname);
if(ifs.bad()) return false;
std::size_t n;
while(ifs >> n) {
polylines.resize(polylines.size()+1);
std::vector<Point_3>& polyline = polylines.back();
while(n-- != 0) {
Point_3 p;
ifs >> p;
if(ifs.fail()) return false;
polyline.push_back(p);
}
}
if(ifs.bad()) return false;
else return ifs.eof();
}
template <typename Concurrency_tag = CGAL::Sequential_tag>
struct Image_tester : public Tester<K_e_i>
{
typedef CGAL::Image_3 Image;
typedef CGAL::Labeled_mesh_domain_3<K_e_i> Domain;
typedef CGAL::Mesh_domain_with_polyline_features_3<Domain> Mesh_domain;
typedef typename CGAL::Mesh_triangulation_3<
Mesh_domain,
CGAL::Kernel_traits<Mesh_domain>::Kernel,
Concurrency_tag>::type Tr;
typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3;
typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
void mesh_and_verify(Mesh_domain& domain, const Image& image, const double volume) const
{
namespace p = CGAL::parameters;
// Set mesh criteria
Mesh_criteria criteria(p::edge_size = 2 * image.vx(),
p::facet_angle = 30,
p::facet_size = 20 * image.vx(),
p::facet_distance = 5 * image.vx(),
p::cell_radius_edge_ratio = 3.,
p::cell_size = 25 * image.vx());
// Mesh generation
C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(domain, criteria,
CGAL::parameters::no_exude(),
CGAL::parameters::no_perturb());
c3t3.remove_isolated_vertices();
// Verify
this->verify_c3t3_volume(c3t3, volume * 0.95, volume * 1.05);
this->verify(c3t3, domain, criteria, Bissection_tag());
typedef typename Mesh_domain::Surface_patch_index Patch_id;
CGAL_static_assertion(CGAL::Output_rep<Patch_id>::is_specialized);
CGAL_USE_TYPE(Patch_id);
}
public:
void image() const
{
namespace p = CGAL::parameters;
std::cout << "\tSeed is\t"
<< CGAL::get_default_random().get_seed() << std::endl;
//-------------------------------------------------------
// Data generation
//-------------------------------------------------------
Image image;
image.read(CGAL::data_file_path("images/liver.inr.gz"));
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain
(p::image = image,
p::relative_error_bound = 1e-9,
CGAL::parameters::p_rng = &CGAL::get_default_random(),
CGAL::parameters::features_detector = CGAL::Mesh_3::Detect_features_in_image());
mesh_and_verify(domain, image, 1772330.);
}
void image_in_bbox() const
{
namespace p = CGAL::parameters;
std::cout << "\tSeed is\t"
<< CGAL::get_default_random().get_seed() << std::endl;
//-------------------------------------------------------
// Data generation
//-------------------------------------------------------
Image image;
image.read(CGAL::data_file_path("images/40420.inr"));
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain
(p::image = image,
p::relative_error_bound = 1e-9,
CGAL::parameters::p_rng = &CGAL::get_default_random(),
CGAL::parameters::features_detector = CGAL::Mesh_3::Detect_features_on_image_bbox());
mesh_and_verify(domain, image, 625044.);
}
void image_with_input_features() const
{
namespace p = CGAL::parameters;
std::cout << "\tSeed is\t"
<< CGAL::get_default_random().get_seed() << std::endl;
//-------------------------------------------------------
// Data generation
//-------------------------------------------------------
Image image;
image.read(CGAL::data_file_path("images/40420.inr"));
const std::string lines_fname = CGAL::data_file_path("images/420.polylines.txt");
using Point_3 = Domain::Point_3;
std::vector<std::vector<Point_3> > features_input;
if (!read_polylines(lines_fname, features_input)) // see file "read_polylines.h"
assert(false);
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain
(p::image = image,
p::relative_error_bound = 1e-9,
CGAL::parameters::p_rng = &CGAL::get_default_random(),
CGAL::parameters::features_detector = CGAL::Mesh_3::Detect_features_on_image_bbox(),
CGAL::parameters::input_features = std::cref(features_input));
mesh_and_verify(domain, image, 632091.);
}
};
int main()
{
Image_tester<> test_epic;
std::cerr << "Mesh generation from a 3D image"
<< " with detection of triple lines:\n";
test_epic.image();
std::cerr << "Mesh generation from a 3D image"
<< " with detection of triple lines on bbox only:\n";
test_epic.image_in_bbox();
std::cerr << "Mesh generation from a 3D image"
<< " with detection of triple lines on bbox"
<< " and input feature polylines:\n";
test_epic.image_with_input_features();
#ifdef CGAL_LINKED_WITH_TBB
Image_tester<CGAL::Parallel_tag> test_epic_p;
std::cerr << "Parallel mesh generation from a 3D image"
<< " with detection of triple lines:\n";
test_epic_p.image();
std::cerr << "Parallel mesh generation from a 3D image"
<< " with detection of triple lines on bbox only:\n";
test_epic_p.image_in_bbox();
std::cerr << "Parallel mesh generation from a 3D image"
<< " with detection of triple lines on bbox"
<< " and input feature polylines:\n";
test_epic_p.image_with_input_features();
#endif
return EXIT_SUCCESS;
}

View File

@ -0,0 +1 @@
INRIA (France)

View File

@ -662,10 +662,6 @@ CGAL::Comparison_result
// NT
friend bool operator == (const Sqrt_extension& p, const NT& num)
{ return (p-num).is_zero();}
friend bool operator < (const Sqrt_extension& p, const NT& num)
{ return ( p.compare(num) == CGAL::SMALLER ); }
friend bool operator > (const Sqrt_extension& p, const NT& num)
{ return ( p.compare(num) == CGAL::LARGER ); }
//CGAL_int(NT)
friend bool operator == (const Sqrt_extension& p, CGAL_int(NT) num)
@ -676,6 +672,19 @@ CGAL::Comparison_result
{ return ( p.compare(num) == CGAL::LARGER ); }
};
// The two operators are moved out of the class scope (where they were friends)
// in order to work around a VC2017 compilation problem
template <class NT, class ROOT_, class ACDE_TAG_, class FP_TAG >
bool operator < (const Sqrt_extension<NT, ROOT_, ACDE_TAG_, FP_TAG>& p, const NT& num)
{
return (p.compare(num) == CGAL::SMALLER);
}
template <class NT, class ROOT_, class ACDE_TAG_, class FP_TAG >
bool operator > (const Sqrt_extension<NT, ROOT_, ACDE_TAG_, FP_TAG>& p, const NT& num)
{
return (p.compare(num) == CGAL::LARGER);
}
/*!
* Compute the square of a one-root number.
*/

View File

@ -166,7 +166,7 @@ Both \ascii and binary formats are supported, and the format is automatically de
The format consists of the number of points of the outer boundary followed
by the points themselves in counterclockwise order, followed by the number of holes,
and for each hole, the number of points of the outer boundary is followed
by the points themselves in clockwise order.
by the points themselves, in clockwise order.
\relates Polygon_with_holes_2
*/

View File

@ -70,13 +70,14 @@ public:
Shape_smoother(TriangleMesh& mesh,
VertexPointMap& vpmap,
VertexConstraintMap& vcmap,
const GeomTraits& traits)
const bool scale_volume_after_smoothing = true,
const GeomTraits& traits = GeomTraits())
:
mesh_(mesh),
vpmap_(vpmap),
vcmap_(vcmap),
vimap_(get(Vertex_local_index(), mesh_)),
scale_volume_after_smoothing(true),
scale_volume_after_smoothing_(scale_volume_after_smoothing),
traits_(traits),
weight_calculator_(mesh_, vpmap_, traits_, false /*no clamping*/, false /*no bounding from below*/)
{ }
@ -104,12 +105,12 @@ public:
if(anchor_point == boost::none)
anchor_point = get(vpmap_, v);
else
scale_volume_after_smoothing = false;
scale_volume_after_smoothing_ = false;
}
}
if(!CGAL::is_closed(mesh_))
scale_volume_after_smoothing = false;
scale_volume_after_smoothing_ = false;
}
void setup_system(Eigen_matrix& A,
@ -222,12 +223,12 @@ public:
{
namespace PMP = CGAL::Polygon_mesh_processing;
if(!scale_volume_after_smoothing)
if(!scale_volume_after_smoothing_)
return update_mesh_no_scaling(Xx, Xy, Xz);
const FT old_vol = volume(mesh_, parameters::vertex_point_map(vpmap_).geom_traits(traits_));
// If no vertex is constrained, then the smoothed mesh will simply share the same centroid as the input mesh
// If no vertex is constrained, then the smoothed mesh will share the same centroid as the input mesh
Point pre_smooth_anchor_point;
if(anchor_point != boost::none)
pre_smooth_anchor_point = *anchor_point;
@ -362,7 +363,7 @@ private:
// of volume. We need an anchor point to scale up, either a constrained point or the centroid
// of the initial mesh if no vertex is constrained. If there is more than a constrained vertex,
// then no scaling can be done without violating the constraint.
bool scale_volume_after_smoothing;
bool scale_volume_after_smoothing_;
boost::optional<Point> anchor_point;
// linear system data

View File

@ -61,6 +61,25 @@ namespace Polygon_mesh_processing {
* \cgalParamDefault{`1`}
* \cgalParamNEnd
*
* \cgalParamNBegin{vertex_is_constrained_map}
* \cgalParamDescription{a property map containing the constrained-or-not status of each vertex of `tmesh`.}
* \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
* as key type and `bool` as value type. It must be default constructible.}
* \cgalParamDefault{a default property map where no vertex is constrained}
* \cgalParamExtra{A constrained vertex cannot be modified at all during smoothing.}
* \cgalParamNEnd
*
* \cgalParamNBegin{do_scale}
* \cgalParamDescription{Whether to apply rescaling after smoothing. This is useful because
* the mean curvature flow tends to shrink the surface.}
* \cgalParamType{Boolean}
* \cgalParamDefault{`true`}
* \cgalParamExtra{Scaling can only be applied if the mesh is closed and if there is no more than
* a single constrained vertex.}
* \cgalParamExtra{If a vertex is constrained, it is the fixed point of the scaling, otherwise
* the centroid is used.}
* \cgalParamNEnd
*
* \cgalParamNBegin{vertex_point_map}
* \cgalParamDescription{a property map associating points to the vertices of `tmesh`}
* \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
@ -77,14 +96,6 @@ namespace Polygon_mesh_processing {
* \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.}
* \cgalParamNEnd
*
* \cgalParamNBegin{vertex_is_constrained_map}
* \cgalParamDescription{a property map containing the constrained-or-not status of each vertex of `tmesh`.}
* \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
* as key type and `bool` as value type. It must be default constructible.}
* \cgalParamDefault{a default property map where no vertex is constrained}
* \cgalParamExtra{A constrained vertex cannot be modified at all during smoothing.}
* \cgalParamNEnd
*
* \cgalParamNBegin{sparse_linear_solver}
* \cgalParamDescription{an instance of the sparse linear solver used for smoothing}
* \cgalParamType{a class model of `SparseLinearAlgebraWithFactorTraits_d`}
@ -97,9 +108,10 @@ namespace Polygon_mesh_processing {
*
* @warning This function involves linear algebra, that is computed using non-exact, floating-point arithmetic.
*
* @see `smooth_mesh()`
* @see `angle_and_area_smoothing()`
*/
template<typename TriangleMesh, typename FaceRange, typename NamedParameters = parameters::Default_named_parameters>
template<typename TriangleMesh, typename FaceRange,
typename NamedParameters = parameters::Default_named_parameters>
void smooth_shape(const FaceRange& faces,
TriangleMesh& tmesh,
const double time,
@ -125,6 +137,7 @@ void smooth_shape(const FaceRange& faces,
VCMap vcmap = choose_parameter(get_parameter(np, internal_np::vertex_is_constrained),
Static_boolean_property_map<vertex_descriptor, false>());
const unsigned int nb_iterations = choose_parameter(get_parameter(np, internal_np::number_of_iterations), 1);
const bool scale_after_smoothing = choose_parameter(get_parameter(np, internal_np::do_scale), true);
#if defined(CGAL_EIGEN3_ENABLED)
#if EIGEN_VERSION_AT_LEAST(3,2,0)
@ -161,11 +174,11 @@ void smooth_shape(const FaceRange& faces,
Eigen_vector bx(n), by(n), bz(n), Xx(n), Xy(n), Xz(n);
std::vector<CGAL::Triple<std::size_t, std::size_t, double> > stiffness;
internal::Shape_smoother<TriangleMesh, VertexPointMap, VCMap, Sparse_solver, GeomTraits> smoother(tmesh, vpmap, vcmap, gt);
internal::Shape_smoother<TriangleMesh, VertexPointMap, VCMap, Sparse_solver, GeomTraits> smoother(tmesh, vpmap, vcmap, scale_after_smoothing, gt);
smoother.init_smoothing(faces);
// For robustness reasons, the laplacian coefficients are computed only once (only the mass
// For robustness reasons, the Laplacian coefficients are computed only once (only the mass
// matrix is updated at every iteration). See Kazdhan et al. "Can Mean-Curvature Flow Be Made Non-Singular?".
smoother.calculate_stiffness_matrix_elements(stiffness);

View File

@ -6,6 +6,7 @@
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Polyhedron_items_with_id_3.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <CGAL/Polygon_mesh_processing/smooth_shape.h>
#include <CGAL/utility.h>
@ -17,6 +18,7 @@
#include <vector>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point;
typedef CGAL::Surface_mesh<Point> SurfaceMesh;
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Mesh_with_id;
@ -38,7 +40,7 @@ void test_implicit_constrained_devil(Mesh mesh)
typedef typename boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typename boost::property_map<Mesh, CGAL::vertex_point_t>::type vpmap = get(CGAL::vertex_point, mesh);
// z max is 20 in the devil
// max 'z' is 20 in the devil
std::set<vertex_descriptor> selected_vertices;
for(vertex_descriptor v : vertices(mesh))
{
@ -47,6 +49,8 @@ void test_implicit_constrained_devil(Mesh mesh)
selected_vertices.insert(v);
}
std::cout << selected_vertices.size() << " constrained vertices" << std::endl;
CGAL::Boolean_property_map<std::set<vertex_descriptor> > vcmap(selected_vertices);
std::vector<Point> fixed_points(selected_vertices.size());
@ -124,6 +128,29 @@ void test_implicit_constrained_elephant(Mesh mesh)
#endif
}
template <typename Mesh>
void test_implicit_unscaled_elephant(Mesh mesh)
{
#ifdef CGAL_PMP_SMOOTHING_DEBUG
std::cout << "-- test_implicit_unscaled_elephant --" << std::endl;
#endif
const FT ivol = PMP::volume(mesh);
std::cout << "Input volume is " << ivol << std::endl;
Mesh mesh_cpy(mesh);
const double time_step = 0.001;
PMP::smooth_shape(mesh_cpy, time_step, CGAL::parameters::number_of_iterations(5).do_scale(true));
FT ovol = PMP::volume(mesh_cpy);
std::cout << "With scaling, output volume is " << ovol << std::endl;
assert(equal_doubles(ivol, ovol, 1e-10));
PMP::smooth_shape(mesh, time_step, CGAL::parameters::number_of_iterations(5).do_scale(false));
ovol = PMP::volume(mesh);
std::cout << "Without scaling, output volume is " << ovol << std::endl;
}
template <typename Mesh>
void test_curvature_flow_time_step(Mesh mesh)
{
@ -167,8 +194,8 @@ int main(int, char**)
SurfaceMesh mesh_devil;
if(!input1 || !(input1 >> mesh_devil))
{
std::cerr << "Error: can not read file.";
return 1;
std::cerr << "Error: cannot read file " << filename_devil << std::endl;
return EXIT_FAILURE;
}
input1.close();
@ -176,8 +203,8 @@ int main(int, char**)
SurfaceMesh mesh_elephant;
if(!input2 || !(input2 >> mesh_elephant))
{
std::cerr << "Error: can not read file.";
return 1;
std::cerr << "Error: cannot read file " << filename_elephant << std::endl;
return EXIT_FAILURE;
}
input2.close();
@ -185,11 +212,12 @@ int main(int, char**)
test_curvature_flow<SurfaceMesh>(mesh_elephant);
test_implicit_constrained_elephant<SurfaceMesh>(mesh_elephant);
test_implicit_constrained_devil<SurfaceMesh>(mesh_devil);
test_implicit_unscaled_elephant<SurfaceMesh>(mesh_elephant);
input1.open(filename_devil);
Mesh_with_id pl_mesh_devil;
if(!input1 || !(input1 >> pl_mesh_devil)){
std::cerr << "Error: can not read file.";
std::cerr << "Error: cannot read file " << filename_devil << std::endl;
return EXIT_FAILURE;
}
input1.close();
@ -200,7 +228,7 @@ int main(int, char**)
Mesh_with_id pl_mesh_elephant;
if(!input2 || !(input2 >> pl_mesh_elephant))
{
std::cerr << "Error: can not read file.";
std::cerr << "Error: cannot read file " << filename_elephant << std::endl;
return EXIT_FAILURE;
}
input2.close();
@ -212,6 +240,7 @@ int main(int, char**)
test_curvature_flow<Mesh_with_id>(pl_mesh_elephant);
test_implicit_constrained_elephant<Mesh_with_id>(pl_mesh_elephant);
test_implicit_constrained_devil<Mesh_with_id>(pl_mesh_devil);
test_implicit_unscaled_elephant<Mesh_with_id>(pl_mesh_elephant);
return EXIT_SUCCESS;
}

View File

@ -277,12 +277,16 @@ void Mesh_3_plugin::mesh_3_volume()
mesh_3(Mesh_type::VOLUME);
}
boost::optional<QString> Mesh_3_plugin::get_items_or_return_error_string() const {
boost::optional<QString> Mesh_3_plugin::get_items_or_return_error_string() const
{
using boost::get;
items = {};
features_protection_available = false;
item = nullptr;
for (int ind : scene->selectionIndices()) {
Scene_polylines_item* polylines_item = nullptr;
for (int ind : scene->selectionIndices())
{
try {
if (auto sm_item =
qobject_cast<Scene_surface_mesh_item*>(scene->item(ind))) {
@ -313,9 +317,11 @@ boost::optional<QString> Mesh_3_plugin::get_items_or_return_error_string() const
return tr("An image items cannot be mixed with other items type");
}
# endif
else if (auto polylines_item =
qobject_cast<Scene_polylines_item*>(scene->item(ind))) {
if (!items) items = Polyhedral_mesh_items{};
else if ((polylines_item =
qobject_cast<Scene_polylines_item*>(scene->item(ind))))
{
if (!items)
continue;
auto poly_items_ptr = get<Polyhedral_mesh_items>(&*items);
if(poly_items_ptr) {
if (poly_items_ptr->polylines_item) {
@ -323,12 +329,16 @@ boost::optional<QString> Mesh_3_plugin::get_items_or_return_error_string() const
} else {
poly_items_ptr->polylines_item = polylines_item;
}
} else {
auto image_items = get<Image_mesh_items>(*items);
if (image_items.polylines_item) {
return tr("Only one polyline item is accepted");
} else {
image_items.polylines_item = polylines_item;
}
else {
if(auto image_items_ptr = get<Image_mesh_items>(&*items))
{
if (image_items_ptr->polylines_item) {
return tr("Only one polyline item is accepted");
}
else {
image_items_ptr->polylines_item = polylines_item;
}
}
}
}
@ -341,6 +351,20 @@ boost::optional<QString> Mesh_3_plugin::get_items_or_return_error_string() const
}
} catch (const boost::bad_get&) { return tr("Wrong selection of items"); }
} // end for loop on selected items
//attach polylines_item to one or the other item
//if it could not be done in the for loop
//because of selection order
if (polylines_item != nullptr && items != boost::none)
{
auto poly_items_ptr = get<Polyhedral_mesh_items>(&*items);
auto image_items_ptr = get<Image_mesh_items>(&*items);
if(poly_items_ptr && poly_items_ptr == nullptr)
poly_items_ptr->polylines_item = polylines_item;
else if(image_items_ptr && image_items_ptr == nullptr)
image_items_ptr->polylines_item = polylines_item;
}
if (!items) { return tr("Selected objects can't be meshed"); }
item = nullptr;
features_protection_available = false;
@ -428,6 +452,8 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
get<Polyhedral_mesh_items>(&*items)
? get<Polyhedral_mesh_items>(&*items)->polylines_item
: nullptr;
if (polylines_item == nullptr && get<Image_mesh_items>(&*items) != nullptr)
polylines_item = get<Image_mesh_items>(&*items)->polylines_item;
Scene_implicit_function_item* function_item =
get<Implicit_mesh_items>(&*items)
? get<Implicit_mesh_items>(&*items)->function_item.get()
@ -571,18 +597,28 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
ui.edgeLabel->setEnabled(ui.noEdgeSizing->isChecked());
ui.edgeSizing->setEnabled(ui.noEdgeSizing->isChecked());
const QString sharp_and_boundary("Sharp and Boundary edges");
const QString boundary_only("Boundary edges only");
const QString sharp_edges("Sharp edges");
const QString input_polylines("Input polylines");
const QString on_cube("Polylines on cube");
const QString triple_lines("Triple+ lines");
if (features_protection_available) {
if (items->which() == POLYHEDRAL_MESH_ITEMS) {
if (mesh_type == Mesh_type::SURFACE_ONLY) {
ui.protectEdges->addItem(QString("Sharp and Boundary edges"));
ui.protectEdges->addItem(QString("Boundary edges only"));
ui.protectEdges->addItem(sharp_and_boundary);
ui.protectEdges->addItem(boundary_only);
} else
ui.protectEdges->addItem(QString("Sharp edges"));
ui.protectEdges->addItem(sharp_edges);
} else if (items->which() == IMAGE_MESH_ITEMS) {
if (polylines_item != nullptr)
ui.protectEdges->addItem(QString("Input polylines"));
if (polylines_item != nullptr) {
ui.protectEdges->addItem(QString(input_polylines).append(" only"));
ui.protectEdges->addItem(QString(on_cube).append(" and input polylines"));
ui.protectEdges->addItem(QString(triple_lines).append(" and input polylines"));
}
else {
ui.protectEdges->addItem(QString("Polylines on cube"));
ui.protectEdges->addItem(on_cube);
ui.protectEdges->addItem(triple_lines);
}
}
}
@ -629,10 +665,15 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
approx = !ui.noApprox->isChecked() ? 0 : ui.approx->value();
tets_shape = !ui.noTetShape->isChecked() ? 0 : ui.tetShape->value();
tets_sizing = !ui.noTetSizing->isChecked() ? 0 : ui.tetSizing->value();
protect_features =
ui.protect->isChecked() && (ui.protectEdges->currentIndex() == 0);
protect_borders =
ui.protect->isChecked() && (ui.protectEdges->currentIndex() == 1);
const int pe_ci = ui.protectEdges->currentIndex();
protect_borders = ui.protect->isChecked()
&& ( pe_ci == ui.protectEdges->findText(on_cube, Qt::MatchContains)
|| pe_ci == ui.protectEdges->findText(boundary_only, Qt::MatchContains));
protect_features = ui.protect->isChecked()
&& ( pe_ci == ui.protectEdges->findText(triple_lines, Qt::MatchContains)
|| pe_ci == ui.protectEdges->findText(sharp_and_boundary, Qt::MatchContains));
const bool detect_connected_components = ui.detectComponents->isChecked();
const int manifold = (ui.manifoldCheckBox->isChecked() ? 1 : 0) +
(ui.facetTopology->isChecked() ? 2 : 0);
@ -728,7 +769,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
}
break;
}//end case POLYHEDRAL_MESH_ITEMS
// Image
// Implicit functions
# ifdef CGAL_MESH_3_DEMO_ACTIVATE_IMPLICIT_FUNCTIONS
case IMPLICIT_MESH_ITEMS: {
const Implicit_function_interface* pFunction = function_item->function();
@ -747,11 +788,15 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
manifold,
mesh_type == Mesh_type::SURFACE_ONLY);
break;
}
}//end case IMPLICIT_MESH_ITEMS
# endif
// Images
# ifdef CGAL_MESH_3_DEMO_ACTIVATE_SEGMENTED_IMAGES
case IMAGE_MESH_ITEMS: {
const Image* pImage = image_item->image();
auto& image_items = get<Image_mesh_items>(*items);
const auto img_polylines_item = image_items.polylines_item;
if (nullptr == pImage) {
QMessageBox::critical(mw, tr(""), tr("ERROR: no data in selected item"));
return;
@ -773,7 +818,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
thread = cgal_code_mesh_3(
pImage,
(polylines_item == nullptr) ? plc : polylines_item->polylines,
(img_polylines_item == nullptr) ? plc : img_polylines_item->polylines,
angle,
facets_sizing,
approx,
@ -781,6 +826,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type,
edges_sizing,
tets_shape,
protect_features,
protect_borders,
manifold,
mesh_type == Mesh_type::SURFACE_ONLY,
detect_connected_components,

View File

@ -13,6 +13,8 @@
#include "Mesh_function.h"
#include "Facet_extra_criterion.h"
#include <CGAL/Mesh_3/Detect_features_in_image.h>
#include <CGAL/Mesh_3/Detect_features_on_image_bbox.h>
using namespace CGAL::Three;
@ -291,7 +293,8 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
const double tet_sizing,
const double edge_size,
const double tet_shape,
bool protect_features,
bool protect_features, //detect_polylines
const bool protect_borders,//polylines on bbox
const int manifold,
const bool surface_only,
bool detect_connected_components,
@ -303,11 +306,9 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
{
if (nullptr == pImage) { return nullptr; }
if(! polylines.empty()){
protect_features = true; // so that it will be passed in make_mesh_3
}
Mesh_parameters param;
param.protect_features = protect_features;
param.protect_features
= protect_features || protect_borders || !polylines.empty();
param.detect_connected_components = detect_connected_components;
param.facet_angle = facet_angle;
param.facet_sizing = facet_sizing;
@ -343,7 +344,7 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
{
namespace p = CGAL::parameters;
Image_mesh_domain* p_domain;
Image_mesh_domain* p_domain = nullptr;
#ifdef CGAL_USE_ITK
if(nullptr != pWeights)
{
@ -359,35 +360,57 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
}
else
#endif
{
p_domain = new Image_mesh_domain
(Image_mesh_domain::create_labeled_image_mesh_domain
(p::image = *pImage,
p::relative_error_bound = 1e-6,
p::construct_surface_patch_index =
[](int i, int j) { return (i * 1000 + j); }
)
);
}
if (protect_features)
{
p_domain = new Image_mesh_domain
(Image_mesh_domain::create_labeled_image_mesh_domain
(p::image = *pImage,
p::relative_error_bound = 1e-6,
p::construct_surface_patch_index =
[](int i, int j) { return (i * 1000 + j); },
p::features_detector = CGAL::Mesh_3::Detect_features_in_image(),
p::input_features = std::cref(polylines)
)
);
}
else if (protect_borders)//protect polylines on image Bbox
{
p_domain = new Image_mesh_domain
(Image_mesh_domain::create_labeled_image_mesh_domain
(p::image = *pImage,
p::relative_error_bound = 1e-6,
p::construct_surface_patch_index =
[](int i, int j) { return (i * 1000 + j); },
p::features_detector = CGAL::Mesh_3::Detect_features_on_image_bbox(),
p::input_features = std::cref(polylines)
)
);
}
else if (!polylines.empty())
{
p_domain = new Image_mesh_domain
(Image_mesh_domain::create_labeled_image_mesh_domain
(p::image = *pImage,
p::relative_error_bound = 1e-6,
p::construct_surface_patch_index =
[](int i, int j) { return (i * 1000 + j); },
p::input_features = std::cref(polylines)
)
);
}
if(protect_features && polylines.empty()){
std::vector<std::vector<Bare_point> > polylines_on_bbox;
if (p_domain == nullptr)
{
p_domain = new Image_mesh_domain
(Image_mesh_domain::create_labeled_image_mesh_domain
(p::image = *pImage,
p::relative_error_bound = 1e-6,
p::construct_surface_patch_index =
[](int i, int j) { return (i * 1000 + j); }
)
);
}
CGAL_IMAGE_IO_CASE(pImage->image(),
{
typedef Word Image_word_type;
(CGAL::polylines_to_protect<
Bare_point,
Image_word_type>(*pImage, polylines_on_bbox));
p_domain->add_features(polylines_on_bbox.begin(),
polylines_on_bbox.end());
}
);
}
if(! polylines.empty()){
// Insert edge in domain
p_domain->add_features(polylines.begin(), polylines.end());
}
typedef ::Mesh_function<Image_mesh_domain,
Mesh_fnt::Labeled_image_domain_tag> Mesh_function;
Mesh_function* p_mesh_function = new Mesh_function(p_new_item->c3t3(),

View File

@ -73,6 +73,7 @@ Meshing_thread* cgal_code_mesh_3(const CGAL::Image_3* pImage,
const double edge_size,
const double tet_shape,
bool protect_features,
const bool protect_borders,
const int manifold,
const bool surface_only,
bool detect_connected_components,

View File

@ -640,7 +640,7 @@ public:
but are isolated from the complex at the end of the meshing process.
This function removes these so-called \em isolated vertices, that belong to the
triangulation but not to any cell of the `C3T3`, from the triangulation.
triangulation but not to any simplex of the `C3T3`, from the triangulation.
*/
void remove_isolated_vertices()
{
@ -669,7 +669,8 @@ public:
std::vector<Vertex_handle> isolated;
for (Vertex_handle v : tr.finite_vertex_handles())
{
if (v->meshing_info() == 0.)
if (v->meshing_info() == 0.
&& (v->in_dimension() > 1 || v->in_dimension() < 0))
isolated.push_back(v);
}

View File

@ -670,7 +670,7 @@ void clear();
bool owns(const_iterator pos);
/*!
* returns whether `pos` is in the range `[cc.begin(), cc`.end())` (`cc.end()` excluded).
* returns whether `pos` is in the range `[cc.begin(), cc.end())` (`cc.end()` excluded).
*/
bool owns_dereferenceable(const_iterator pos);

View File

@ -294,8 +294,8 @@ complexity. No exception is thrown.
/// returns whether `pos` is in the range `[ccc.begin(), ccc.end()]` (`ccc.end()` included).
bool owns(const_iterator pos);
/// returns whether `pos` is in the range `[ccc.begin(), ccc.end())` (`ccc.end()` excluded).
bool owns_dereferenceable(const_iterator pos);
bool owns_dereferencable(const_iterator pos);
/// @}
/// \name Merging

View File

@ -149,12 +149,12 @@ CGAL_add_named_parameter(mesh_facet_angle_t, mesh_facet_angle, mesh_facet_angle)
CGAL_add_named_parameter(mesh_facet_distance_t, mesh_facet_distance, mesh_facet_distance)
CGAL_add_named_parameter(mesh_facet_topology_t, mesh_facet_topology, mesh_facet_topology)
CGAL_add_named_parameter(polyline_constraints_t, polyline_constraints, polyline_constraints)
CGAL_add_named_parameter(do_scale_t, do_scale, do_scale)
CGAL_add_named_parameter(vertex_corner_map_t, vertex_corner_map, vertex_corner_map)
CGAL_add_named_parameter(patch_normal_map_t, patch_normal_map, patch_normal_map)
CGAL_add_named_parameter(region_primitive_map_t, region_primitive_map, region_primitive_map)
CGAL_add_named_parameter(postprocess_regions_t, postprocess_regions, postprocess_regions)
// List of named parameters that we use in the package 'Surface Mesh Simplification'
CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost)
CGAL_add_named_parameter(get_placement_policy_t, get_placement_policy, get_placement)
@ -333,6 +333,8 @@ CGAL_add_named_parameter_with_compatibility(rng_t, rng, p_rng)
CGAL_add_named_parameter_with_compatibility(null_subdomain_index_param_t,null_subdomain_index_param, null_subdomain_index)
CGAL_add_named_parameter_with_compatibility(surface_patch_index_t, surface_patch_index, construct_surface_patch_index)
CGAL_add_named_parameter_with_compatibility_ref_only(weights_param_t, weights_param, weights)
CGAL_add_named_parameter_with_compatibility(features_detector_param_t, features_detector_param, features_detector)
CGAL_add_named_parameter_with_compatibility(input_features_param_t, input_features_param, input_features)
CGAL_add_named_parameter_with_compatibility(edge_size_param_t, edge_size_param, edge_size)
CGAL_add_named_parameter_with_compatibility_ref_only(edge_sizing_field_param_t, edge_sizing_field_param, edge_sizing_field)

View File

@ -0,0 +1,77 @@
#!/bin/bash
echo "| repo | workflow | branch | event | runs on | status of last run | state | annotation | date | date since last runs | file |"
echo "| :--: | :--------: | :----: | :---: | :------: | :------------------: | :---: | :--------: | :----: | :------------------: | :----: |"
actualdate=$EPOCHSECONDS
for repo in $(gh api orgs/CGAL/repos --jq '.[].full_name' | grep -v dev )
do
if [ "$repo" != "CGAL/CNRS" ] && [ "$repo" != "CGAL/GeometryFactory" ]
then
default_branch=$(gh api repos/$repo --jq '.default_branch')
workflows=$(gh api repos/$repo/actions/workflows)
workflows_count=$(jq '.total_count' <<< "$workflows")
for ((i=0;i<workflows_count;i++))
do
workflow_id=$(jq '.workflows['$i'].id' <<< "$workflows")
workflows_state=$(jq '.workflows['$i'].state' <<< "$workflows")
if [ "$workflows_state" == "\"disabled\"" -o "$workflows_state" == "\"disabled_manually\"" ]
then
continue
fi
workflow_runs=$(gh api repos/$repo/actions/workflows/$workflow_id/runs)
workflows_name=$(jq -e '.workflow_runs[0].name' <<< "$workflow_runs")
if [ $? -eq 0 ]
then
workflows_status=$(jq -r '.workflow_runs[0].status' <<< "$workflow_runs")
workflows_conclusion=$(jq -r '.workflow_runs[0].conclusion' <<< "$workflow_runs")
workflows_start=$(jq -r '.workflow_runs[0].run_started_at' <<< "$workflow_runs")
workflows_date=$( date --date="$workflows_start" +%s )
workflows_on=$(jq -r '.workflow_runs[0].event' <<< "$workflow_runs")
workflows_path=$(jq -r '.workflow_runs[0].path' <<< "$workflow_runs")
workflows_branch=$(jq -r '.workflow_runs[0].head_branch' <<< "$workflow_runs")
workflows_checksuite_id=$(jq -r '.workflow_runs[0].check_suite_id' <<< "$workflow_runs")
workflows_check_runs=$(gh api repos/$repo/check-suites/$workflows_checksuite_id/check-runs)
workflows_check_runs_id=$(jq -r '.check_runs[0].id' <<< "$workflows_check_runs")
workflows_check_runs_annotation=$(gh api repos/$repo/check-runs/$workflows_check_runs_id/annotations)
worfklows_annotation_level=$(jq -r '.[].annotation_level' <<< "$workflows_check_runs_annotation" | tr '\n' ' ')
if [ "$worfklows_annotation_level" == "" ]
then
worfklows_annotation_level+="-"
fi
workflows_event=""
for trigger in $(curl --silent https://raw.githubusercontent.com/$repo/$default_branch/$workflows_path | yq '.on' | grep -v ' .*'); do
if [ "${trigger}" != "-" ]
then
workflows_event+=${trigger}
workflows_event+="<br/>"
fi
done
echo "| $repo | $workflows_name | $workflows_branch | $workflows_event | $workflows_on | $workflows_status - $workflows_conclusion | $workflows_state | ***$worfklows_annotation_level*** | $workflows_start | $(((actualdate - workflows_date) / 86400 )) days | $repo/$workflows_path"
fi
done
fi
done
echo ""
echo "| repo | dependabot |"
echo "| :--: | :--------: |"
for repo in $(gh api orgs/CGAL/repos --jq '.[].full_name' | grep -v dev )
do
if [ "$repo" != "CGAL/CNRS" ] && [ "$repo" != "CGAL/GeometryFactory" ]
then
default_branch=$(gh api repos/$repo --jq '.default_branch')
workflows=$(gh api repos/$repo/actions/workflows)
workflows_count=$(jq '.total_count' <<< "$workflows")
if [ $workflows_count != 0 ]
then
dependabot=$(curl --silent https://raw.githubusercontent.com/$repo/$default_branch/.github/dependabot.yml)
dependabotexist=""
if [ "$dependabot" != "404: Not Found" ]
then
dependabotexist="yes"
else
dependabotexist="no"
fi
echo "| $repo | $dependabotexist |"
fi
fi
done

View File

@ -39,7 +39,7 @@ int main( int argc, char* argv[] )
for(Polygon_with_holes::Hole_const_iterator it = input.holes_begin();
it != input.holes_end();
++it){
assert(it->is_counterclockwise_oriented());
assert(it->is_clockwise_oriented());
}
double lOffset = 0.25 ;
@ -75,13 +75,13 @@ int main( int argc, char* argv[] )
else
{
std::cerr << "Computes the interior offset of a polygon with holes and draws the result in an EPS file." << std::endl
<< std::endl
<< "Usage: show_offset_polygon <input_file> [output_eps_file]" << std::endl
<< std::endl
<< "Usage: show_offset_polygon <intput_file> [offset_distance] [output_eps_file]" << std::endl
<< std::endl
<< " intput_file Text file describing the input polygon with holes." << std::endl
<< " (See inputfile_format.txt for details)" << std::endl
<< " offset_distance [default=0.25]." << std::endl
<< " output_file [default='innput_file.offset.eps']" << std::endl ;
<< " input_file Text file describing the input polygon with holes." << std::endl
<< " (See input_file_format.txt for details" << std::endl
<< " or use input_file_example.txt)" << std::endl
<< " output_file [default='input_file.offset.eps']" << std::endl ;
}
return 0;

View File

@ -42,7 +42,7 @@ int main( int argc, char* argv[] )
for(Polygon_with_holes::Hole_const_iterator it = input.holes_begin();
it != input.holes_end();
++it){
assert(it->is_counterclockwise_oriented());
assert(it->is_clockwise_oriented());
}
//check the validity of the input and fix orientation
@ -51,8 +51,6 @@ int main( int argc, char* argv[] )
std::cerr << "ERROR: outer boundary is not simple.";
return 1;
}
if ( input.outer_boundary().is_clockwise_oriented() )
input.outer_boundary().reverse_orientation();
int k=0;
for (Polygon_with_holes::Hole_iterator it = input.holes_begin();
it!=input.holes_end(); ++it, ++k)
@ -62,8 +60,6 @@ int main( int argc, char* argv[] )
std::cerr << "ERROR: hole "<< k << " is not simple.\n";
return 1;
}
if (it->is_counterclockwise_oriented())
it->reverse_orientation();
}
Straight_skeleton_ptr ss = CGAL::create_interior_straight_skeleton_2(input);
@ -99,11 +95,12 @@ int main( int argc, char* argv[] )
{
std::cerr << "Computes the straight skeleton in the interior of a polygon with holes and draws it in an EPS file." << std::endl
<< std::endl
<< "Usage: show_straight_skeleton <intput_file> [output_eps_file]" << std::endl
<< "Usage: show_straight_skeleton <input_file> [output_eps_file]" << std::endl
<< std::endl
<< " intput_file Text file describing the input polygon with holes." << std::endl
<< " (See input_file_format.txt for details)" << std::endl
<< " output_file [default='innput_file.skeleton.eps']" << std::endl ;
<< " input_file Text file describing the input polygon with holes." << std::endl
<< " (See input_file_format.txt for details" << std::endl
<< " or use input_file_example.txt)" << std::endl
<< " output_file [default='input_file.skeleton.eps']" << std::endl ;
}
return 0;

View File

@ -0,0 +1,11 @@
4
0 0
1 0
1 1
0 1
1
4
0.125 0.125
0.125 0.875
0.875 0.875
0.875 0.125

View File

@ -39,12 +39,21 @@ The page \ref bgl_namedparameters describes their usage.
- `DQQMask_3`
- `Sqrt3Mask_3`
\cgalCRPSection{Functions}
- `CGAL::Subdivision_method_3::PQQ()`
- `CGAL::Subdivision_method_3::PTQ()`
- `CGAL::Subdivision_method_3::DQQ()`
- `CGAL::Subdivision_method_3::Sqrt3()`
- `CGAL::Subdivision_method_3::CatmullClark_subdivision()`
- `CGAL::Subdivision_method_3::Loop_subdivision()`
- `CGAL::Subdivision_method_3::DooSabin_subdivision()`
- `CGAL::Subdivision_method_3::Sqrt3_subdivision()`
\cgalCRPSection{Classes}
- `CGAL::Subdivision_method_3`
- `CGAL::CatmullClark_mask_3<PolygonMesh>`
- `CGAL::Loop_mask_3<PolygonMesh>`
- `CGAL::DooSabin_mask_3<PolygonMesh>`
- `CGAL::Sqrt3_mask_3<PolygonMesh>`
- `CGAL::Linear_mask_3<PolygonMesh>`
*/

View File

@ -2,6 +2,7 @@
\example Subdivision_method_3/Customized_subdivision.cpp
\example Subdivision_method_3/CatmullClark_subdivision.cpp
\example Subdivision_method_3/DooSabin_subdivision.cpp
\example Subdivision_method_3/Linear_subdivision.cpp
\example Subdivision_method_3/Loop_subdivision.cpp
\example Subdivision_method_3/Sqrt3_subdivision.cpp
*/

View File

@ -0,0 +1,34 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
#include <CGAL/subdivision_method_3.h>
#include <iostream>
#include <fstream>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef CGAL::Surface_mesh<Kernel::Point_3> Surface_mesh;
namespace PMP = CGAL::Polygon_mesh_processing;
int main(int argc, char* argv[]) {
const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/quad.off");
Surface_mesh mesh;
if(!PMP::IO::read_polygon_mesh(filename, mesh))
{
std::cerr << "Invalid input." << std::endl;
return 1;
}
CGAL::Linear_mask_3<Surface_mesh> mask(&mesh);
CGAL::Subdivision_method_3::PQQ(mesh, mask, CGAL::parameters::number_of_iterations(1));
std::ofstream out("out.off");
out << mesh;
return 0;
}

View File

@ -81,6 +81,7 @@ void PQQ_1step(Poly& p, VertexPointMap vpm, Mask mask) {
int i=0;
std::unordered_map<vertex_descriptor,int> v_index;
for(vertex_descriptor vh : p_vertices){
vertex_point_buffer[i] = get(vpm, vh);
v_index[vh]= i++;
}

View File

@ -88,7 +88,7 @@ public:
public:
Linear_mask_3(Mesh* pmesh)
: Base(pmesh, get(vertex_point, pmesh))
: Base(pmesh, get(vertex_point, *pmesh))
{ }
Linear_mask_3(Mesh* pmesh, VertexPointMap vpmap)
@ -118,7 +118,7 @@ public:
}
void border_node(halfedge_descriptor edge, Point& ept, Point& /*vpt*/){
edge_node(edge, ept);
edge_node(edge, ept);
}
};

View File

@ -74,6 +74,7 @@ Catmull-Clark subdivision.
\sa `CGAL::DooSabin_mask_3<PolygonMesh`
\sa `CGAL::Loop_mask_3<PolygonMesh`
\sa `CGAL::Sqrt3_mask_3<PolygonMesh>`
\sa `CGAL::Linear_mask_3<PolygonMesh>`
*/
/// @{
@ -121,7 +122,6 @@ void CatmullClark_subdivision(PolygonMesh& pmesh, int step) {
* \cgalParamNEnd
* \cgalNamedParamsEnd
*
* \pre `pmesh` must be a triangle mesh.
**/
template <class PolygonMesh, class NamedParameters = parameters::Default_named_parameters>
void CatmullClark_subdivision(PolygonMesh& pmesh, const NamedParameters& np = parameters::default_values()) {
@ -179,6 +179,8 @@ void Loop_subdivision(PolygonMesh& pmesh, int step) {
* \cgalParamDefault{`1`}
* \cgalParamNEnd
* \cgalNamedParamsEnd
*
* \pre `pmesh` must be a triangle mesh.
**/
template <class PolygonMesh, class NamedParameters = parameters::Default_named_parameters>
void Loop_subdivision(PolygonMesh& pmesh, const NamedParameters& np = parameters::default_values()) {

View File

@ -77,11 +77,20 @@ they were created must be used to obtain this information.
\subsection usage_example Example
The following example shows how to create a very simple `Surface_mesh`
The first example shows how to create a very simple `Surface_mesh`
by adding 2 faces, and how to check that a face is correctly added
to the mesh.
\cgalExample{Surface_mesh/check_orientation.cpp}
The second example shows how to access the points associated
to the vertices, either for an individual vertex, or as
the range of points of the entire mesh. Such a range can
be accessed in a for-loop or passed to functions that expect
a range of points as input.
\cgalExample{Surface_mesh/sm_points.cpp}
\section sectionSurfaceMeshConnectivity Connectivity
A surface mesh is an edge-centered data structure capable of

View File

@ -4,6 +4,7 @@ Algebraic_foundations
BGL
Box_intersection_d
Circulator
Convex_hull_3
HalfedgeDS
Kernel_23
Miscellany
@ -11,4 +12,3 @@ Polyhedron
Polygon_mesh_processing
STL_Extension
Stream_support

View File

@ -1,5 +1,6 @@
/*!
\example Surface_mesh/check_orientation.cpp
\example Surface_mesh/sm_points.cpp
\example Surface_mesh/sm_iterators.cpp
\example Surface_mesh/sm_circulators.cpp
\example Surface_mesh/sm_properties.cpp

View File

@ -12,6 +12,7 @@ project(Surface_mesh_Examples)
#CGAL_Qt5 is needed for the drawing.
find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5)
create_single_source_cgal_program("sm_points.cpp")
create_single_source_cgal_program("sm_derivation.cpp")
create_single_source_cgal_program("sm_join.cpp")
create_single_source_cgal_program("sm_aabbtree.cpp")

View File

@ -46,7 +46,8 @@ int main()
// or with boost::tie, as the CGAL range derives from std::pair
for(boost::tie(vb, ve) = m.vertices(); vb != ve; ++vb){
std::cout << *vb << std::endl;
// Print vertex index and vertex coordinates
std::cout << *vb << " " << m.point(*vb) << std::endl;
}
// Instead of the classical for loop one can use

View File

@ -0,0 +1,35 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/convex_hull_3.h>
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef Mesh::Vertex_index vertex_descriptor;
typedef Mesh::Face_index face_descriptor;
int main()
{
Mesh m;
vertex_descriptor v0 = m.add_vertex(K::Point_3(0,0,0));
vertex_descriptor v1 = m.add_vertex(K::Point_3(1,0,0));
vertex_descriptor v2 = m.add_vertex(K::Point_3(0,1,0));
vertex_descriptor v3 = m.add_vertex(K::Point_3(0,0,1));
face_descriptor fd = m.add_face(v0, v1, v2);
m.add_face(v1, v0, v3);
// Access the point for a given vertex
for(vertex_descriptor vd : vertices_around_face(m.halfedge(fd), m)){
std ::cout << m.point(vd) << std::endl;
}
// Access the range of all points of the mesh
for( const K::Point_3& p : m.points()){
std::cout << p << std::endl;
}
Mesh ch;
CGAL::convex_hull_3(m.points().begin(), m.points().end(), ch);
return 0;
}

View File

@ -2,6 +2,7 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/generators.h>
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
@ -25,7 +26,7 @@ int main()
// give each vertex a name, the default is empty
Mesh::Property_map<vertex_descriptor,std::string> name;
bool created;
boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name","");
boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name","m1");
assert(created);
// add some names to the vertices
name[v0] = "hello";
@ -51,14 +52,34 @@ int main()
std::cout << name[vd] << " @ " << location[vd] << std::endl;
}
Mesh m2;
CGAL::make_triangle(K::Point_3(0,0,1), K::Point_3(1,0,1),K::Point_3(0,1,1), m2);
m2.add_property_map<vertex_descriptor,std::string>("v:name","m2");
Mesh::Property_map<vertex_descriptor,int> index;
index = m2.add_property_map<vertex_descriptor,int>("v:index",-1).first;
int i = 0;
for (auto v : vertices(m2)) {
index[v] = i++;
}
std::cout << "properties of m1:" << std::endl;
std::vector<std::string> props = m.properties<vertex_descriptor>();
for(std::string p : props){
std::cout << p << std::endl;
}
m.join(m2);
std::cout << "properties of m1 after join:" << std::endl;
for(std::string p : m.properties<vertex_descriptor>()){
std::cout << p << std::endl;
}
for (auto v : vertices(m)) {
std::cout << name[v] << std::endl;
}
// delete the string property again
m.remove_property_map(name);
return 0;
}

View File

@ -1215,6 +1215,10 @@ public:
fprops_.resize(nfaces);
}
/// copies the simplices from `other`, and copies values of
/// properties that already exist under the same name in `*this`.
/// In case `*this` has a property that does not exist in `other`
/// the copied simplices get the default value of the property.
bool join(const Surface_mesh& other)
{
// increase capacity

View File

@ -191,8 +191,6 @@ Inserts the line segment between the points `c.first` and `c.second` as a const
/*!
Inserts the line segment whose endpoints are the vertices `va` and
`vb` as a constraint in the triangulation.
\pre `va` != `vb`.
*/
void insert_constraint(Vertex_handle va, Vertex_handle vb);
@ -224,7 +222,10 @@ std::size_t insert_constraints(ConstraintIterator first, ConstraintIterator last
Same as above except that each constraints is given as a pair of indices of the points
in the range [points_first, points_last). The indices must go from 0 to `std::distance(points_first, points_last)`
\tparam PointIterator is an `InputIterator` with the value type `Point`.
\tparam IndicesIterator is an `InputIterator` with `std::pair<Int, Int>` where `Int` is an integral type implicitly convertible to `std::size_t`
\tparam IndicesIterator is an `InputIterator` with `std::pair<Int,Int>`
where `Int` is an integral type implicitly convertible to `std::size_t`
\note points are inserted even if they are not endpoint of a constraint.
\return the number of inserted points.
*/
template <class PointIterator, class IndicesIterator>
std::size_t insert_constraints(PointIterator points_first, PointIterator points_last,

View File

@ -22,11 +22,17 @@ point.
The data structure maintains for each input constraint
the sequence of vertices on this constraint. These vertices are
the sequence of vertices on this constraint. Note that there is
not a one-to-one correspondence between an input constraint and
the sequence of vertices. These vertices are
either vertices of the input constraint or intersection points.
Also consecutive identical points in the input constraint
result in a single vertex in the sequence of vertices on this
constraint. In case of an input constraint being degenerate
to a point, this point is inserted but there will not be a
zero length constraint.
\todo The following description does not match the code
Two consecutive vertices of an input constraint form a *subconstraint*.
Two consecutive vertices of a constraint form a *subconstraint*.
A subconstraint is a pair of vertex handles and corresponds to a constrained edge of the
triangulation, which is a pair of a face handle and an index.
@ -36,7 +42,8 @@ It further enables the retrieval of the set of input constraints that induce a s
As it is straightforward to obtain a subconstraint from a constrained edge `e`,
one can obtain the input constraints which induce `e`.
\tparam Tr must be either a CGAL::Constrained_triangulation_2 or a CGAL::Constrained_Delaunay_triangulation_2
\tparam Tr must be either a `CGAL::Constrained_triangulation_2` or a `CGAL::Constrained_Delaunay_triangulation_2`
\sa `CGAL::Constrained_triangulation_2<Traits,Tds>`
\sa `CGAL::Constrained_Delaunay_triangulation_2<Traits,Tds>`
@ -242,12 +249,14 @@ insert(PointIterator first, PointIterator last);
/*!
inserts the constraint segment `ab` in the triangulation.
If the two points are equal the point is inserted but no constraint,
and the default constructed `Constraint_id` is returned.
and a default constructed `Constraint_id` is returned.
*/
Constraint_id insert_constraint(Point a, Point b);
/*!
inserts the constraint `c`.
inserts the constraint `c` in the triangulation.
If the two points are equal the point is inserted but no constraint,
and a default constructed `Constraint_id` is returned.
*/
void push_back(const std::pair<Point,Point>& c);
@ -255,7 +264,7 @@ inserts the constraint `c`.
inserts a constraint whose endpoints are the vertices
pointed by `va` and `vb` in the triangulation.
If the two vertex handles are equal no constraint is inserted,
and the default constructed `Constraint_id` is returned.
and a default constructed `Constraint_id` is returned.
*/
Constraint_id insert_constraint(Vertex_handle va, Vertex_handle vb);
@ -264,9 +273,10 @@ inserts a polyline defined by the points in the range `[first,last)`
and returns the constraint id.
The polyline is considered as a closed curve if the first and last point are equal or if `close == true`. This enables for example passing the vertex range of a `Polygon_2`.
When traversing the vertices of a closed polyline constraint with a `Vertices_in_constraint_iterator` the first and last vertex are the same.
In case the range is empty `Constraint_id()` is returned.
In case all points are equal the point is inserted but no constraint,
and `Constraint_id()` is returned.
In case the range is empty a default constructed `Constraint_id` is returned.
In case the range contains only one point or all points are equal the point is inserted but no constraint,
and a default constructed `Constraint_id` is returned.
\tparam PointIterator must be an `InputIterator` with the value type `Point`.
*/
template < class PointIterator>
@ -280,9 +290,12 @@ is used to improve efficiency.
More precisely, all endpoints are inserted prior to the segments and according to the order provided by the spatial sort.
Once endpoints have been inserted, the segments are inserted in the order of the input iterator,
using the vertex handles of its endpoints.
In case the constraints are degenerate the points are inserted, but no
constraints.
\tparam ConstraintIterator must be an `InputIterator` with the value type `std::pair<Point,Point>` or `Segment`.
\return the number of inserted points.
\tparam ConstraintIterator must be an `InputIterator` with the value type `std::pair<Point,Point>` or `Segment`.
*/
template <class ConstraintIterator>
std::size_t insert_constraints(ConstraintIterator first, ConstraintIterator last);
@ -291,7 +304,11 @@ std::size_t insert_constraints(ConstraintIterator first, ConstraintIterator last
Same as above except that each constraint is given as a pair of indices of the points
in the range [points_first, points_last). The indices must go from 0 to `std::distance(points_first, points_last)`
\tparam PointIterator is an `InputIterator` with the value type `Point`.
\tparam IndicesIterator is an `InputIterator` with `std::pair<Int, Int>` where `Int` is an integral type implicitly convertible to `std::size_t`
\tparam IndicesIterator is an `InputIterator` with `std::pair<Int,
Int>` where `Int` is an integral type implicitly convertible to
`std::size_t`
\note points are inserted even if they are not endpoint of a constraint.
\return the number of inserted points.
*/
template <class PointIterator, class IndicesIterator>
std::size_t insert_constraints(PointIterator points_first, PointIterator points_last,

View File

@ -103,6 +103,10 @@ are described in Chapter \ref PkgTDS2Ref "2D Triangulation Data Structure".
- `CGAL::Triangulation_cw_ccw_2`
\cgalCRPSection{Functions}
- `CGAL::mark_domain_in_triangulation()`
\cgalCRPSection{Enum}
- \link CGAL::Triangulation_2::Locate_type `CGAL::Triangulation_2<Traits,Tds>::Locate_type` \endlink

View File

@ -431,6 +431,9 @@ public:
IndicesIterator indices_first,
IndicesIterator indices_beyond)
{
if(indices_first == indices_beyond){
return insert(points_first, points_beyond);
}
std::vector<Point> points(points_first, points_beyond);
return internal::insert_constraints(*this,points, indices_first, indices_beyond);
}

View File

@ -828,6 +828,9 @@ insert_constraint(Vertex_handle vaa, Vertex_handle vbb)
// if a vertex vc of t lies on segment ab
// or if ab intersect some constrained edges
{
if(vaa == vbb){
return;
}
std::stack<std::pair<Vertex_handle, Vertex_handle> > stack;
stack.push(std::make_pair(vaa,vbb));

View File

@ -34,7 +34,7 @@ namespace CGAL {
IndicesIterator indices_beyond )
{
if(indices_first == indices_beyond){
return 0;
return t.insert(points.begin(), points.end());
}
typedef typename T::Vertex_handle Vertex_handle;
typedef typename T::Face_handle Face_handle;

Some files were not shown because too many files have changed in this diff Show More