Merge pull request #1115 from lrineau/Mesh_3-connected_components_for_images-GF

Mesh_3: connected components for 3D images
This commit is contained in:
Sebastien Loriot 2016-06-22 14:52:10 +02:00 committed by GitHub
commit 749e40fce9
33 changed files with 1019 additions and 86 deletions

1
.gitignore vendored
View File

@ -373,6 +373,7 @@ Mesh_3/examples/Mesh_3/*.mesh.*
Mesh_3/examples/Mesh_3/*.off
Mesh_3/examples/Mesh_3/*.png
Mesh_3/examples/Mesh_3/.*.deps
Mesh_3/examples/Mesh_3/random-image.inr
Mesh_3/examples/Mesh_3/Makefile
Mesh_3/examples/Mesh_3/applications
Mesh_3/examples/Mesh_3/cgal_test_with_cmake

View File

@ -614,7 +614,7 @@ static_evaluate(const _image* image,
template <typename Word>
inline
Word
Word&
static_evaluate(const _image* image,
const std::size_t i,
const std::size_t j,
@ -623,6 +623,15 @@ static_evaluate(const _image* image,
return ((Word*)image->data)[(k * image->ydim + j) * image->xdim + i];
}
template <typename Word>
inline
Word&
static_evaluate(const _image* image,
const std::size_t i)
{
return ((Word*)image->data)[i];
}
} // end namespace IMAGEIO
} // end namespace CGAL

View File

@ -6,4 +6,8 @@ HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/implicit_domain_3.jpg
${CGAL_PACKAGE_DOC_DIR}/fig/implicit_domain_5.jpg \
${CGAL_PACKAGE_DOC_DIR}/fig/no-protection.png \
${CGAL_PACKAGE_DOC_DIR}/fig/protection-box.png \
${CGAL_PACKAGE_DOC_DIR}/fig/protection-all.png
${CGAL_PACKAGE_DOC_DIR}/fig/protection-all.png \
${CGAL_PACKAGE_DOC_DIR}/fig/no-custom-init.png \
${CGAL_PACKAGE_DOC_DIR}/fig/with-custom-init.png
EXAMPLE_PATH += ${CGAL_PACKAGE_INCLUDE_DIR}

View File

@ -669,6 +669,91 @@ The resulting mesh is shown in \cgalFigureRef{figureliver_3d_image_mesh}.
Cut view of a 3D mesh produced from a segmented liver image. Code from subsection \ref Mesh_3_subsection_examples_3d_image generates this file.
\cgalFigureEnd
\subsubsection Mesh_3DomainsFromSegmented3DImagesWithCustomInitialization Domains From Segmented 3D Images, with a Custom Initialization
The example \ref Mesh_3/mesh_3D_image_with_custom_initialization.cpp is a modification
of \ref Mesh_3/mesh_3D_image.cpp. The goal of that example is to show how
the default initialization of the triangulation, using random rays, can be
replaced by a new implementation. In this case, the initialization detects
all connected components in the 3D segmented image, and inserts points in
the triangulation for each connected component.
For the meshing, in the previous example (\ref Mesh_3/mesh_3D_image.cpp), we called `make_mesh_3()` as follows.
\snippet Mesh_3/mesh_3D_image.cpp Meshing
In the example \ref Mesh_3/mesh_3D_image_with_custom_initialization.cpp,
that call is replaced by:
-# the creation of an empty `%c3t3` object,
-# a call to a non-documented function
`initialize_triangulation_from_labeled_image()` that inserts points in
the triangulation,
-# then the call to `refine_mesh_3()`.
\snippet Mesh_3/mesh_3D_image_with_custom_initialization.cpp Meshing
The code of the function `initialize_triangulation_from_labeled_image()` is
in the non-documented header \ref
CGAL/Mesh_3/initialize_triangulation_from_labeled_image.h\. As it is
undocumented and may be removed or modified at any time, if you wish to
use it then you should copy-paste it to your user code. The code of that
function is rather complicated. The following lines show how to insert new
points in the `%c3t3` object, with the calls to
`MeshVertexBase_3::set_dimension()` and
`MeshVertexBase_3::set_index()`.
\snippet CGAL/Mesh_3/initialize_triangulation_from_labeled_image.h insert initial points
The value of `index` must be consistent with the possible values of
`Mesh_domain::Index`. In \ref
CGAL/Mesh_3/initialize_triangulation_from_labeled_image.h, it is
constructed using the API of the mesh domain, as follows. First the functor
`construct_intersect` is created
\dontinclude CGAL/Mesh_3/initialize_triangulation_from_labeled_image.h
\skip Construct_intersection construct_intersection =
\until construct_intersection_object
then the `%Mesh_domain::Intersection` object (a `%tuple` with three
elements) is constructed using a call to the functor `construct_intersection`
\skip Intersection intersect =
\until construct_intersection
and eventually `%index` is the element \#1 of `%intersect`.
\skipline get<1>(intersect)
The result of the custom initialization can be seen in
\cgalFigureRef{mesh3custominitimage3D}. The generated 3D image contains a
big sphere at the center, and 50 smaller spheres, generated
randomly. Without the custom initialization, only the biggest component
(the sphere at the center) was initialized and meshed. With the custom
initialization, the initial `%c3t3` object contains points on all connected
components, and all spheres are meshed.
\cgalFigureAnchor{mesh3custominitimage3D}
<center>
<table border=0>
<tr>
<td><img border="0" src="./no-custom-init.png"></td>
<td><img border="0" src="./with-custom-init.png"></td>
</tr>
</table>
</center>
\cgalFigureCaptionBegin{mesh3custominitimage3D}
Left: the mesh without the custom initialization, only the big sphere at
the center is meshed
Right: the mesh generated after the initialization of all connected components
\cgalFigureCaptionEnd
Note that the example \ref
Mesh_3/mesh_3D_image_with_custom_initialization.cpp also shows how to
create a 3D image using the undocumented API of CGAL_ImageIO.
\snippet Mesh_3/mesh_3D_image_with_custom_initialization.cpp Create the image
The code of the function `%random_labeled_image()` is in the header file \ref
Mesh_3/random_labeled_image.h\.
\subsection Mesh_3UsingVariableSizingField Using Variable Sizing Field
\subsubsection Mesh_3SizingFieldasanAnalyticalFunction Sizing Field as an Analytical Function

View File

@ -2,6 +2,9 @@
\example Mesh_3/implicit_functions.cpp
\example Mesh_3/mesh_3D_image.cpp
\example Mesh_3/mesh_3D_image_with_features.cpp
\example Mesh_3/mesh_3D_image_with_custom_initialization.cpp
\example Mesh_3/random_labeled_image.h
\example CGAL/Mesh_3/initialize_triangulation_from_labeled_image.h
\example Mesh_3/mesh_3D_image_variable_size.cpp
\example Mesh_3/mesh_implicit_domains.cpp
\example Mesh_3/mesh_implicit_domains_2.cpp

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -86,6 +86,7 @@ if ( CGAL_FOUND )
create_single_source_cgal_program( "mesh_optimization_example.cpp" )
create_single_source_cgal_program( "mesh_optimization_lloyd_example.cpp" )
create_single_source_cgal_program( "mesh_3D_image.cpp" )
create_single_source_cgal_program( "mesh_3D_image_with_custom_initialization.cpp" )
create_single_source_cgal_program( "mesh_3D_image_variable_size.cpp" )
else()
message( STATUS "NOTICE: The examples mesh_3D_image.cpp, mesh_3D_image_variable_size.cpp, mesh_optimization_example.cpp and mesh_optimization_lloyd_example.cpp need CGAL_ImageIO to be configured with ZLIB support, and will not be compiled." )

View File

@ -1,4 +1,3 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Mesh_triangulation_3.h>
@ -32,13 +31,14 @@ using namespace CGAL::parameters;
int main(int argc, char* argv[])
{
/// [Loads image]
const char* fname = (argc>1)?argv[1]:"data/liver.inr.gz";
// 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
Mesh_domain domain(image);
@ -47,8 +47,9 @@ int main(int argc, char* argv[])
Mesh_criteria criteria(facet_angle=30, facet_size=6, facet_distance=4,
cell_radius_edge_ratio=3, cell_size=8);
// Meshing
/// [Meshing]
C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(domain, criteria);
/// [Meshing]
// Output
std::ofstream medit_file("out.mesh");

View File

@ -0,0 +1,64 @@
#include "random_labeled_image.h"
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Mesh_triangulation_3.h>
#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
#include <CGAL/Mesh_criteria_3.h>
#include <CGAL/Mesh_3/initialize_triangulation_from_labeled_image.h>
#include <CGAL/Labeled_image_mesh_domain_3.h>
#include <CGAL/make_mesh_3.h>
#include <CGAL/Image_3.h>
#include <CGAL/Mesh_3/Dump_c3t3.h>
// Domain
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Labeled_image_mesh_domain_3<CGAL::Image_3,K> Mesh_domain;
#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
using namespace CGAL::parameters;
int main()
{
/// [Create the image]
CGAL::Image_3 image = random_labeled_image();
/// [Create the image]
// Domain
Mesh_domain domain(image);
// Mesh criteria
Mesh_criteria criteria(facet_angle=30, facet_size=3, facet_distance=1,
cell_radius_edge_ratio=3, cell_size=3);
/// [Meshing]
C3t3 c3t3;
initialize_triangulation_from_labeled_image(c3t3,
domain,
image,
criteria,
(unsigned char)0);
CGAL::refine_mesh_3<C3t3>(c3t3, domain, criteria);
/// [Meshing]
// Output
CGAL::dump_c3t3(c3t3, "out");
return 0;
}

View File

@ -0,0 +1,53 @@
#include <CGAL/Image_3.h>
#include <CGAL/Random.h>
#include <algorithm>
CGAL::Image_3 random_labeled_image()
{
const int dim = 400;
const unsigned char number_of_spheres = 50;
const int max_radius_of_spheres = 10;
const int radius_of_big_sphere = 80;
_image* image = _createImage(dim, dim, dim, 1,
1.f, 1.f, 1.f, 1,
WK_FIXED, SGN_UNSIGNED);
unsigned char* ptr = (unsigned char*)(image->data);
std::fill(ptr, ptr+dim*dim*dim, '\0');
std::ptrdiff_t center = dim / 2;
CGAL::Random rand(0);
for(unsigned char n = number_of_spheres; n > 0 ; --n) {
std::size_t i, j, k;
do {
i = rand.uniform_smallint(1 + max_radius_of_spheres,
dim-2 - max_radius_of_spheres);
j = rand.uniform_smallint(1 + max_radius_of_spheres,
dim-2 - max_radius_of_spheres);
k = rand.uniform_smallint(1 + max_radius_of_spheres,
dim-2 - max_radius_of_spheres);
} while ( ( CGAL::square(double(center) - double(i)) +
CGAL::square(double(center) - double(j)) +
CGAL::square(double(center) - double(k)) )
<
CGAL::square(double(radius_of_big_sphere) + 4 * max_radius_of_spheres) );
std::ptrdiff_t radius = max_radius_of_spheres;
if(n==1) {
i = j = k = center;
radius = radius_of_big_sphere;
}
for(std::ptrdiff_t ii = - radius; ii <= radius; ++ii)
{
for(std::ptrdiff_t jj = - radius; jj <= radius; ++jj)
{
for(std::ptrdiff_t kk = - radius; kk <= radius; ++kk)
{
if(ii*ii + jj*jj + kk*kk > radius * radius) continue;
using CGAL::IMAGEIO::static_evaluate;
static_evaluate<unsigned char>(image, i+ii, j+jj, k+kk) = n;
}
}
}
}
_writeImage(image, "random-image.inr");
return CGAL::Image_3(image);
}

View File

@ -32,6 +32,7 @@
#include <CGAL/Labeled_mesh_domain_3.h>
#include <CGAL/Mesh_3/Image_to_labeled_function_wrapper.h>
#include <CGAL/Bbox_3.h>
#include <CGAL/Default.h>
namespace CGAL {

View File

@ -39,6 +39,10 @@
#include <CGAL/tuple.h>
#include <CGAL/Origin.h>
#include <CGAL/Default.h>
#include <CGAL/internal/Mesh_3/Handle_IO_for_pair_of_int.h>
namespace CGAL {
struct Null_subdomain_index {

View File

@ -32,9 +32,13 @@ namespace CGAL {
template <typename C3t3,
bool is_streamable =
is_streamable<typename C3t3::Triangulation::Vertex>::value &&
is_streamable<typename C3t3::Triangulation::Cell>::value &&
is_streamable<typename C3t3::Surface_patch_index>::value &&
is_streamable<typename C3t3::Subdomain_index>::value
is_streamable<typename C3t3::Triangulation::Cell>::value
&&
(is_streamable<typename C3t3::Surface_patch_index>::value ||
Output_rep<typename C3t3::Surface_patch_index>::is_specialized)
&&
(is_streamable<typename C3t3::Subdomain_index>::value ||
Output_rep<typename C3t3::Subdomain_index>::is_specialized)
>
struct Dump_c3t3 {
void dump_c3t3(const C3t3& c3t3, std::string prefix) const {
@ -75,13 +79,17 @@ struct Dump_c3t3<C3t3, false> {
<< "\n";
}
if(!is_streamable<typename C3t3::Surface_patch_index>::value) {
if(!is_streamable<typename C3t3::Surface_patch_index>::value &&
!CGAL::Output_rep<typename C3t3::Surface_patch_index>::is_specialized)
{
std::cerr << " - C3t3::Surface_patch_index is not streamable\n";
std::cerr << " "
<< typeid(typename C3t3::Surface_patch_index).name()
<< "\n";
}
if(!is_streamable<typename C3t3::Subdomain_index>::value) {
if(!is_streamable<typename C3t3::Subdomain_index>::value &&
!CGAL::Output_rep<typename C3t3::Subdomain_index>::is_specialized)
{
std::cerr << " - C3t3::Subdomain_index is not streamable\n";
std::cerr << " "
<< typeid(typename C3t3::Subdomain_index).name()

View File

@ -0,0 +1,237 @@
// Copyright (c) 2015,2016 GeometryFactory
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
//
// Author(s) : Laurent Rineau
#ifndef CGAL_MESH_3_INITIALIZE_TRIANGULATION_FROM_LABELED_IMAGE_H
#define CGAL_MESH_3_INITIALIZE_TRIANGULATION_FROM_LABELED_IMAGE_H
#include <CGAL/Mesh_3/search_for_connected_components_in_labeled_image.h>
#include <iostream>
#include <queue>
#include <CGAL/Mesh_3/squared_distance_Point_3_Triangle_3.h>
#include <CGAL/iterator.h>
#include <CGAL/point_generators_3.h>
#include <CGAL/Image_3.h>
#include <CGAL/make_mesh_3.h>
#include <boost/foreach.hpp>
template <typename Point>
struct Get_point
{
const double vx, vy, vz;
Get_point(const CGAL::Image_3* image)
: vx(image->vx())
, vy(image->vy())
, vz(image->vz())
{}
Point operator()(const std::size_t i,
const std::size_t j,
const std::size_t k) const
{
return Point(double(i) * vx, double(j) * vy, double(k) * vz);
}
};
template<class C3T3, class MeshDomain, class MeshCriteria>
void init_tr_from_labeled_image_call_init_features(C3T3&,
const MeshDomain&,
const MeshCriteria&,
CGAL::Tag_false)
{
}
template<class C3T3, class MeshDomain, class MeshCriteria>
void init_tr_from_labeled_image_call_init_features(C3T3& c3t3,
const MeshDomain& domain,
const MeshCriteria& criteria,
CGAL::Tag_true)
{
CGAL::internal::Mesh_3::init_c3t3_with_features(c3t3,
domain,
criteria);
std::cout << c3t3.triangulation().number_of_vertices()
<< " initial points on 1D-features" << std::endl;
}
template<class C3T3, class MeshDomain, class MeshCriteria,
typename Image_word_type>
void initialize_triangulation_from_labeled_image(C3T3& c3t3,
const MeshDomain& domain,
const CGAL::Image_3& image,
const MeshCriteria& criteria,
Image_word_type,
bool protect_features = false
)
{
typedef typename C3T3::Triangulation Tr;
typedef typename Tr::Point Weighted_point;
typedef typename Weighted_point::Point Point_3;
typedef typename Tr::Segment Segment_3;
typedef typename Tr::Geom_traits::Vector_3 Vector_3;
typedef typename Tr::Vertex_handle Vertex_handle;
typedef typename Tr::Cell_handle Cell_handle;
typedef Point_3 Point;
typedef MeshDomain Mesh_domain;
Tr& tr = c3t3.triangulation();
if(protect_features) {
init_tr_from_labeled_image_call_init_features
(c3t3, domain, criteria,
CGAL::internal::Mesh_3::Has_features<Mesh_domain>());
}
const double max_v = (std::max)((std::max)(image.vx(),
image.vy()),
image.vz());
typedef std::vector<std::pair<Point_3, std::size_t> > Seeds;
Seeds seeds;
Get_point<Point_3> get_point(&image);
std::cout << "Searching for connected components..." << std::endl;
CGAL::Identity<Image_word_type> no_transformation;
search_for_connected_components_in_labeled_image(image,
std::back_inserter(seeds),
CGAL::Emptyset_iterator(),
no_transformation,
get_point,
Image_word_type());
std::cout << " " << seeds.size() << " components were found." << std::endl;
std::cout << "Construct initial points..." << std::endl;
for(typename Seeds::const_iterator it = seeds.begin(), end = seeds.end();
it != end; ++it)
{
const double radius = double(it->second + 1)* max_v;
CGAL::Random_points_on_sphere_3<Point> points_on_sphere_3(radius);
typename Mesh_domain::Construct_intersection construct_intersection =
domain.construct_intersection_object();
std::vector<Vector_3> directions;
if(it->second < 2) {
// shoot in six directions
directions.push_back(Vector_3(-radius, 0, 0));
directions.push_back(Vector_3(+radius, 0, 0));
directions.push_back(Vector_3(0, -radius, 0));
directions.push_back(Vector_3(0, +radius, 0));
directions.push_back(Vector_3(0, 0, -radius));
directions.push_back(Vector_3(0, 0, +radius));
} else {
for(int i = 0; i < 20; ++i)
{
// shoot 20 random directions
directions.push_back(*points_on_sphere_3++ - CGAL::ORIGIN);
}
}
BOOST_FOREACH(const Vector_3& v, directions)
{
const Point test = it->first + v;
const typename Mesh_domain::Intersection intersect =
construct_intersection(Segment_3(it->first, test));
if (CGAL::cpp11::get<2>(intersect) != 0)
{
Point_3 pi = CGAL::cpp11::get<0>(intersect);
// This would cause trouble to optimizers
// check pi will not be hidden
typename Tr::Locate_type lt;
Cell_handle c;
int li, lj;
Cell_handle pi_cell = tr.locate(pi, lt, li, lj);
if(lt != Tr::OUTSIDE_AFFINE_HULL) {
switch (tr.dimension())
{ //skip dimension 0
case 1:
if (tr.side_of_power_segment(pi_cell, pi, true) != CGAL::ON_BOUNDED_SIDE)
continue;
break;
case 2:
if (tr.side_of_power_circle(pi_cell, 3, pi, true) != CGAL::ON_BOUNDED_SIDE)
continue;
break;
case 3:
if (tr.side_of_power_sphere(pi_cell, pi, true) != CGAL::ON_BOUNDED_SIDE)
continue;
}
}
//check pi is not inside a protecting ball
std::vector<Vertex_handle> conflict_vertices;
if (tr.dimension() == 3)
{
tr.vertices_on_conflict_zone_boundary(pi, pi_cell
, std::back_inserter(conflict_vertices));
}
else
{
for (typename Tr::Finite_vertices_iterator vit = tr.finite_vertices_begin();
vit != tr.finite_vertices_end(); ++vit)
{
if (vit->point().weight() > 0.)
conflict_vertices.push_back(vit);
}
}
bool pi_inside_protecting_sphere = false;
BOOST_FOREACH(Vertex_handle cv, conflict_vertices)
{
if (cv->point().weight() == 0.)
continue;
if (CGAL::compare_squared_distance(pi, cv->point(), cv->point().weight())
!= CGAL::LARGER)
{
pi_inside_protecting_sphere = true;
break;
}
}
if (pi_inside_protecting_sphere)
continue;
const typename Mesh_domain::Index index = CGAL::cpp11::get<1>(intersect);
/// The following lines show how to insert initial points in the
/// `c3t3` object. [insert initial points]
Vertex_handle v = tr.insert(pi);
// `v` could be null if `pi` is hidden by other vertices of `tr`.
CGAL_assertion(v != Vertex_handle());
c3t3.set_dimension(v, 2); // by construction, points are on surface
c3t3.set_index(v, index);
/// [insert initial points]
}
// else
// {
// std::cerr <<
// boost::format("Error. Segment (%1%, %2%) does not intersect the surface!\n")
// % it->first % test;
// }
}
}
std::cout << " " << tr.number_of_vertices() << " initial points." << std::endl;
if ( c3t3.triangulation().dimension() != 3 )
{
std::cout << " not enough points: triangulation.dimension() == "
<< c3t3.triangulation().dimension() << std::endl;
CGAL::internal::Mesh_3::init_c3t3(c3t3, domain, criteria, 20);
std::cout << " -> " << tr.number_of_vertices() << " initial points." << std::endl;
}
}
#endif // CGAL_MESH_3_INITIALIZE_TRIANGULATION_FROM_LABELED_IMAGE_H

View File

@ -0,0 +1,249 @@
// Copyright (c) 2015,2016 GeometryFactory
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
//
// Author(s) : Laurent Rineau
#ifndef CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_H
#define CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_H
#include <CGAL/Image_3.h>
#include <cstdlib>
#include <vector>
#include <queue>
#include <utility>
#include <algorithm>
#include <boost/container/deque.hpp>
#include <boost/multi_array.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <boost/cstdint.hpp>
#ifdef CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_VERBOSE
# include <iostream>
# include <boost/format.hpp>
#endif // CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_VERBOSE
template <typename PointsOutputIterator,
typename DomainsOutputIterator,
typename TransformOperator,
typename Construct_point,
typename Image_word_type>
void
search_for_connected_components_in_labeled_image(const CGAL::Image_3& image,
PointsOutputIterator it,
DomainsOutputIterator dom_it,
TransformOperator transform,
Construct_point point,
Image_word_type)
{
const std::size_t nx = image.xdim();
const std::size_t ny = image.ydim();
const std::size_t nz = image.zdim();
const std::size_t size = nx * ny * nz;
typedef boost::uint16_t uint;
if(nx > 65535 || ny > 65535 || nz > 65535)
{
CGAL_error_msg("The dimensions of the image must be lower than 2^16");
}
typedef typename TransformOperator::result_type Label;
std::vector<bool> visited(size, false);
std::vector<bool> second_pass(size, false);
typedef boost::tuple<uint, uint, uint, uint> Indices;
typedef std::queue<Indices, boost::container::deque<Indices> > Indices_queue;
typedef std::vector<Indices> Border_vector;
#ifdef CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_VERBOSE
int number_of_connected_components = 0;
#endif // CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_VERBOSE
std::size_t voxel_index = 0;
for(uint k=0; k<nz; k++)
for(uint j=0; j<ny; j++)
for(uint i=0; i<nx; i++)
{
using CGAL::IMAGEIO::static_evaluate;
if(visited[voxel_index] | second_pass[voxel_index]) {
++voxel_index;
continue;
}
const Label current_label =
transform(static_evaluate<Image_word_type>(image.image(),
voxel_index));
*dom_it++ = current_label;
if(current_label == Label()) {
visited[voxel_index] = true;
second_pass[voxel_index] = true;
++voxel_index;
continue;
}
#ifdef CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_VERBOSE
// if we reach here, (i, j, k) is a new connected component
++number_of_connected_components;
std::cerr << boost::format("Found new connected component (#%5%) "
"at voxel (%1%, %2%, %3%), value=%4%, volume id=%6%\n")
% i % j % k
% (long)static_evaluate<Image_word_type>(image.image(), i, j, k)
% number_of_connected_components
% (int)current_label;
#endif // CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_VERBOSE
int nb_voxels = 0;
Indices_queue queue;
Indices indices(i, j ,k, 0);
queue.push(indices);
Border_vector border;
/*
* First pass is a BFS to retrieve all the connected component, and
* its border.
* Second pass is a BFS initialized with all voxel of the border.
* The last voxel of that BFS is used as the seed.
*/
int pass = 1; // pass will be equal to 2 in second pass
Indices bbox_min = indices;
Indices bbox_max = indices;
while(!queue.empty()) // walk through the connected component
{
Indices indices = queue.front();
queue.pop();
// warning: those indices i, j and k are local to the while loop
const uint i = boost::get<0>(indices);
const uint j = boost::get<1>(indices);
const uint k = boost::get<2>(indices);
const uint depth = boost::get<3>(indices);
const size_t offset = i + nx * (j + ny * k);
const int m = (visited[offset] ? 1 : 0) + (second_pass[offset] ? 2 : 0);
if(m < pass)
{
if(pass == 1 )
{
visited[offset] = true;
second_pass[offset] = false;
++nb_voxels;
boost::get<0>(bbox_min) = (std::min)(i, boost::get<0>(bbox_min));
boost::get<0>(bbox_max) = (std::max)(i, boost::get<0>(bbox_max));
boost::get<1>(bbox_min) = (std::min)(j, boost::get<1>(bbox_min));
boost::get<1>(bbox_max) = (std::max)(j, boost::get<1>(bbox_max));
boost::get<2>(bbox_min) = (std::min)(k, boost::get<2>(bbox_min));
boost::get<2>(bbox_max) = (std::max)(k, boost::get<2>(bbox_max));
} else
{
CGAL_assertion(pass == 2);
visited[offset] = false;
second_pass[offset] = true;
}
static const int neighbors_offset[6][3] = { { +1, 0, 0 },
{ -1, 0, 0 },
{ 0, +1, 0 },
{ 0, -1, 0 },
{ 0, 0, +1 },
{ 0, 0, -1 } };
bool voxel_is_on_border = false;
// Visit neighbors.
// (i_n, j_n, k_n) are indices of neighbors.
for(int n = 0; n < 6; ++n)
{
const ptrdiff_t i_n = i + neighbors_offset[n][0];
const ptrdiff_t j_n = j + neighbors_offset[n][1];
const ptrdiff_t k_n = k + neighbors_offset[n][2];
if(i_n < 0 || i_n >= static_cast<ptrdiff_t>(nx) ||
j_n < 0 || j_n >= static_cast<ptrdiff_t>(ny) ||
k_n < 0 || k_n >= static_cast<ptrdiff_t>(nz))
{
voxel_is_on_border = true;
continue;
}
else
{
const std::size_t offset_n = i_n + nx * (j_n + k_n * ny);
if(transform(static_evaluate<Image_word_type>(image.image(),
offset_n))
== current_label)
{
const int m_n = (visited[offset_n] ? 1 : 0) +
(second_pass[offset_n] ? 2 : 0);
if(m_n < pass) {
Indices indices(uint(i_n), uint(j_n), uint(k_n), uint(depth+1));
queue.push(indices);
}
}
else
voxel_is_on_border = true;
}
} // end for neighbors
if(pass == 1 && voxel_is_on_border)
border.push_back(indices);
} // end if voxel not already visited
if(queue.empty()) {
if(pass == 1)
{ // End of first pass. Begin second pass with the voxels of
// the border.
for(typename Border_vector::const_iterator
border_it = border.begin(), border_end = border.end();
border_it != border_end; ++border_it)
queue.push(*border_it);
pass = 2;
}
else // end of second pass, return the last visited voxel
{
// if(nb_voxels >= 100)
{
*it++ = std::make_pair(point(i, j, k),
depth+1);
#if CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_VERBOSE > 1
std::cerr << boost::format("Found seed %5%, which is voxel "
"(%1%, %2%, %3%), value=%4%\n")
% i % j % k
% (long)static_evaluate<Image_word_type>(image.image(), i, j, k)
% point(i, j, k);
#endif // CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_VERBOSE>1
}
}
} // end if queue.empty()
} // end while !queue.empty() (with local indices i, j, k)
#ifdef CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_VERBOSE
std::cerr
<< boost::format("There was %1% voxel(s) in that component.\n"
"The bounding box is (%2% %3% %4%, %5% %6% %7%).\n"
"%8% voxel(s) on border\n")
% nb_voxels
% boost::get<0>(bbox_min) % boost::get<1>(bbox_min)
% boost::get<2>(bbox_min)
% boost::get<0>(bbox_max) % boost::get<1>(bbox_max)
% boost::get<2>(bbox_max)
% border.size();
#endif // CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_VERBOSE
++voxel_index;
} // end for i,j,k
} // end function search_for_connected_components_in_labeled_image()
#endif // CGAL_MESH_3_SEARCH_FOR_CONNECTED_COMPONENTS_IN_LABELED_IMAGE_H

