Skip to content

Commit 18fc6a8

Browse files
author
Arttu Miettinen
committed
Fixes (cgalmesh part of) issue fangq#7 by replacing mesh initialization in cgalmesh with the custom initialization by Laurent Irineau.
1 parent c394673 commit 18fc6a8

File tree

3 files changed

+339
-124
lines changed

3 files changed

+339
-124
lines changed

cgalv2m.m

+5-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
% author: Qianqian Fang (q.fang at neu.edu)
1111
%
1212
% input:
13-
% vol: a volumetric binary image
13+
% vol: a volumetric binary or labeled image
1414
% ix,iy,iz: subvolume selection indices in x,y,z directions
1515
% opt: parameters for CGAL mesher, if opt is a structure, then
1616
% opt.radbound: defines the maximum surface element size
@@ -37,10 +37,10 @@
3737

3838
fprintf(1,'creating surface and tetrahedral mesh from a multi-domain volume ...\n');
3939

40-
dtype=class(vol);
41-
if(~(islogical(vol) || strcmp(dtype,'uint8')))
42-
error('cgalmesher can only handle uint8 volumes, you have to convert your image to unit8 first.');
43-
end
40+
%dtype=class(vol);
41+
%if(~(islogical(vol) || strcmp(dtype,'uint8')))
42+
% error('cgalmesher can only handle uint8 volumes, you have to convert your image to unit8 first.');
43+
%end
4444

