Changes to guarantee there will be no border case problems with cone angle in [0, PI].

This commit is contained in:
iyaz 2013-04-16 18:19:56 +03:00
parent 68197c0352
commit 65fc0a0b6b
2 changed files with 30 additions and 49 deletions

View File

@ -58,32 +58,21 @@ public:
/** /**
* Samples points from unit-disk. * Samples points from unit-disk.
* @param number_of_points number of points to be picked * @param number_of_points number of points to be picked
* @param cone_angle opening angle of cone (might be necessary for weighting)
* @param[out] out_it sampled points from disk, each point is tuple of: * @param[out] out_it sampled points from disk, each point is tuple of:
* - coordinate-x * - coordinate-x
* - coordinate-y * - coordinate-y
* - weight (proportional to angle between cone-normal) * - weight (proportional to distance from disk center)
*/ */
template<class OutputIterator> template<class OutputIterator>
void operator()(int number_of_points, void operator()(int number_of_points,
double cone_angle,
OutputIterator out_it) const { OutputIterator out_it) const {
if(cone_angle <= 0.0) {
CGAL_warning(false
&& "Warning: cone angle smaller than or equal to zero will be assigned to epsilon!");
cone_angle = (std::numeric_limits<double>::epsilon)();
}
const double golden_ratio = 3.0 - std::sqrt(5.0); const double golden_ratio = 3.0 - std::sqrt(5.0);
if(uniform) { if(uniform) {
const double length_of_normal = 1.0 / tan(cone_angle / 2.0);
const double angle_st_dev = cone_angle / CGAL_ANGLE_ST_DEV_DIVIDER;
for(int i = 0; i < number_of_points; ++i) { for(int i = 0; i < number_of_points; ++i) {
double Q = i * golden_ratio * CGAL_PI; double Q = i * golden_ratio * CGAL_PI;
double R = std::sqrt(static_cast<double>(i) / number_of_points); double R = std::sqrt(static_cast<double>(i) / number_of_points);
double angle = atan(R / length_of_normal); double weight = exp(-0.5 * (std::pow(R / CGAL_ANGLE_ST_DEV_DIVIDER, 2)));
double weight = exp(-0.5 * (std::pow(angle / angle_st_dev, 2)));
*out_it++ = Tuple(R * cos(Q), R * sin(Q), weight); *out_it++ = Tuple(R * cos(Q), R * sin(Q), weight);
} }
} else { } else {
@ -137,29 +126,19 @@ public:
/** /**
* Samples points from unit-disk. * Samples points from unit-disk.
* @param number_of_points number of points to be picked * @param number_of_points number of points to be picked
* @param cone_angle opening angle of cone (might be necessary for weighting)
* @param[out] out_it sampled points from disk, each point is tuple of: * @param[out] out_it sampled points from disk, each point is tuple of:
* - coordinate-x * - coordinate-x
* - coordinate-y * - coordinate-y
* - weight (proportional to angle between cone-normal) * - weight (proportional to distance from disk center)
* *
* Note: returned samples size = \f$ \lfloor \sqrt {number\_of\_points} \rfloor ^ 2 \f$ * Note: returned samples size = \f$ \lfloor \sqrt {number\_of\_points} \rfloor ^ 2 \f$
*/ */
template<class OutputIterator> template<class OutputIterator>
void operator()(int number_of_points, void operator()(int number_of_points,
double cone_angle,
OutputIterator out_it) const { OutputIterator out_it) const {
if(cone_angle <= 0.0) {
CGAL_warning(false
&& "Warning: cone angle smaller than or equal to zero will be assigned to epsilon!");
cone_angle = (std::numeric_limits<double>::epsilon)();
}
const int number_of_points_sqrt = static_cast<int>(std::sqrt( const int number_of_points_sqrt = static_cast<int>(std::sqrt(
static_cast<double>(number_of_points))); static_cast<double>(number_of_points)));
const double length_of_normal = 1.0 / tan(cone_angle / 2.0);
// use cone_angle / 3 as one standard deviation while weighting. // use cone_angle / 3 as one standard deviation while weighting.
const double angle_st_dev = cone_angle / CGAL_ANGLE_ST_DEV_DIVIDER;
for(int i = 1; i <= number_of_points_sqrt; ++i) for(int i = 1; i <= number_of_points_sqrt; ++i)
for(int j = 1; j <= number_of_points_sqrt; ++j) { for(int j = 1; j <= number_of_points_sqrt; ++j) {
@ -167,8 +146,8 @@ public:
double w2 = static_cast<double>(j) / number_of_points_sqrt; double w2 = static_cast<double>(j) / number_of_points_sqrt;
double R = w1; double R = w1;
double Q = 2 * w2 * CGAL_PI; double Q = 2 * w2 * CGAL_PI;
double angle = atan(R / length_of_normal);
double weight = exp(-0.5 * (pow(angle / angle_st_dev, 2))); double weight = exp(-0.5 * (pow(R / CGAL_ANGLE_ST_DEV_DIVIDER, 2)));
*out_it++ = Tuple(R * cos(Q), R * sin(Q), weight); *out_it++ = Tuple(R * cos(Q), R * sin(Q), weight);
} }
} }
@ -219,21 +198,11 @@ public:
*/ */
template<class OutputIterator> template<class OutputIterator>
void operator()(int number_of_points, void operator()(int number_of_points,
double cone_angle,
OutputIterator out_it) const { OutputIterator out_it) const {
if(cone_angle <= 0.0) {
CGAL_warning(false
&& "Warning: cone angle smaller than or equal to zero will be assigned to epsilon!");
cone_angle = (std::numeric_limits<double>::epsilon)();
}
const int number_of_points_sqrt = static_cast<int>(std::sqrt( const int number_of_points_sqrt = static_cast<int>(std::sqrt(
static_cast<double>(number_of_points))); static_cast<double>(number_of_points)));
const double length_of_normal = 1.0 / tan(cone_angle / 2.0);
const double fraction = (number_of_points_sqrt == 1) ? 0.0 const double fraction = (number_of_points_sqrt == 1) ? 0.0
: 2.0 / (number_of_points_sqrt -1); : 2.0 / (number_of_points_sqrt -1);
// use cone_angle / 3 as one standard deviation while weighting.
const double angle_st_dev = cone_angle / CGAL_ANGLE_ST_DEV_DIVIDER;
for(int i = 0; i < number_of_points_sqrt; ++i) for(int i = 0; i < number_of_points_sqrt; ++i)
for(int j = 0; j < number_of_points_sqrt; ++j) { for(int j = 0; j < number_of_points_sqrt; ++j) {
@ -261,8 +230,8 @@ public:
} }
} }
Q *= (CGAL_PI / 4.0); Q *= (CGAL_PI / 4.0);
double angle = atan(R / length_of_normal);
double weight = exp(-0.5 * (pow(angle / angle_st_dev, 2))); double weight = exp(-0.5 * (pow(R / CGAL_ANGLE_ST_DEV_DIVIDER, 2)));
*out_it++ = Tuple(R * cos(Q), R * sin(Q), weight); *out_it++ = Tuple(R * cos(Q), R * sin(Q), weight);
} }
} }

