Merge remote-tracking branch 'cgal/master' into Mesh_3-sizing_field_with_aabb_tree-GF

# Conflicts:
#	Mesh_3/doc/Mesh_3/PackageDescription.txt
This commit is contained in:
Jane Tournois 2023-03-23 13:53:48 +01:00
commit ac5ccbd62f
66 changed files with 10442 additions and 230 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 ssh-keyscan -H ${{ secrets.host }} > ~/.ssh/known_hosts
- name: send email via ssh - name: send email via ssh
run: | 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

@ -201,6 +201,13 @@ bool read_polygon_mesh(const std::string& fname,
* \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.} * \cgalParamExtra{This parameter is only meaningful while using \ascii encoding.}
* \cgalParamNEnd * \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} * \cgalParamNBegin{verbose}
* \cgalParamDescription{whether extra information is printed when an incident occurs during reading} * \cgalParamDescription{whether extra information is printed when an incident occurs during reading}
* \cgalParamType{Boolean} * \cgalParamType{Boolean}

View File

@ -1,17 +1 @@
ETH Zurich (Switzerland). 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

View File

@ -20,7 +20,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <boost/cstdint.hpp> // for uint32_t, etc. #include <cstdint> // for uint32_t, etc.
#ifdef CGAL_USE_ZLIB #ifdef CGAL_USE_ZLIB
#include <zlib.h> #include <zlib.h>
@ -562,38 +562,50 @@ struct Word_type_generator<WK_FLOAT, sign, 8>
template <> template <>
struct Word_type_generator<WK_FIXED, SGN_SIGNED, 1> struct Word_type_generator<WK_FIXED, SGN_SIGNED, 1>
{ {
// typedef boost::int8_t type; // typedef std::int8_t type;
typedef char type; typedef char type;
}; };
template <> template <>
struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 1> struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 1>
{ {
typedef boost::uint8_t type; typedef std::uint8_t type;
}; };
template <> template <>
struct Word_type_generator<WK_FIXED, SGN_SIGNED, 2> struct Word_type_generator<WK_FIXED, SGN_SIGNED, 2>
{ {
typedef boost::int16_t type; typedef std::int16_t type;
}; };
template <> template <>
struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 2> struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 2>
{ {
typedef boost::uint16_t type; typedef std::uint16_t type;
}; };
template <> template <>
struct Word_type_generator<WK_FIXED, SGN_SIGNED, 4> struct Word_type_generator<WK_FIXED, SGN_SIGNED, 4>
{ {
typedef boost::int32_t type; typedef std::int32_t type;
}; };
template <> template <>
struct Word_type_generator<WK_FIXED, SGN_UNSIGNED, 4> 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> 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); Attribute_descriptor_i a1 = amap.template attribute<i>(adart);
if ( found_attributes.is_defined(a1) ) if ( found_attributes.is_defined(a1) )
{ // Here the attribute was already present in the hash_map { // 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 Attribute_descriptor_i a2 = amap.template
create_attribute<i>(amap.template get_attribute<i>(a1)); create_attribute<i>(amap.template get_attribute<i>(a1));

View File

@ -146,6 +146,8 @@ namespace CGAL {
{ return cit; } { return cit; }
bool is_used(size_type i) const bool is_used(size_type i) const
{ return mmap.mdarts.is_used(i); } { return mmap.mdarts.is_used(i); }
bool owns(size_type i) const
{ return mmap.mdarts.owns(i); }
private: private:
Self & mmap; Self & mmap;
}; };
@ -286,6 +288,13 @@ namespace CGAL {
{ {
CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0, CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0,
"copy_attribute<i> called but i-attributes are disabled."); "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= typename Attribute_descriptor<i>::type res=
std::get<Helper::template Dimension_index<i>::value> std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).emplace(get_attribute<i>(ah)); (mattribute_containers).emplace(get_attribute<i>(ah));

View File

@ -752,6 +752,9 @@ public:
return false; return false;
} }
bool owns(size_type i) const
{ return i<capacity() && is_used(i); }
bool owns_dereferenceable(const_iterator cit) const bool owns_dereferenceable(const_iterator cit) const
{ return cit!=end() && owns(cit); } { return cit!=end() && owns(cit); }
@ -764,7 +767,6 @@ public:
void reserve(size_type n) void reserve(size_type n)
{ {
if(capacity_>=n) return; if(capacity_>=n) return;
capacity_=n;
increase_size(); 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) target_link_libraries(Combinatorial_map_copy_test_index PUBLIC CGAL CGAL::Data)
cgal_add_compilation_test(Combinatorial_map_copy_test_index) cgal_add_compilation_test(Combinatorial_map_copy_test_index)
create_single_source_cgal_program(cmap_test_split_attribute.cpp)
# Link with OpenMesh if possible # Link with OpenMesh if possible
find_package(OpenMesh QUIET) find_package(OpenMesh QUIET)
if(TARGET OpenMesh::OpenMesh) 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} 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 % 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); Attribute_descriptor_i a1 = amap.template attribute<i>(adart);
if ( found_attributes.is_defined(a1) ) if ( found_attributes.is_defined(a1) )
{ // Here the attribute was already present in the hash_map { // 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 Attribute_descriptor_i a2 = amap.template
create_attribute<i>(amap.template get_attribute<i>(a1)); 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, CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0,
"copy_attribute<i> called but i-attributes are disabled."); "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= typename Attribute_descriptor<i>::type res=
std::get<Helper::template Dimension_index<i>::value> std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).emplace(get_attribute<i>(ah)); (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_compile_definitions(Generalized_map_test_index PUBLIC USE_COMPACT_CONTAINER_WITH_INDEX)
target_link_libraries(Generalized_map_test_index PUBLIC CGAL CGAL::Data) target_link_libraries(Generalized_map_test_index PUBLIC CGAL CGAL::Data)
cgal_add_compilation_test(Generalized_map_test_index) 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

@ -38,6 +38,13 @@ CGAL tetrahedral Delaunay refinement algorithm.
- 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. - 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) ### [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. - **Breaking change**: The region growing part of the package have been reworked to fix design issues introduced with the handling `FaceGraph` models.
@ -59,6 +66,7 @@ CGAL tetrahedral Delaunay refinement algorithm.
and cylinders in 3D. and cylinders in 3D.
### [2D Arrangements](https://doc.cgal.org/5.6/Manual/packages.html#PkgArrangementOnSurface2) ### [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. - 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) ### [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) ${CMAKE_BINARY_DIR}/icons/Triangulation_2.qrc)
endif() 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; } { return cit; }
bool is_used(size_type i) const bool is_used(size_type i) const
{ return mmap.mdarts.is_used(i); } { return mmap.mdarts.is_used(i); }
bool owns(size_type i) const
{ return mmap.mdarts.owns(i); }
private: private:
Self & mmap; Self & mmap;
}; };
@ -307,6 +309,13 @@ namespace CGAL {
{ {
CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0, CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0,
"copy_attribute<i> called but i-attributes are disabled."); "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= typename Attribute_descriptor<i>::type res=
std::get<Helper::template Dimension_index<i>::value> std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).emplace(get_attribute<i>(ah)); (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, CGAL_static_assertion_msg(Helper::template Dimension_index<i>::value>=0,
"copy_attribute<i> called but i-attributes are disabled."); "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= typename Attribute_descriptor<i>::type res=
std::get<Helper::template Dimension_index<i>::value> std::get<Helper::template Dimension_index<i>::value>
(mattribute_containers).emplace(get_attribute<i>(ah)); (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.na {background-color: white;}
TD.requirements { background-color: rgb(65%,65%,100%) } 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.warning {background-color: rgb(100%,100%,50%)}
TH.third_party_warning {background-color: rgb(75%,100%,50%)} TH.third_party_warning {background-color: rgb(75%,100%,50%)}
TH.error {background-color: rgb(100%,50%,50%)} TH.error {background-color: rgb(100%,50%,50%)}

View File

@ -20,7 +20,9 @@ INPUT += \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_facet_topology.h \ ${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_vertex_base_3.h \
${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_cell_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" PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Mesh Generation"
HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/implicit_domain_3.jpg \ 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). without the weights (left, 25563 vertices) and with the weights (right, 19936 vertices).
\cgalFigureEnd \cgalFigureEnd
\subsubsection Mesh_3DomainsFrom3DImagesWithCustomInitialization Domains From 3D Images, with a Custom Initialization \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 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 \snippet Mesh_3/mesh_3D_image_with_features.cpp Domain definition
Then, in the function `%main()`, after the `%domain` object has been created, In the %main() function, the domain is created with an additional argument - a
a dedicated function computes the 1D-features, and adds them to the domain. 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 The `CGAL::Mesh_3::Detect_features_in_image` functor is defined in its own
file. It uses non-documented code from \cgal, that should be copy-pasted in header file. It computes the one-dimensional features that correspond to the
any user-code willing to use similar code. It uses the undocumented intersections of the bounding box of the image with the surfaces defined by the
function template `%CGAL::polylines_to_protect` that computes the image, as well as polylines that lie at the intersection of three or more
1D-features that correspond to the intersection of the bounding box of the subdomains (including the outside). It then constructs a graph of these polyline
image with the surfaces defined by the image. At the same time, a few other features. The named constructor adds this feature graph to the domain for later
polylines are added as 1D-features, to protect 1D curves in the interior of feature protection. The original feature detection algorithm was described in
the image. Then, the method \cgalCite{cgal:hssz-gmcabonbc-97}, which provides a list of possible voxel
`CGAL::Mesh_domain_with_polyline_features_3::add_features` is called twice configurations. The feature detection implemented in \cgal generalizes this
to add the computed 1D-features to the mesh domain. 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 In the meshing criteria, if 1D features are added to the domain, the user
can define the parameter `edge_size` of the criteria class 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()`. Left: the mesh without any call to `%add_features()`.
Middle: the mesh with only the 1D-features computed by 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 Right: the mesh with added 1D-features in the interior of the bounding box
of the image. of the image.

View File

@ -16,6 +16,10 @@
/// \ingroup PkgMesh3Ref /// \ingroup PkgMesh3Ref
/// The classes in this group are models of domain concepts and their associated classes. /// 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 PkgMesh3DomainFields Mesh Domain Fields /// \defgroup PkgMesh3DomainFields Mesh Domain Fields
/// \ingroup PkgMesh3Ref /// \ingroup PkgMesh3Ref
/// The classes in this group are models of `MeshDomainField_3` /// The classes in this group are models of `MeshDomainField_3`
@ -107,6 +111,11 @@ and their associated classes:
- `CGAL::Labeled_image_mesh_domain_3<Image,BGT>` (deprecated) - `CGAL::Labeled_image_mesh_domain_3<Image,BGT>` (deprecated)
- `CGAL::Gray_image_mesh_domain_3<Image,BGT,Image_word_type>` (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} \cgalCRPSection{Function Templates}
- `CGAL::make_mesh_3()` - `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_gray_image_with_custom_initialization.cpp
\example Mesh_3/mesh_3D_image_with_features.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_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/mesh_3D_weighted_image.cpp
\example Mesh_3/random_labeled_image.h \example Mesh_3/random_labeled_image.h
\example CGAL/Mesh_3/initialize_triangulation_from_gray_image.h \example CGAL/Mesh_3/initialize_triangulation_from_gray_image.h

View File

@ -137,6 +137,12 @@ if(TARGET CGAL::CGAL_ImageIO)
create_single_source_cgal_program("mesh_3D_image_with_features.cpp") create_single_source_cgal_program("mesh_3D_image_with_features.cpp")
target_link_libraries(mesh_3D_image_with_features PUBLIC CGAL::Eigen3_support) 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) if(CGAL_ImageIO_USE_ZLIB)
create_single_source_cgal_program("mesh_optimization_example.cpp") create_single_source_cgal_program("mesh_optimization_example.cpp")
target_link_libraries(mesh_optimization_example PUBLIC CGAL::Eigen3_support) target_link_libraries(mesh_optimization_example PUBLIC CGAL::Eigen3_support)
@ -189,6 +195,8 @@ if(CGAL_ACTIVATE_CONCURRENT_MESH_3 AND TARGET CGAL::TBB_support)
mesh_3D_image_with_custom_initialization mesh_3D_image_with_custom_initialization
mesh_3D_gray_image_with_custom_initialization mesh_3D_gray_image_with_custom_initialization
mesh_3D_image_with_features mesh_3D_image_with_features
mesh_3D_image_with_detection_of_features
mesh_3D_image_with_input_features
mesh_implicit_domains mesh_implicit_domains
mesh_implicit_sphere mesh_implicit_sphere
mesh_implicit_sphere_variable_size 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/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Mesh_triangulation_3.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; typedef CGAL::Mesh_domain_with_polyline_features_3<Image_domain> Mesh_domain;
/// [Domain definition] /// [Domain definition]
#include <CGAL/Mesh_3/Detect_features_on_image_bbox.h>
#ifdef CGAL_CONCURRENT_MESH_3 #ifdef CGAL_CONCURRENT_MESH_3
typedef CGAL::Parallel_tag Concurrency_tag; typedef CGAL::Parallel_tag Concurrency_tag;
#else #else
@ -34,40 +36,8 @@ typedef CGAL::Mesh_criteria_3<Tr> Mesh_criteria;
namespace params = CGAL::parameters; namespace params = CGAL::parameters;
/// [Add 1D features] // Read input features
#include "read_polylines.h" #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[]) int main(int argc, char* argv[])
{ {
@ -79,21 +49,28 @@ int main(int argc, char* argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// Domain /// Load 1D-features
Mesh_domain domain = Mesh_domain::create_labeled_image_mesh_domain(image); 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;
/// Declare 1D-features, see above [Call add_1D_features] if (!read_polylines(lines_fname, features_inside)) // see file "read_polylines.h"
const std::string lines_fname = (argc>2)?argv[2]:CGAL::data_file_path("images/420.polylines.txt"); {
std::cerr << "Error: Cannot read file " << lines_fname << std::endl;
if(!add_1D_features(image, domain, lines_fname)) {
return EXIT_FAILURE; 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] /// Note that `edge_size` is needed with 1D-features [Mesh criteria]
Mesh_criteria criteria(params::edge_size(6). Mesh_criteria criteria(params::edge_size = 6.,
facet_angle(30).facet_size(6).facet_distance(4). params::facet_angle = 30,
cell_radius_edge_ratio(3).cell_size(8)); params::facet_size = 6,
params::facet_distance = 4,
params::cell_radius_edge_ratio = 3,
params::cell_size = 8);
/// [Mesh criteria] /// [Mesh criteria]
// Meshing // Meshing
@ -104,5 +81,5 @@ int main(int argc, char* argv[])
CGAL::IO::write_MEDIT(medit_file, c3t3); CGAL::IO::write_MEDIT(medit_file, c3t3);
medit_file.close(); 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/Labeled_mesh_domain_3.h>
#include <CGAL/Implicit_to_labeling_function_wrapper.h> #include <CGAL/Implicit_to_labeling_function_wrapper.h>
#include <CGAL/Mesh_3/Null_subdomain_index.h>
#include <CGAL/Random.h> #include <CGAL/Random.h>
namespace CGAL { namespace CGAL {

View File

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

View File

@ -31,6 +31,7 @@
#include <CGAL/Origin.h> #include <CGAL/Origin.h>
#include <functional> #include <functional>
#include <type_traits>
#include <CGAL/SMDS_3/internal/Handle_IO_for_pair_of_int.h> #include <CGAL/SMDS_3/internal/Handle_IO_for_pair_of_int.h>
#include <CGAL/SMDS_3/internal/indices_management.h> #include <CGAL/SMDS_3/internal/indices_management.h>
@ -48,6 +49,11 @@
#endif #endif
#include <boost/optional.hpp> #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 CGAL {
namespace Mesh_3 { namespace Mesh_3 {
namespace internal { 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::internal
} // end namespace CGAL::Mesh_3 } // end namespace CGAL::Mesh_3
#ifndef DOXYGEN_RUNNING #ifndef DOXYGEN_RUNNING
struct Null_subdomain_index {
template <typename T>
bool operator()(const T& x) const { return 0 == x; }
};
template <typename Subdomain_index> template <typename Subdomain_index>
struct Construct_pair_from_subdomain_indices { struct Construct_pair_from_subdomain_indices {
typedef std::pair<Subdomain_index, Subdomain_index> result_type; 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 * domain to be discretized is the union of voxels that have non-zero
* values. * 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" * \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
* \param image_ the input 3D image. * \param image_ the input 3D image.
* \param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below: * \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.} * bound, relative to the diameter of the box of the image.}
* \cgalParamDefault{FT(1e-3)} * \cgalParamDefault{FT(1e-3)}
* \cgalParamNEnd * \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 * \cgalNamedParamsEnd
* *
* \cgalHeading{Example} * \cgalHeading{Example}
@ -578,13 +669,24 @@ public:
* *
* \snippet Mesh_3/mesh_3D_weighted_image.cpp Domain creation * \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> 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;
using parameters::get_parameter_reference; using parameters::get_parameter_reference;
using parameters::choose_parameter; using parameters::choose_parameter;
auto iso_value_ = choose_parameter(get_parameter(np, internal_np::iso_value_param), 0); 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); 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)); 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); 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 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()); 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_); CGAL_USE(iso_value_);
namespace p = CGAL::parameters; 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()) if (weights_.is_valid())
{ return domain;
return Labeled_mesh_domain_3
(p::function = create_weighted_labeled_image_wrapper // features
(image_, Mesh_3::internal::Add_features_in_domain<!no_features>()
weights_, (image_, domain, input_features_, features_detector_);
image_values_to_subdomain_indices_,
value_outside_), return domain;
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_));
}
} }
/// @} /// @}
@ -686,7 +809,7 @@ public:
} }
template<typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT> 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"); 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; using parameters::get_parameter_reference;
@ -698,10 +821,10 @@ public:
template<typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_1, template<typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_1,
typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_2, typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_2,
typename ... NP> typename ... NP>
static Labeled_mesh_domain_3 create_labeled_image_mesh_domain(const CGAL::Image_3& image_, static auto create_labeled_image_mesh_domain(const CGAL::Image_3& image_,
const CGAL_NP_CLASS_1& np1, const CGAL_NP_CLASS_1& np1,
const CGAL_NP_CLASS_2& np2, const CGAL_NP_CLASS_2& np2,
const NP& ... nps) const NP& ... nps)
{ {
return create_labeled_image_mesh_domain(image_, internal_np::combine_named_parameters(np1, np2, 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, template<typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_1,
typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_2, typename CGAL_NP_TEMPLATE_PARAMETERS_NO_DEFAULT_2,
typename ... NP> typename ... NP>
static Labeled_mesh_domain_3 create_labeled_image_mesh_domain(const CGAL_NP_CLASS_1& np1, static auto create_labeled_image_mesh_domain(const CGAL_NP_CLASS_1& np1,
const CGAL_NP_CLASS_2& np2, const CGAL_NP_CLASS_2& np2,
const NP& ... nps) const NP& ... nps)
{ {
return create_labeled_image_mesh_domain(internal_np::combine_named_parameters(np1, np2, 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 // null(f(p)) means p is outside the domain
Subdomain_index index = (r_domain_.function_)(p); Subdomain_index index = (r_domain_.function_)(p);
if ( r_domain_.null(index) ) if ( r_domain_.null(index) )
return Subdomain(); return Subdomain{};
else else
return Subdomain(index); return Subdomain{ index };
} }
private: private:
const Labeled_mesh_domain_3& r_domain_; const Labeled_mesh_domain_3& r_domain_;

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

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

View File

@ -15,7 +15,6 @@
#include <CGAL/license/Mesh_3.h> #include <CGAL/license/Mesh_3.h>
#include <vector> #include <vector>
#include <map> #include <map>
#include <utility> // std::swap #include <utility> // std::swap
@ -23,17 +22,23 @@
#include <CGAL/tuple.h> #include <CGAL/tuple.h>
#include <CGAL/Image_3.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/boost/graph/split_graph_into_polylines.h>
#include <CGAL/Mesh_3/internal/Graph_manipulations.h> #include <CGAL/Mesh_3/internal/Graph_manipulations.h>
#include <boost/graph/adjacency_list.hpp> #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/utility.hpp> // for boost::prior
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <CGAL/Search_traits_3.h> #include <CGAL/Search_traits_3.h>
#include <CGAL/Orthogonal_incremental_neighbor_search.h> #include <CGAL/Orthogonal_incremental_neighbor_search.h>
#include <CGAL/Mesh_3/Null_subdomain_index.h>
#include <type_traits>
namespace CGAL { namespace CGAL {
namespace Mesh_3 { namespace Mesh_3 {
namespace internal { namespace internal {
@ -1128,6 +1133,63 @@ polylines_to_protect(const CGAL::Image_3& cgal_image,
existing_polylines_end); 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 } // namespace CGAL
#endif // CGAL_MESH_3_POLYLINES_TO_PROTECT_H #endif // CGAL_MESH_3_POLYLINES_TO_PROTECT_H

View File

@ -31,6 +31,7 @@ create_single_source_cgal_program( "test_without_detect_features.cpp" )
if(CGAL_ImageIO_USE_ZLIB) if(CGAL_ImageIO_USE_ZLIB)
create_single_source_cgal_program( "test_meshing_3D_image.cpp" ) 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_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.cpp" )
create_single_source_cgal_program( "test_meshing_3D_gray_image_deprecated.cpp" ) create_single_source_cgal_program( "test_meshing_3D_gray_image_deprecated.cpp" )
else() else()
@ -64,6 +65,7 @@ foreach(target
test_without_detect_features test_without_detect_features
test_meshing_3D_image test_meshing_3D_image
test_meshing_3D_image_deprecated test_meshing_3D_image_deprecated
test_meshing_3D_image_with_features
test_meshing_3D_gray_image test_meshing_3D_gray_image
test_meshing_3D_gray_image_deprecated test_meshing_3D_gray_image_deprecated
test_meshing_implicit_function 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

@ -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 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, 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 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 \relates Polygon_with_holes_2
*/ */

View File

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

View File

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

View File

@ -640,7 +640,7 @@ public:
but are isolated from the complex at the end of the meshing process. 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 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() void remove_isolated_vertices()
{ {
@ -669,7 +669,8 @@ public:
std::vector<Vertex_handle> isolated; std::vector<Vertex_handle> isolated;
for (Vertex_handle v : tr.finite_vertex_handles()) 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); isolated.push_back(v);
} }

View File

@ -325,6 +325,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(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(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_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(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) 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(); for(Polygon_with_holes::Hole_const_iterator it = input.holes_begin();
it != input.holes_end(); it != input.holes_end();
++it){ ++it){
assert(it->is_counterclockwise_oriented()); assert(it->is_clockwise_oriented());
} }
double lOffset = 0.25 ; double lOffset = 0.25 ;
@ -75,13 +75,13 @@ int main( int argc, char* argv[] )
else else
{ {
std::cerr << "Computes the interior offset of a polygon with holes and draws the result in an EPS file." << std::endl 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 << std::endl
<< "Usage: show_offset_polygon <intput_file> [offset_distance] [output_eps_file]" << std::endl << " input_file Text file describing the input polygon with holes." << std::endl
<< std::endl << " (See input_file_format.txt for details" << std::endl
<< " intput_file Text file describing the input polygon with holes." << std::endl << " or use input_file_example.txt)" << std::endl
<< " (See inputfile_format.txt for details)" << std::endl << " output_file [default='input_file.offset.eps']" << std::endl ;
<< " offset_distance [default=0.25]." << std::endl
<< " output_file [default='innput_file.offset.eps']" << std::endl ;
} }
return 0; 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(); for(Polygon_with_holes::Hole_const_iterator it = input.holes_begin();
it != input.holes_end(); it != input.holes_end();
++it){ ++it){
assert(it->is_counterclockwise_oriented()); assert(it->is_clockwise_oriented());
} }
//check the validity of the input and fix orientation //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."; std::cerr << "ERROR: outer boundary is not simple.";
return 1; return 1;
} }
if ( input.outer_boundary().is_clockwise_oriented() )
input.outer_boundary().reverse_orientation();
int k=0; int k=0;
for (Polygon_with_holes::Hole_iterator it = input.holes_begin(); for (Polygon_with_holes::Hole_iterator it = input.holes_begin();
it!=input.holes_end(); ++it, ++k) 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"; std::cerr << "ERROR: hole "<< k << " is not simple.\n";
return 1; return 1;
} }
if (it->is_counterclockwise_oriented())
it->reverse_orientation();
} }
Straight_skeleton_ptr ss = CGAL::create_interior_straight_skeleton_2(input); 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::cerr << "Computes the straight skeleton in the interior of a polygon with holes and draws it in an EPS file." << std::endl
<< 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 << std::endl
<< " intput_file Text file describing the input polygon with holes." << std::endl << " input_file Text file describing the input polygon with holes." << std::endl
<< " (See input_file_format.txt for details)" << std::endl << " (See input_file_format.txt for details" << std::endl
<< " output_file [default='innput_file.skeleton.eps']" << std::endl ; << " or use input_file_example.txt)" << std::endl
<< " output_file [default='input_file.skeleton.eps']" << std::endl ;
} }
return 0; 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

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

View File

@ -1215,6 +1215,10 @@ public:
fprops_.resize(nfaces); 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) bool join(const Surface_mesh& other)
{ {
// increase capacity // increase capacity

View File

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

View File

@ -9,18 +9,22 @@ R = RU Groningen
AABB_tree I AABB_tree I
Advancing_front_surface_reconstruction I
Algebraic_foundations ETIMU Algebraic_foundations ETIMU
Algebraic_kernel_d IM Algebraic_kernel_d IM
Algebraic_kernel_for_circles I Algebraic_kernel_for_circles I
Algebraic_kernel_for_spheres I Algebraic_kernel_for_spheres I
Alpha_shapes_2 I Alpha_shapes_2 I
Alpha_shapes_3 I Alpha_shapes_3 I
Alpha_wrap_3 I Google LLC (USA).
Apollonius_graph_2 I Apollonius_graph_2 I
Approximate_min_ellipsoid_d E Approximate_min_ellipsoid_d E
Arithmetic_kernel M Arithmetic_kernel M
Arrangement_on_surface_2 T Arrangement_on_surface_2 T
Barycentric_coordinates_2 IG; Università della Svizzera italiana (Switzerland)
BGL G BGL G
Boolean_set_operations_2 T Boolean_set_operations_2 T
Bounding_volumes E
Box_intersection_d M Box_intersection_d M
CGAL_Core NYU; Chee Yap agreed to upgrade CGAL_Core NYU; Chee Yap agreed to upgrade
CGAL_ImageIO third party lib under LGPL CGAL_ImageIO third party lib under LGPL
@ -29,7 +33,9 @@ R = RU Groningen
Circular_kernel_2 I Circular_kernel_2 I
Circular_kernel_3 I Circular_kernel_3 I
Circulator ETIMU Circulator ETIMU
Combinatorial_map Cnrs; Guillaume Damiand upgraded Classification G
Combinatorial_map CNRS; Guillaume Damiand upgraded
Cone_spanners_2 University of Western Sydney (Australia)
Conic_2 ETIMU Conic_2 ETIMU
Convex_decomposition_3 M Convex_decomposition_3 M
Convex_hull_2 M Convex_hull_2 M
@ -41,24 +47,28 @@ R = RU Groningen
Envelope_2 T Envelope_2 T
Envelope_3 T Envelope_3 T
Filtered_kernel I Filtered_kernel I
Generalized_map CNRS
Generator ETIMU Generator ETIMU
Geomview ETIMU Geomview ETIMU
GraphicsView G GraphicsView G
HalfedgeDS ETIMU HalfedgeDS ETIMU
Hash_map M Hash_map M
Heat_method_3 G; Carnegie Mellon University
Homogeneous_kernel ETIMU Homogeneous_kernel ETIMU
Hyperbolic_triangulation_2 I
Inscribed_areas ET
Installation ETIMU Installation ETIMU
Interpolation I Interpolation I
Intersections_2 ETIMU Intersections_2 ETIMU
Intersections_3 ETIMU Intersections_3 ETIMU
Interval_skip_list G Interval_skip_list G
Interval_support M Interval_support M
Inventor ETIMU
Jet_fitting_3 I Jet_fitting_3 I
Kernel_23 ETIMU Kernel_23 ETIMU
Kernel_d ETIMU Kernel_d ETIMU
LEDA ETIMU LEDA ETIMU
Largest_empty_rect_2 T Largest_empty_rect_2 T
Linear_cell_complex CNRS
MacOSX F MacOSX F
Maintenance ETIMUG Maintenance ETIMUG
Manual ETIMU Manual ETIMU
@ -66,6 +76,7 @@ R = RU Groningen
Matrix_search E Matrix_search E
Mesh_2 I Mesh_2 I
Mesh_3 I Mesh_3 I
Mesher_level I
Min_annulus_d E Min_annulus_d E
Min_circle_2 E Min_circle_2 E
Min_ellipse_2 E Min_ellipse_2 E
@ -79,48 +90,80 @@ R = RU Groningen
Nef_2 M Nef_2 M
Nef_3 M Nef_3 M
Nef_S2 M Nef_S2 M
NewKernel_d I
Number_types ETIMU Number_types ETIMU
OpenNL third party lib under LGPL 3 OpenNL third party lib under LGPL 3
Optimal_bounding_box G
Optimal_transportation_reconstruction_2 I
Optimisation_basic E Optimisation_basic E
Optimisation_doc E Optimisation_doc E
Orthtree I
Partition_2 M Partition_2 M
Periodic_2_triangulation_2 I
Periodic_3_triangulation_3 I Periodic_3_triangulation_3 I
Periodic_3_mesh_3 I
Periodic_4_hyperbolic_triangulation_2 I
Point_set_2 Halle transfered copyright to Inria Point_set_2 Halle transfered copyright to Inria
Point_set_3 G
Point_set_processing_3 I Point_set_processing_3 I
Poisson_surface_reconstruction_3 I Poisson_surface_reconstruction_3 I
Polygon ETIMU Polygon ETIMU
Polygonal_surface_reconstruction Liangliang Nan
Polygon_mesh_processing G
Polyhedron E Polyhedron E
Polyhedron_IO E Polyline_simplification_2 G
Polynomial M Polynomial M
Polytope_distance_d E Polytope_distance_d E
Principal_component_analysis I Principal_component_analysis I
Principal_component_analysis_LGPL I
Profiling_tools ETIMU Profiling_tools ETIMU
Property_map I
QP_solver E QP_solver E
Qt_widget I
Random_numbers ETIMU Random_numbers ETIMU
Ridges_3 I Ridges_3 I
Robustness M Scale_space_reconstruction_3 I
STL_Extension ETIMU STL_Extension ETIMU
Scripts ETIMU Scripts ETIMU
SearchStructures E SearchStructures E
Segment_Delaunay_graph_2 I Menelaos removed Notre Dame U Segment_Delaunay_graph_2 I Menelaos removed Notre Dame U
Segment_Delaunay_graph_Linf_2 Università della Svizzera italiana
Set_movable_separability_2 T Set_movable_separability_2 T
Shape_detection I
Shape_regularization GI
Skin_surface_3 R Gert Vegter agreed to upgrade Skin_surface_3 R Gert Vegter agreed to upgrade
SMDS_3 I
Snap_rounding_2 T Snap_rounding_2 T
Solver_interface I
Spatial_searching U Spatial_searching U
Spatial_sorting I Spatial_sorting I
Straight_skeleton_2 Cacciola; Fernando agreed to upgrade to GPL STL_Extension ETIMU
Straight_skeleton_2 G
Stream_lines_2 I Stream_lines_2 I
Stream_support ETIMU Stream_support ETIMU
Subdivision_method_3 G Subdivision_method_3 G
Surface_mesh_parameterization I Surface_mesh G; Bielefeld University; RWTH Aachen
Surface_mesh_simplification G Surface_mesh_approximation I
Surface_mesh_deformation G
Surface_mesher I Surface_mesher I
Surface_mesh_parameterization I
Surface_mesh_segmentation G
Surface_mesh_shortest_path G
Surface_mesh_simplification G
Surface_mesh_skeletonization G
Surface_mesh_topology CNRS
Surface_sweep_2 T
TDS_2 I
TDS_3 I
Testsuite IG Testsuite IG
Tetrahedral_remeshing G; Telecom Paris (France)
Triangulation I
Triangulation_2 I Triangulation_2 I
Triangulation_3 I Triangulation_3 I
Triangulation_on_sphere_2 I
Union_find M Union_find M
Visibility_2 Braunschweig University (Germany).
Voronoi_diagram_2 F I sent mail to Forth Voronoi_diagram_2 F I sent mail to Forth
Weights G
Width_3 E Width_3 E
iostream ETIMU iostream ETIMU
kdtree T kdtree T