4545
if(~any(vol))
4646
error('no labeled regions found in the input volume.');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
// Copyright (c) 2015,2016 GeometryFactory
2+
// All rights reserved.
3+
//
4+
// This file is part of CGAL (www.cgal.org).
5+
//
6+
// $URL: https://github.com/CGAL/cgal/blob/releases/CGAL-5.0-I-190/Mesh_3/include/CGAL/Mesh_3/initialize_triangulation_from_labeled_image.h $
7+
// $Id: initialize_triangulation_from_labeled_image.h 254d60f 2019-10-19T15:23:19+02:00 Sébastien Loriot
8+
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
9+
//
10+
//
11+
// Author(s) : Laurent Rineau
12+
#ifndef CGAL_MESH_3_INITIALIZE_TRIANGULATION_FROM_LABELED_IMAGE_H
13+
#define CGAL_MESH_3_INITIALIZE_TRIANGULATION_FROM_LABELED_IMAGE_H
14+
#include <CGAL/license/Mesh_3.h>
15+
#include <CGAL/Mesh_3/search_for_connected_components_in_labeled_image.h>
16+
#include <CGAL/Mesh_3/squared_distance_Point_3_Triangle_3.h>
17+
#include <CGAL/make_mesh_3.h>
18+
#include <CGAL/enum.h>
19+
#include <CGAL/iterator.h>
20+
#include <CGAL/point_generators_3.h>
21+
#include <CGAL/Image_3.h>
22+
#include <iostream>
23+
#include <queue>
24+
template <typename Point>
25+
struct Get_point
26+
{
27+
const double vx, vy, vz;
28+
Get_point(const CGAL::Image_3* image)
29+
: vx(image->vx())
30+
, vy(image->vy())
31+
, vz(image->vz())
32+
{}
33+
Point operator()(const std::size_t i,
34+
const std::size_t j,
35+
const std::size_t k) const
36+
{
37+
return Point(double(i) * vx, double(j) * vy, double(k) * vz);
38+
}
39+
};
40+
template<class C3T3, class MeshDomain, class MeshCriteria>
41+
void init_tr_from_labeled_image_call_init_features(C3T3&,
42+
const MeshDomain&,
43+
const MeshCriteria&,
44+
CGAL::Tag_false)
45+
{
46+
}
47+
template<class C3T3, class MeshDomain, class MeshCriteria>
48+
void init_tr_from_labeled_image_call_init_features(C3T3& c3t3,
49+
const MeshDomain& domain,
50+
const MeshCriteria& criteria,
51+
CGAL::Tag_true)
52+
{
53+
CGAL::Mesh_3::internal::init_c3t3_with_features(c3t3,
54+
domain,
55+
criteria);
56+
std::cout << c3t3.triangulation().number_of_vertices()
57+
<< " initial points on 1D-features" << std::endl;
58+
}
59+
template<class C3T3, class MeshDomain, class MeshCriteria,
60+
typename Image_word_type>
61+
void initialize_triangulation_from_labeled_image(C3T3& c3t3,
62+
const MeshDomain& domain,
63+
const CGAL::Image_3& image,
64+
const MeshCriteria& criteria,
65+
Image_word_type,
66+
bool protect_features = false
67+
)
68+
{
69+
typedef typename C3T3::Triangulation Tr;
70+
typedef typename Tr::Geom_traits Gt;
71+
typedef typename Gt::FT FT;
72+
typedef typename Tr::Weighted_point Weighted_point;
73+
typedef typename Tr::Bare_point Bare_point;
74+
typedef typename Tr::Segment Segment_3;
75+
typedef typename Tr::Vertex_handle Vertex_handle;
76+
typedef typename Tr::Cell_handle Cell_handle;
77+
typedef typename Gt::Vector_3 Vector_3;
78+
typedef MeshDomain Mesh_domain;
79+
Tr& tr = c3t3.triangulation();
80+
typename Gt::Compare_weighted_squared_radius_3 cwsr =
81+
tr.geom_traits().compare_weighted_squared_radius_3_object();
82+
typename Gt::Construct_point_3 cp =
83+
tr.geom_traits().construct_point_3_object();
84+
typename Gt::Construct_weighted_point_3 cwp =
85+
tr.geom_traits().construct_weighted_point_3_object();
86+
if (protect_features) {
87+
init_tr_from_labeled_image_call_init_features
88+
(c3t3, domain, criteria,
89+
CGAL::Mesh_3::internal::Has_features<Mesh_domain>());
90+
}
91+
const double max_v = (std::max)((std::max)(image.vx(),
92+
image.vy()),
93+
image.vz());
94+
typedef std::vector<std::pair<Bare_point, std::size_t> > Seeds;
95+
Seeds seeds;
96+
Get_point<Bare_point> get_point(&image);
97+
std::cout << "Searching for connected components..." << std::endl;
98+
CGAL::Identity<Image_word_type> no_transformation;
99+
search_for_connected_components_in_labeled_image(image,
100+
std::back_inserter(seeds),
101+
CGAL::Emptyset_iterator(),
102+
no_transformation,
103+
get_point,
104+
Image_word_type());
105+
std::cout << " " << seeds.size() << " components were found." << std::endl;
106+
std::cout << "Construct initial points..." << std::endl;
107+
for (typename Seeds::const_iterator it = seeds.begin(), end = seeds.end();
108+
it != end; ++it)
109+
{
110+
const double radius = double(it->second + 1)* max_v;
111+
CGAL::Random_points_on_sphere_3<Bare_point> points_on_sphere_3(radius);
112+
typename Mesh_domain::Construct_intersection construct_intersection =
113+
domain.construct_intersection_object();
114+
std::vector<Vector_3> directions;
115+
if (it->second < 2) {
116+
// shoot in six directions
117+
directions.push_back(Vector_3(-radius, 0, 0));
118+
directions.push_back(Vector_3(+radius, 0, 0));
119+
directions.push_back(Vector_3(0, -radius, 0));
120+
directions.push_back(Vector_3(0, +radius, 0));
121+
directions.push_back(Vector_3(0, 0, -radius));
122+
directions.push_back(Vector_3(0, 0, +radius));
123+
}
124+
else {
125+
for (int i = 0; i < 20; ++i)
126+
{
127+
// shoot 20 random directions
128+
directions.push_back(*points_on_sphere_3++ - CGAL::ORIGIN);
129+
}
130+
}
131+
for (const Vector_3& v : directions)
132+
{
133+
const Bare_point test = it->first + v;
134+
const typename Mesh_domain::Intersection intersect =
135+
construct_intersection(Segment_3(it->first, test));
136+
if (std::get<2>(intersect) != 0)
137+
{
138+
const Bare_point& bpi = std::get<0>(intersect);
139+
Weighted_point pi = cwp(bpi);
140+
// This would cause trouble to optimizers
141+
// check pi will not be hidden
142+
typename Tr::Locate_type lt;
143+
int li, lj;
144+
Cell_handle pi_cell = tr.locate(pi, lt, li, lj);
145+
if (lt != Tr::OUTSIDE_AFFINE_HULL) {
146+
switch (tr.dimension())
147+
{ //skip dimension 0
148+
case 1:
149+
if (tr.side_of_power_segment(pi_cell, pi, true) != CGAL::ON_BOUNDED_SIDE)
150+
continue;
151+
break;
152+
case 2:
153+
if (tr.side_of_power_circle(pi_cell, 3, pi, true) != CGAL::ON_BOUNDED_SIDE)
154+
continue;
155+
break;
156+
case 3:
157+
if (tr.side_of_power_sphere(pi_cell, pi, true) != CGAL::ON_BOUNDED_SIDE)
158+
continue;
159+
}
160+
}
161+
//check pi is not inside a protecting ball
162+
std::vector<Vertex_handle> conflict_vertices;
163+
if (tr.dimension() == 3)
164+
{
165+
tr.vertices_on_conflict_zone_boundary(pi, pi_cell
166+
, std::back_inserter(conflict_vertices));
167+
}
168+
else
169+
{
170+
for (typename Tr::Finite_vertices_iterator vit = tr.finite_vertices_begin();
171+
vit != tr.finite_vertices_end(); ++vit)
172+
{
173+
const Weighted_point& wp = tr.point(vit);
174+
if (cwsr(wp, FT(0)) == CGAL::SMALLER) // 0 < wp's weight
175+
conflict_vertices.push_back(vit);
176+
}
177+
}
178+
bool pi_inside_protecting_sphere = false;
179+
for (Vertex_handle cv : conflict_vertices)
180+
{
181+
if (tr.is_infinite(cv))
182+
continue;
183+
const Weighted_point& cv_wp = tr.point(cv);
184+
if (cwsr(cv_wp, FT(0)) == CGAL::EQUAL) // 0 == wp's weight
185+
continue;
186+
// if the (squared) distance between bpi and cv is smaller or equal than cv's weight
187+
if (cwsr(cv_wp, -tr.min_squared_distance(bpi, cp(cv_wp))) != CGAL::LARGER)
188+
{
189+
pi_inside_protecting_sphere = true;
190+
break;
191+
}
192+
}
193+
if (pi_inside_protecting_sphere)
194+
continue;
195+
const typename Mesh_domain::Index index = std::get<1>(intersect);
196+
Vertex_handle v = tr.insert(pi);
197+
// `v` could be null if `pi` is hidden by other vertices of `tr`.
198+
CGAL_assertion(v != Vertex_handle());
199+
c3t3.set_dimension(v, 2); // by construction, points are on surface
200+
c3t3.set_index(v, index);
201+
}
202+
// else
203+
// {
204+
// std::cerr <<
205+
// boost::format("Error. Segment (%1%, %2%) does not intersect the surface!\n")
206+
// % it->first % test;
207+
// }
208+
}
209+
}
210+
std::cout << " " << tr.number_of_vertices() << " initial points." << std::endl;
211+
if (c3t3.triangulation().dimension() != 3)
212+
{
213+
std::cout << " not enough points: triangulation.dimension() == "
214+
<< c3t3.triangulation().dimension() << std::endl;
215+
CGAL::Mesh_3::internal::init_c3t3(c3t3, domain, criteria, 20);
216+
std::cout << " -> " << tr.number_of_vertices() << " initial points." << std::endl;
217+
}
218+
}
219+
#endif // CGAL_MESH_3_INITIALIZE_TRIANGULATION_FROM_LABELED_IMAGE_H

0 commit comments

Comments
 (0)