View File

@ -0,0 +1,84 @@
// Copyright (c) 2016 GeometryFactory
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
//
// Author(s) : Laurent Rineau
#ifndef CGAL_INTERNAL_MESH_3_INTERNAL_HANDLE_IO_FOR_PAIR_OF_INT_H
#define CGAL_INTERNAL_MESH_3_INTERNAL_HANDLE_IO_FOR_PAIR_OF_INT_H
#include <utility>
#include <CGAL/Mesh_3/io_signature.h>
#include <ostream>
#include <istream>
namespace CGAL {
template <>
struct Get_io_signature<std::pair<int, int> > {
std::string operator()() const
{
return std::string("std::pair<i,i>");
}
}; // end Get_io_signature<std::pair<int, int> >
inline std::ostream& operator<<(std::ostream& out, const std::pair<int, int>& id) {
return out << id.first << " " << id.second;
}
inline std::istream& operator>>(std::istream& in, std::pair<int, int>& id) {
return in >> id.first >> id.second;
}
template <>
class Output_rep<std::pair<int, int> > : public IO_rep_is_specialized {
typedef std::pair<int, int> T;
const T& t;
public:
//! initialize with a const reference to \a t.
Output_rep( const T& tt) : t(tt) {}
//! perform the output, calls \c operator\<\< by default.
std::ostream& operator()( std::ostream& out) const {
if(is_ascii(out)) {
out << t.first << " " << t.second;
} else {
CGAL::write(out, t.first);
CGAL::write(out, t.second);
}
return out;
}
};
template <>
class Input_rep<std::pair<int, int> > : public IO_rep_is_specialized {
typedef std::pair<int, int> T;
T& t;
public:
//! initialize with a const reference to \a t.
Input_rep( T& tt) : t(tt) {}
//! perform the output, calls \c operator\<\< by default.
std::istream& operator()( std::istream& in) const {
if(is_ascii(in)) {
in >> t.first >> t.second;
} else {
CGAL::read(in, t.first);
CGAL::read(in, t.second);
}
return in;
}
};
} // end namespace CGAL
#endif // CGAL_INTERNAL_MESH_3_INTERNAL_HANDLE_IO_FOR_PAIR_OF_INT_H

