1 #ifndef CGAL_SURFACE_MESH_SEGMENTATION_SDF_CALCULATION_H
2 #define CGAL_SURFACE_MESH_SEGMENTATION_SDF_CALCULATION_H
4 #include <CGAL/AABB_tree.h>
5 #include <CGAL/AABB_traits.h>
6 #include <CGAL/AABB_polyhedron_triangle_primitive.h>
7 #include <CGAL/internal/Surface_mesh_segmentation/AABB_traversal_traits.h>
12 #include <boost/tuple/tuple.hpp>
13 #include <boost/optional.hpp>
15 #define CGAL_ST_DEV_MULTIPLIER 1 //0.75
31 class DiskSampling = Vogel_disk_sampling<boost::tuple<double, double, double> >
38 typedef typename GeomTraits::Vector_3 Vector;
39 typedef typename GeomTraits::Point_3 Point;
40 typedef typename GeomTraits::Ray_3 Ray;
41 typedef typename GeomTraits::Plane_3 Plane;
42 typedef typename GeomTraits::Segment_3 Segment;
44 typedef typename Polyhedron::Traits Kernel;
45 typedef typename Polyhedron::Facet Facet;
46 typedef typename Polyhedron::Facet Vertex;
48 typedef typename Polyhedron::Facet_const_iterator Facet_const_iterator;
49 typedef typename Polyhedron::Facet_const_handle Facet_const_handle;
51 typedef AABB_const_polyhedron_triangle_primitive<GeomTraits, Polyhedron> Primitive;
52 typedef typename CGAL::AABB_tree<AABB_traits<GeomTraits, Primitive> > Tree;
53 typedef typename Tree::Object_and_primitive_id Object_and_primitive_id;
54 typedef typename Tree::Primitive_id Primitive_id;
57 typedef boost::tuple<double, double, double> Disk_sample;
58 typedef std::vector<Disk_sample> Disk_samples_list;
65 Disk_samples_list disk_samples;
67 bool use_minimum_segment;
68 double multiplier_for_segment;
71 typename GeomTraits::Angle_3 angle_functor;
72 typename GeomTraits::Construct_scaled_vector_3 scale_functor;
73 typename GeomTraits::Construct_sum_of_vectors_3 sum_functor;
74 typename GeomTraits::Construct_normal_3 normal_functor;
75 typename GeomTraits::Construct_unit_normal_3 unit_normal_functor;
76 typename GeomTraits::Construct_translated_point_3 translated_point_functor;
77 typename GeomTraits::Construct_centroid_3 centroid_functor;
82 SDF_calculation(GeomTraits traits)
83 : traits(traits), use_minimum_segment(false), multiplier_for_segment(1),
84 angle_functor(traits.angle_3_object()),
85 scale_functor(traits.construct_scaled_vector_3_object()),
86 sum_functor(traits.construct_sum_of_vectors_3_object()),
87 normal_functor(traits.construct_normal_3_object()),
88 unit_normal_functor(traits.construct_unit_normal_3_object()),
89 translated_point_functor(traits.construct_translated_point_3_object()),
90 centroid_functor(traits.construct_centroid_3_object())
100 template <
class FacetValueMap>
101 void calculate_sdf_values(
const Polyhedron& mesh,
double cone_angle,
int number_of_rays, FacetValueMap sdf_values)
103 this->cone_angle = cone_angle;
104 this->number_of_rays = number_of_rays;
106 DiskSampling()(number_of_rays, cone_angle, std::back_inserter(disk_samples));
108 Tree tree(mesh.facets_begin(), mesh.facets_end());
109 for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end(); ++facet_it)
111 sdf_values[facet_it] = calculate_sdf_value_of_facet(facet_it, tree);
123 double calculate_sdf_value_of_facet(Facet_const_handle facet,
const Tree& tree)
const
125 const Point& p1 = facet->halfedge()->vertex()->point();
126 const Point& p2 = facet->halfedge()->next()->vertex()->point();
127 const Point& p3 = facet->halfedge()->prev()->vertex()->point();
128 Point center = centroid_functor(p1, p2, p3);
129 Vector normal = unit_normal_functor(p2, p1, p3);
131 Plane plane(center, normal);
132 Vector v1 = plane.base1(), v2 = plane.base2();
133 v1 = scale_functor(v1, 1.0 / CGAL::sqrt(v1.squared_length()));
134 v2 = scale_functor(v2, 1.0 / CGAL::sqrt(v2.squared_length()));
136 std::vector<std::pair<double, double> > ray_distances;
137 ray_distances.reserve(disk_samples.size());
139 const double length_of_normal = 1.0 / tan(cone_angle / 2.0);
140 normal = scale_functor(normal, length_of_normal);
142 for(Disk_samples_list::const_iterator sample_it = disk_samples.begin();
143 sample_it != disk_samples.end(); ++sample_it)
145 bool is_intersected, intersection_is_acute;
147 Vector disk_vector = sum_functor(scale_functor(v1, sample_it->get<0>()), scale_functor(v2, sample_it->get<1>()));
148 Vector ray_direction = sum_functor(normal, disk_vector);
150 Ray ray(center, ray_direction);
151 boost::tie(is_intersected, intersection_is_acute, min_distance) = cast_and_return_minimum(ray, tree, facet);
152 if(!intersection_is_acute) {
continue; }
154 ray_distances.push_back(std::make_pair(min_distance, sample_it->get<2>()));
156 return remove_outliers_and_calculate_sdf_value(ray_distances);
170 template <
class Query>
171 boost::tuple<bool, bool, double> cast_and_return_minimum(
172 const Query& query,
const Tree& tree, Facet_const_handle facet)
const
174 boost::tuple<bool, bool, double> min_distance(
false,
false, 0.0);
175 std::list<Object_and_primitive_id> intersections;
178 typedef std::back_insert_iterator< std::list<Object_and_primitive_id> > Output_iterator;
179 Listing_intersection_traits_ray_or_segment_triangle<typename Tree::AABB_traits,Query,Output_iterator>
180 traversal_traits(std::back_inserter(intersections));
181 tree.traversal(query,traversal_traits);
185 for(
typename std::list<Object_and_primitive_id>::iterator op_it = intersections.begin();
186 op_it != intersections.end() ; ++op_it)
188 Object
object = op_it->first;
189 Primitive_id
id = op_it->second;
190 if(
id == facet) {
continue; }
192 const Point* i_point;
193 if(!(i_point = object_cast<Point>(&
object))) {
continue; }
195 Vector i_ray(*i_point, query.source());
196 double new_distance = i_ray.squared_length();
197 if(!min_distance.get<0>() || new_distance < min_distance.get<2>())
199 min_distance.get<2>() = new_distance;
200 min_distance.get<0>() =
true;
205 if(!min_distance.get<0>()) {
return min_distance; }
208 const Point& min_v1 = min_id->halfedge()->vertex()->point();
209 const Point& min_v2 = min_id->halfedge()->next()->vertex()->point();
210 const Point& min_v3 = min_id->halfedge()->prev()->vertex()->point();
211 Vector min_normal = scale_functor(normal_functor(min_v1, min_v2, min_v3), -1.0);
213 if(angle_functor(translated_point_functor(Point(ORIGIN), min_i_ray),
215 translated_point_functor(Point(ORIGIN), min_normal)) != ACUTE)
219 min_distance.get<1>() =
true;
220 min_distance.get<2>() = std::sqrt(min_distance.get<2>());
230 double remove_outliers_and_calculate_sdf_value(std::vector<std::pair<double, double> >& ray_distances)
const
234 const int accepted_ray_count = ray_distances.size();
235 if(accepted_ray_count == 0) {
return 0.0; }
236 else if(accepted_ray_count == 1) {
return ray_distances[0].first * ray_distances[0].second; }
239 const int half_ray_count = accepted_ray_count / 2;
240 std::nth_element(ray_distances.begin(), ray_distances.begin() + half_ray_count, ray_distances.end());
241 double median_sdf = ray_distances[half_ray_count].first;
242 if(accepted_ray_count % 2 == 0)
244 median_sdf += std::max_element(ray_distances.begin(), ray_distances.begin() + half_ray_count)->first;
249 std::vector<double> absolute_deviation;
250 absolute_deviation.reserve(accepted_ray_count);
251 for(std::vector<std::pair<double, double> >::iterator it = ray_distances.begin(); it != ray_distances.end(); ++it)
253 absolute_deviation.push_back(std::abs(it->first - median_sdf));
256 std::nth_element(absolute_deviation.begin(), absolute_deviation.begin() + half_ray_count, absolute_deviation.end());
257 double median_deviation = absolute_deviation[half_ray_count];
258 if(accepted_ray_count % 2 == 0)
260 median_deviation += *std::max_element(absolute_deviation.begin(), absolute_deviation.begin() + half_ray_count);
261 median_deviation /= 2.0;
265 double total_weights = 0.0, total_distance = 0.0;
266 for(std::vector<std::pair<double, double> >::iterator it = ray_distances.begin(); it != ray_distances.end(); ++it)
268 if(std::abs(it->first - median_sdf) > (median_deviation * CGAL_ST_DEV_MULTIPLIER)) {
continue; }
269 total_distance += it->first * it->second;
270 total_weights += it->second;
273 if(total_distance == 0.0) {
return median_sdf; }
274 else {
return total_distance / total_weights; }
280 #undef CGAL_ST_DEV_MULTIPLIER
281 #undef CGAL_ACCEPTANCE_RATE_THRESHOLD
283 #endif //CGAL_SURFACE_MESH_SEGMENTATION_SDF_CALCULATION_H