View File

@ -60,6 +60,7 @@ private:
typedef typename GeomTraits::Ray_3 Ray; typedef typename GeomTraits::Ray_3 Ray;
typedef typename GeomTraits::Plane_3 Plane; typedef typename GeomTraits::Plane_3 Plane;
typedef typename GeomTraits::Segment_3 Segment; typedef typename GeomTraits::Segment_3 Segment;
typedef typename GeomTraits::FT FT;
typedef typename Polyhedron::Facet Facet; typedef typename Polyhedron::Facet Facet;
@ -80,6 +81,7 @@ private:
typedef Vogel_disk_sampling<boost::tuple<double, double, double> > typedef Vogel_disk_sampling<boost::tuple<double, double, double> >
Default_sampler; Default_sampler;
// member variables // member variables
private: private:
GeomTraits traits; GeomTraits traits;
@ -168,7 +170,7 @@ public:
FacetValueMap sdf_values, FacetValueMap sdf_values,
DiskSampling disk_sampler) const { DiskSampling disk_sampler) const {
Disk_samples_list disk_samples; Disk_samples_list disk_samples;
disk_sampler(number_of_rays, cone_angle, std::back_inserter(disk_samples)); disk_sampler(number_of_rays, std::back_inserter(disk_samples));
for( ; facet_begin != facet_end; ++facet_begin) { for( ; facet_begin != facet_end; ++facet_begin) {
boost::optional<double> sdf_value = calculate_sdf_value_of_facet(facet_begin, boost::optional<double> sdf_value = calculate_sdf_value_of_facet(facet_begin,
@ -232,7 +234,7 @@ public:
bool accept_if_acute, bool accept_if_acute,
DiskSampling disk_sampler) const { DiskSampling disk_sampler) const {
Disk_samples_list disk_samples; Disk_samples_list disk_samples;
disk_sampler(number_of_rays, cone_angle, std::back_inserter(disk_samples)); disk_sampler(number_of_rays, std::back_inserter(disk_samples));
return calculate_sdf_value_of_point(center, normal, skip, visitor, cone_angle, return calculate_sdf_value_of_point(center, normal, skip, visitor, cone_angle,
accept_if_acute, disk_samples); accept_if_acute, disk_samples);
@ -250,19 +252,23 @@ public:
double cone_angle, double cone_angle,
bool accept_if_acute, bool accept_if_acute,
const Disk_samples_list& disk_samples) const { const Disk_samples_list& disk_samples) const {
if(cone_angle < 0.0 || cone_angle > CGAL_PI) {
CGAL_warning(false && "Cone angle is clamped between [0, CGAL_PI].");
cone_angle = (std::min)(CGAL_PI, (std::max)(0.0, cone_angle));
}
Plane plane(center, normal); Plane plane(center, normal);
Vector v1 = plane.base1(), v2 = plane.base2(); Vector v1 = plane.base1(), v2 = plane.base2();
v1 = scale_functor(v1, static_cast<typename GeomTraits::FT>(1.0 / CGAL::sqrt( v1 = scale_functor(v1, static_cast<FT>(1.0 / CGAL::sqrt(v1.squared_length())));
v1.squared_length()))); v2 = scale_functor(v2, static_cast<FT>(1.0 / CGAL::sqrt(v2.squared_length())));
v2 = scale_functor(v2, static_cast<typename GeomTraits::FT>(1.0 / CGAL::sqrt(
v2.squared_length())));
std::vector<std::pair<double, double> > ray_distances; std::vector<std::pair<double, double> > ray_distances;
ray_distances.reserve(disk_samples.size()); ray_distances.reserve(disk_samples.size());
const typename GeomTraits::FT length_of_normal = const FT normal_multiplier( cos(cone_angle / 2.0) );
static_cast<typename GeomTraits::FT>( 1.0 / tan(cone_angle / 2.0) ); const FT disk_multiplier ( sin(cone_angle / 2.0) );
Vector scaled_normal = scale_functor(normal, length_of_normal);
Vector scaled_normal = scale_functor(normal, normal_multiplier);
for(Disk_samples_list::const_iterator sample_it = disk_samples.begin(); for(Disk_samples_list::const_iterator sample_it = disk_samples.begin();
sample_it != disk_samples.end(); ++sample_it) { sample_it != disk_samples.end(); ++sample_it) {
@ -271,11 +277,17 @@ public:
Primitive_id closest_id; Primitive_id closest_id;
Vector disk_vector = sum_functor( Vector disk_vector = sum_functor(
scale_functor(v1, static_cast<typename GeomTraits::FT>(sample_it->get<0>())), scale_functor(v1, static_cast<FT>(disk_multiplier * sample_it->get<0>())),
scale_functor(v2, static_cast<typename GeomTraits::FT>(sample_it->get<1>())) ); scale_functor(v2, static_cast<FT>(disk_multiplier * sample_it->get<1>())) );
Vector ray_direction = sum_functor(scaled_normal, disk_vector); Vector ray_direction = sum_functor(scaled_normal, disk_vector);
Ray ray(center, ray_direction); Ray ray(center, ray_direction);
if(traits.is_degenerate_3_object()(ray)) {
CGAL_warning(false &&
"A degenerate ray is constructed. Most probable reason is using CGAL_PI as cone_angle parameter and also picking center of disk as a sample.");
}
boost::tie(is_intersected, intersection_is_acute, min_distance, closest_id) boost::tie(is_intersected, intersection_is_acute, min_distance, closest_id)
= cast_and_return_minimum(ray, skip, accept_if_acute); = cast_and_return_minimum(ray, skip, accept_if_acute);