View File

@ -29,6 +29,7 @@
#include <boost/type_traits/is_same.hpp>
#include <CGAL/Mesh_3/Has_features.h>
#include <CGAL/IO/io.h>
namespace CGAL {
namespace internal {
@ -87,13 +88,13 @@ struct Write_mesh_domain_index {
switch(dimension) {
case 0: {
const Ci& ci = get_index<Ci>(index);
if(is_ascii(os)) os << ci;
if(is_ascii(os)) os << oformat(ci);
else CGAL::write(os, ci);
}
break;
case 1: {
const Si& si = get_index<Si>(index);
if(is_ascii(os)) os << si;
if(is_ascii(os)) os << oformat(si);
else CGAL::write(os, si);
}
break;
@ -122,7 +123,7 @@ struct Read_mesh_domain_index<Mesh_domain, false> {
break;
default: {// 3
typename MT::Subdomain_index di;
if(is_ascii(is)) is >> di;
if(is_ascii(is)) is >> iformat(di);
else CGAL::read(is, di);
return di;
}
@ -146,13 +147,13 @@ struct Write_mesh_domain_index<Mesh_domain, false> {
switch(dimension) {
case 2: {
const Spi& spi = get_index<Spi>(index);
if(is_ascii(os)) os << spi;
if(is_ascii(os)) os << oformat(spi);
else CGAL::write(os, spi);
}
break;
default: {// 3
const Di& di = get_index<Di>(index);
if(is_ascii(os)) os << di;
if(is_ascii(os)) os << oformat(di);
else CGAL::write(os, di);
}
break;

View File

@ -257,7 +257,15 @@ struct C3t3_initializer < C3T3, MD, MC, true, CGAL::Tag_true >
bool with_features,
const int nb_initial_points = -1)
{
if ( with_features ) { init_c3t3_with_features(c3t3,domain,criteria); }
if ( with_features ) {
init_c3t3_with_features(c3t3,domain,criteria);
// If c3t3 initialization is not sufficient (may happen if there is only
// a planar curve as feature for example), add some surface points
if ( c3t3.triangulation().dimension() != 3 ) {
init_c3t3(c3t3, domain, criteria, nb_initial_points);
}
}
else { init_c3t3(c3t3,domain,criteria,nb_initial_points); }
}
};
@ -430,13 +438,6 @@ void make_mesh_3_impl(C3T3& c3t3,
with_features,
mesh_options.number_of_initial_points);
// If c3t3 initialization is not sufficient (may happen if there is only
// a planar curve as feature for example), add some surface points
if ( c3t3.triangulation().dimension() != 3 )
{
internal::Mesh_3::init_c3t3(c3t3, domain, criteria,
mesh_options.number_of_initial_points);
}
CGAL_assertion( c3t3.triangulation().dimension() == 3 );
// Build mesher and launch refinement process

View File

@ -46,8 +46,6 @@ public:
typedef typename Mesh_criteria::Facet_criteria Facet_criteria;
typedef typename Mesh_criteria::Cell_criteria Cell_criteria;
CGAL_USE_TYPE(typename Mesh_domain::Surface_patch_index);
//-------------------------------------------------------
// Data generation
//-------------------------------------------------------
@ -71,6 +69,10 @@ public:
// Verify
this->verify_c3t3_volume(c3t3, 1772330*0.95, 1772330*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);
}
};

View File

@ -155,7 +155,7 @@ public:
};
template <class F>
class Output_rep< ::CORE::BigRat, F> {
class Output_rep< ::CORE::BigRat, F> : public IO_rep_is_specialized {
const ::CORE::BigRat& t;
public:
//! initialize with a const reference to \a t.
@ -192,7 +192,9 @@ struct Needs_parens_as_product< ::CORE::BigRat >{
};
template <>
class Output_rep< ::CORE::BigRat, Parens_as_product_tag > {
class Output_rep< ::CORE::BigRat, Parens_as_product_tag >
: public IO_rep_is_specialized
{
const ::CORE::BigRat& t;
public:
// Constructor

View File

@ -209,7 +209,7 @@ public:
};
template <class F>
class Output_rep< leda_rational, F> {
class Output_rep< leda_rational, F> : public IO_rep_is_specialized {
const leda_rational& t;
public:
//! initialize with a const reference to \a t.
@ -246,7 +246,9 @@ struct Needs_parens_as_product< leda_rational >{
};
template <>
class Output_rep< leda_rational, Parens_as_product_tag > {
class Output_rep< leda_rational, Parens_as_product_tag >
: public IO_rep_is_specialized
{
const leda_rational& t;
public:
// Constructor

View File

@ -212,7 +212,7 @@ template <> class Real_embeddable_traits< leda_real >
template <>
class Output_rep< ::leda::real > {
class Output_rep< ::leda::real > : public IO_rep_is_specialized {
const ::leda::real& t;
public:
//! initialize with a const reference to \a t.
@ -226,7 +226,9 @@ public:
};
template <>
class Output_rep< ::leda::real, CGAL::Parens_as_product_tag > {
class Output_rep< ::leda::real, CGAL::Parens_as_product_tag >
: public IO_rep_is_specialized
{
const ::leda::real& t;
public:
//! initialize with a const reference to \a t.

View File

@ -107,6 +107,7 @@ int main()
// CORE
#ifdef CGAL_USE_CORE
CGAL_static_assertion(CGAL::Output_rep<CORE::BigRat>::is_specialized == true);
//bug in io for CORE.
test_it<CORE::BigInt>("CORE::BigInt");
test_it<CORE::BigRat>("CORE::BigRat");
@ -116,6 +117,7 @@ int main()
// LEDA based NTs
#ifdef CGAL_USE_LEDA
CGAL_static_assertion(CGAL::Output_rep<leda_rational>::is_specialized == true);
test_it<leda_integer>("leda_integer");
test_it<leda_rational>("leda_rational");
test_it<leda_bigfloat>("leda_bigfloat");

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>448</width>
<height>282</height>
<width>493</width>
<height>241</height>
</rect>
</property>
<property name="sizePolicy">
@ -17,7 +17,7 @@
</sizepolicy>
</property>
<property name="windowTitle">
<string>Image Drawing Precision</string>
<string>Load a 3D image</string>
</property>
<layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0,0,0,0,0,0,0,0,0">
<item row="12" column="0" colspan="2">
@ -36,14 +36,17 @@
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Please choose the image type</string>
<string>Please choose the image &amp;type</string>
</property>
<property name="buddy">
<cstring>imageType</cstring>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>GroupBox</string>
<string>Drawing settings for a segment image</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
@ -77,11 +80,14 @@
<number>1</number>
</property>
<property name="text">
<string>Please choose the image drawing precision</string>
<string>Please choose the image drawing &amp;precision</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="buddy">
<cstring>precisionList</cstring>
</property>
</widget>
</item>
</layout>
@ -97,7 +103,7 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>0</height>
</size>
</property>
</spacer>

View File

@ -188,7 +188,7 @@ void Mesh_3_plugin::mesh_3(const bool surface_only)
else if (NULL != image_item)
{
item = image_item;
features_protection_available = (polylines_item != NULL);
features_protection_available = (polylines_item != NULL) || !image_item->isGray();
bool fit_wrdtp = true;
std::size_t img_wdim = image_item->image()->image()->wdim;
@ -298,6 +298,7 @@ void Mesh_3_plugin::mesh_3(const bool surface_only)
ui.protect->setEnabled(features_protection_available);
ui.protect->setChecked(features_protection_available);
ui.initializationGroup->setVisible(image_item != NULL && !image_item->isGray());
ui.grayImgGroup->setVisible(image_item != NULL && image_item->isGray());
if (poly_item != NULL)
ui.volumeGroup->setVisible(!surface_only && poly_item->polyhedron()->is_closed());
@ -321,6 +322,7 @@ void Mesh_3_plugin::mesh_3(const bool surface_only)
const double tet_sizing = !ui.noTetSizing->isChecked() ? 0 : ui.tetSizing->value();
const double edge_size = !ui.noEdgeSizing->isChecked() ? DBL_MAX : ui.edgeSizing->value();
const bool protect_features = ui.protect->isChecked();
const bool detect_connected_components = ui.detectComponents->isChecked();
const int manifold = ui.manifoldCheckBox->isChecked() ? 1 : 0;
const float iso_value = ui.iso_value_spinBox->value();
const float value_outside = ui.value_outside_spinBox->value();
@ -402,6 +404,7 @@ void Mesh_3_plugin::mesh_3(const bool surface_only)
protect_features,
manifold,
scene,
detect_connected_components,
image_item->isGray(),
iso_value,
value_outside,

View File

@ -81,7 +81,8 @@ Meshing_thread* cgal_code_mesh_3(const Polyhedron* pMesh,
param.manifold = manifold;
param.protect_features = protect_features;
typedef ::Mesh_function<Polyhedral_mesh_domain> Mesh_function;
typedef ::Mesh_function<Polyhedral_mesh_domain,
CGAL::Tag_false> Mesh_function;
Mesh_function* p_mesh_function = new Mesh_function(p_new_item->c3t3(),
p_domain, param);
return new Meshing_thread(p_mesh_function, p_new_item);
@ -124,7 +125,8 @@ Meshing_thread* cgal_code_mesh_3(const Implicit_function_interface* pfunction,
param.edge_sizing = edge_size;
param.manifold = manifold;
typedef ::Mesh_function<Function_mesh_domain> Mesh_function;
typedef ::Mesh_function<Function_mesh_domain,
CGAL::Tag_false> Mesh_function;
Mesh_function* p_mesh_function = new Mesh_function(p_new_item->c3t3(),
p_domain, param);
return new Meshing_thread(p_mesh_function, p_new_item);
@ -150,6 +152,7 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
bool protect_features,
const int manifold,
CGAL::Three::Scene_interface* scene,
bool detect_connected_components,
bool is_gray,
float iso_value,
float value_outside,
@ -161,6 +164,7 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
Mesh_parameters param;
param.protect_features = protect_features;
param.detect_connected_components = detect_connected_components;
param.facet_angle = facet_angle;
param.facet_sizing = facet_sizing;
param.facet_approx = facet_approx;
@ -168,6 +172,7 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
param.edge_sizing = edge_size;
param.tet_shape = tet_shape;
param.manifold = manifold;
param.image_3_ptr = pImage;
CGAL::Timer timer;
Scene_c3t3_item* p_new_item = new Scene_c3t3_item;
p_new_item->setScene(scene);
@ -187,7 +192,8 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
p_domain->add_features(polylines.begin(), polylines.end());
}
timer.start();
typedef ::Mesh_function<Image_mesh_domain> Mesh_function;
typedef ::Mesh_function<Image_mesh_domain,
CGAL::Tag_true> Mesh_function;
Mesh_function* p_mesh_function = new Mesh_function(p_new_item->c3t3(),
p_domain, param);
return new Meshing_thread(p_mesh_function, p_new_item);
@ -214,7 +220,8 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
p_domain->add_features(polylines.begin(), polylines.end());
}
timer.start();
typedef ::Mesh_function<Gray_Image_mesh_domain> Mesh_function;
typedef ::Mesh_function<Gray_Image_mesh_domain,
CGAL::Tag_false> Mesh_function;
Mesh_function* p_mesh_function = new Mesh_function(p_new_item->c3t3(),
p_domain, param);
return new Meshing_thread(p_mesh_function, p_new_item);

View File

@ -56,6 +56,7 @@ Meshing_thread* cgal_code_mesh_3(const CGAL::Image_3* pImage,
bool protect_features,
const int manifold,
CGAL::Three::Scene_interface* scene,
bool detect_connected_components,
bool is_gray = false,
float iso_value = 3.f,
float value_outside = 0.f,

View File

@ -35,12 +35,17 @@
#include <CGAL/Mesh_3/Mesher_3.h>
#include <CGAL/Mesh_criteria_3.h>
#include <CGAL/Mesh_3/Protect_edges_sizing_field.h>
#include <CGAL/Mesh_3/initialize_triangulation_from_labeled_image.h>
#include "C3t3_type.h"
#include "Meshing_thread.h"
#include <CGAL/make_mesh_3.h> // for C3t3_initializer
#include <CGAL/use.h>
namespace CGAL {
class Image_3;
}
struct Mesh_parameters
{
double facet_angle;
@ -51,13 +56,15 @@ struct Mesh_parameters
double tet_sizing;
double edge_sizing;
bool protect_features;
bool detect_connected_components;
int manifold;
const CGAL::Image_3* image_3_ptr;
inline QStringList log() const;
};
template < typename Domain_ >
template < typename Domain_, typename Image_tag >
class Mesh_function
: public Mesh_function_interface
{
@ -93,6 +100,9 @@ private:
typedef CGAL::Mesh_3::Mesher_3<C3t3, Mesh_criteria, Domain> Mesher;
void initialize(const Mesh_criteria& criteria, CGAL::Tag_true);
void initialize(const Mesh_criteria& criteria, CGAL::Tag_false);
private:
C3t3& c3t3_;
Domain* domain_;
@ -121,6 +131,8 @@ log() const
<< QString("facet approx error: %1").arg(facet_approx)
<< QString("tet shape (radius-edge): %1").arg(tet_shape)
<< QString("tet max size: %1").arg(tet_sizing)
<< QString("detect connected components: %1")
.arg(detect_connected_components)
<< QString("protect features: %1").arg(protect_features);
}
@ -128,8 +140,8 @@ log() const
// -----------------------------------
// Class Mesh_function
// -----------------------------------
template < typename D_ >
Mesh_function<D_>::
template < typename D_, typename Tag >
Mesh_function<D_,Tag>::
Mesh_function(C3t3& c3t3, Domain* domain, const Mesh_parameters& p)
: c3t3_(c3t3)
, domain_(domain)
@ -146,8 +158,8 @@ Mesh_function(C3t3& c3t3, Domain* domain, const Mesh_parameters& p)
}
template < typename D_ >
Mesh_function<D_>::
template < typename D_, typename Tag >
Mesh_function<D_,Tag>::
~Mesh_function()
{
delete domain_;
@ -162,9 +174,47 @@ CGAL::Mesh_facet_topology topology(int manifold) {
CGAL::FACET_VERTICES_ON_SAME_SURFACE_PATCH);
}
template < typename D_ >
template < typename D_, typename Tag >
void
Mesh_function<D_>::
Mesh_function<D_,Tag>::
initialize(const Mesh_criteria& criteria, CGAL::Tag_true) // for an image
{
if(p_.detect_connected_components) {
initialize_triangulation_from_labeled_image(c3t3_
, *domain_
, *p_.image_3_ptr
, criteria
, typename D_::Image_word_type()
, p_.protect_features);
} else {
initialize(criteria, CGAL::Tag_false());
}
}
template < typename D_, typename Tag >
void
Mesh_function<D_,Tag>::
initialize(const Mesh_criteria& criteria, CGAL::Tag_false) // for the other domain types
{
// Initialization of the mesh, either with the protection of sharp
// features, or with the initial points (or both).
// If `detect_connected_components==true`, the initialization is
// already done.
CGAL::internal::Mesh_3::C3t3_initializer<
C3t3,
Domain,
Mesh_criteria,
CGAL::internal::Mesh_3::has_Has_features<Domain>::value >()
(c3t3_,
*domain_,
criteria,
p_.protect_features);
}
template < typename D_, typename Tag >
void
Mesh_function<D_,Tag>::
launch()
{
#ifdef CGAL_MESH_3_INITIAL_POINTS_NO_RANDOM_SHOOTING
@ -180,17 +230,7 @@ launch()
Cell_criteria(p_.tet_shape,
p_.tet_sizing));
// Initialization of the mesh, either with the protection of sharp
// features, or with the initial points (or both).
CGAL::internal::Mesh_3::C3t3_initializer<
C3t3,
Domain,
Mesh_criteria,
CGAL::internal::Mesh_3::has_Has_features<Domain>::value >()
(c3t3_,
*domain_,
criteria,
p_.protect_features);
initialize(criteria, CGAL::Boolean_tag<Tag::value>());
// Build mesher and launch refinement process
mesher_ = new Mesher(c3t3_, *domain_, criteria);
@ -219,27 +259,27 @@ launch()
}
template < typename D_ >
template < typename D_, typename Tag >
void
Mesh_function<D_>::
Mesh_function<D_,Tag>::
stop()
{
continue_ = false;
}
template < typename D_ >
template < typename D_, typename Tag >
QStringList
Mesh_function<D_>::
Mesh_function<D_,Tag>::
parameters_log() const
{
return p_.log();
}
template < typename D_ >
template < typename D_, typename Tag >
QString
Mesh_function<D_>::
Mesh_function<D_,Tag>::
status(double time_period) const
{
QString result;

View File

@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>473</width>
<height>637</height>
<height>662</height>
</rect>
</property>
<property name="sizePolicy">
@ -47,6 +47,38 @@
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="initializationGroup">
<property name="title">
<string>Mesh initialization</string>
</property>
<layout class="QGridLayout" name="gridLayout_5" columnstretch="2,0,0">
<item row="1" column="2">
<widget class="QCheckBox" name="detectComponents">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="detectComponentsLabel">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>&amp;Detect all connected components</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>detectComponents</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="sharpFeaturesGroup">
<property name="layoutDirection">
@ -88,9 +120,6 @@
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="protect">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string/>
</property>
@ -102,7 +131,10 @@
<item row="0" column="1">
<widget class="QLabel" name="protectLabel">
<property name="text">
<string>Protect sharp edges</string>
<string>&amp;Protect sharp edges</string>
</property>
<property name="buddy">
<cstring>protect</cstring>
</property>
</widget>
</item>
@ -507,8 +539,8 @@
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>397</x>
<y>544</y>
<x>403</x>
<y>655</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
@ -523,8 +555,8 @@
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>397</x>
<y>544</y>
<x>403</x>
<y>655</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
@ -539,12 +571,12 @@
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>69</x>
<y>283</y>
<x>83</x>
<y>339</y>
</hint>
<hint type="destinationlabel">
<x>72</x>
<y>297</y>
<x>78</x>
<y>199</y>
</hint>
</hints>
</connection>

View File

@ -148,14 +148,21 @@ Specializations of `Output_rep` should provide the following features:
template< class F >
struct Output_rep< Some_type, F > {
Output_rep( const Some_type& t );
std::ostream& operator()( std::ostream& out ) const;
static const bool is_specialized = true;
Output_rep( const Some_type& t );
std::ostream& operator()( std::ostream& out ) const;
};
\endcode
You can also specialize for a formatting tag `F`.
The constant `is_specialized` can be tested by meta-programming tools to
verify that a given type can be used with `oformat()`. Its value has to be
`true` in a specialization of `Output_rep`. When there is no specialization
for a type, the class template `Output_rep` defines `is_specialized` to the
default value `false`.
*/
template< typename T, typename F >
class Output_rep {

View File

@ -56,8 +56,27 @@ public:
enum Mode {ASCII = 0, PRETTY, BINARY};
};
template <typename Dummy>
struct IO_rep_is_specialized_aux
{
static const bool is_specialized = true;
};
template< class Dummy >
const bool IO_rep_is_specialized_aux<Dummy>::is_specialized;
template <typename Dummy>
struct IO_rep_is_not_specialized_aux
{
static const bool is_specialized = false;
};
template< class Dummy >
const bool IO_rep_is_not_specialized_aux<Dummy>::is_specialized;
typedef IO_rep_is_specialized_aux<void> IO_rep_is_specialized;
typedef IO_rep_is_not_specialized_aux<void> IO_rep_is_not_specialized;
template <class T, class F = ::CGAL::Null_tag >
class Output_rep {
class Output_rep : public IO_rep_is_not_specialized {
const T& t;
public:
//! initialize with a const reference to \a t.
@ -95,7 +114,7 @@ oformat( const T& t, F) { return Output_rep<T,F>(t); }
* for external types not supporting our stream IO format.
*/
template <class T>
class Input_rep {
class Input_rep : public IO_rep_is_not_specialized {
T& t;
public:
//! initialize with a reference to \a t.
@ -107,7 +126,7 @@ public:
#if CGAL_FORCE_IFORMAT_DOUBLE || \
( ( _MSC_VER > 1600 ) && (! defined( CGAL_NO_IFORMAT_DOUBLE )) )
template <>
class Input_rep<double> {
class Input_rep<double> : public IO_rep_is_specialized {
double& t;
public:
//! initialize with a reference to \a t.

View File

@ -59,6 +59,8 @@ void test_io(const NT& x){
}
int main() {
CGAL_static_assertion(CGAL::Output_rep<int>::is_specialized == false);
CGAL_static_assertion(CGAL::Input_rep<int>::is_specialized == false);
std::cout << "test_io: short "<< std::endl;
test_io<short>(12);