cgal/Envelope_3/include/CGAL/Envelope_caching_traits_3.h

255 lines
8.3 KiB
C++

// Copyright (c) 2005 Tel-Aviv University (Israel).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL distributed with CGAL.
//
// 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.
//
// $Source: /CVSROOT/CGAL/Packages/Envelope_3/include/CGAL/Envelope_caching_traits_3.h,v $
// $Revision$ $Date$
// $Name: $
//
// Author(s) : Michal Meyerovitch <gorgymic@post.tau.ac.il>
#ifndef ENVELOPE_CACHING_TRAITS_3_H
#define ENVELOPE_CACHING_TRAITS_3_H
/*! \file
* The caching traits class for the envelope package.
*/
#include <map>
CGAL_BEGIN_NAMESPACE
/*!
* \class A decorator for a traits class of the envelope divide-and-conquer
* algorithm, adding a caching ability.
*/
template <class EnvelopeTraits_3>
class Envelope_caching_traits_3 : public EnvelopeTraits_3
{
public:
typedef EnvelopeTraits_3 Base_traits_3;
typedef Envelope_caching_traits_3<Base_traits_3> Self;
typedef typename Base_traits_3::Point_2 Point_2;
typedef typename Base_traits_3::Curve_2 Curve_2;
typedef typename Base_traits_3::X_monotone_curve_2 X_monotone_curve_2;
typedef typename Base_traits_3::Surface_3 Surface_3;
typedef typename Base_traits_3::Xy_monotone_surface_3 Xy_monotone_surface_3;
protected:
typedef std::pair<Curve_2, Intersection_type> Intersection_curve;
// caching for intersections
typedef std::list<Object> Intersections_list;
typedef std::pair<Xy_monotone_surface_3,
Xy_monotone_surface_3> Surface_pair;
struct Less_surface_pair
{
bool operator() (const Surface_pair& sp1,
const Surface_pair& sp2) const
{
// Compare the pairs of IDs lexicographically.
return (sp1.first < sp2.first ||
(sp1.first == sp2.first && sp1.second < sp2.second));
}
};
// caching for construct_projected_intersections traits method's result
typedef std::map<Surface_pair,
Intersections_list, Less_surface_pair> Intersections_cache;
// caching for compare_distance_to_envelope traits method's result
typedef std::map<Surface_pair,
Comparison_result, Less_surface_pair> Compare_cache;
public:
class Construct_projected_intersections_2
{
protected:
const Self& parent;
Intersections_cache& inter_cache;
unsigned int& intersections_number;
public:
Construct_projected_intersections_2(const Self* p,
Intersections_cache& inter,
unsigned int& inter_num)
: parent(*p), inter_cache(inter),
intersections_number(inter_num)
{}
// insert into OutputIterator all the (2d) projections on the xy plane of
// the intersection objects between the 2 surfaces
// the data type of OutputIterator is Object
template <class OutputIterator>
OutputIterator
operator()(const Xy_monotone_surface_3& s1,
const Xy_monotone_surface_3& s2,
OutputIterator o) const
{
Intersections_list inter_list;
typename Intersections_cache::iterator cache_iter;
Surface_pair spair(s1, s2);
// search for this pair in the cache
cache_iter = inter_cache.find(spair);
if (cache_iter == inter_cache.end())
{
parent.Base_traits_3::construct_projected_intersections_2_object()
(s1, s2, std::back_inserter(inter_list));
inter_cache[spair] = inter_list;
// update statistics
if (inter_list.size() > 0)
++intersections_number;
}
else
{
inter_list = (*cache_iter).second;
}
// report intersections
typename Intersections_list::const_iterator iter;
for (iter = inter_list.begin(); iter != inter_list.end(); ++iter)
*o++ = *iter;
return o;
}
};
/*! Get a Construct_projected_intersections_2 functor object. */
Construct_projected_intersections_2
construct_projected_intersections_2_object() const
{
return Construct_projected_intersections_2(this, inter_cache,
intersections_number);
}
class Compare_distance_to_envelope_3
{
protected:
const Self& parent;
Compare_cache& compare_cache;
public:
Compare_distance_to_envelope_3(const Self* p, Compare_cache& comp_cache)
: parent(*p), compare_cache(comp_cache)
{}
// check which of the surfaces is closer to the envelope at the xy
// coordinates of point (i.e. lower if computing the lower envelope, or
// upper if computing the upper envelope)
// precondition: the surfaces are defined in point
Comparison_result operator()(const Point_2& p,
const Xy_monotone_surface_3& s1,
const Xy_monotone_surface_3& s2) const
{
return compare_distance_to_envelope(p,s1,s2);
}
// check which of the surfaces is closer to the envelope at the xy
// coordinates of cv (i.e. lower if computing the lower envelope, or upper
// if computing the upper envelope)
// precondition: the surfaces are defined in all points of cv, and the
// answer is the same for each of these points
Comparison_result operator()(const X_monotone_curve_2& cv,
const Xy_monotone_surface_3& s1,
const Xy_monotone_surface_3& s2) const
{
return compare_distance_to_envelope(cv,s1,s2);
}
protected:
template <class Geometry>
Comparison_result compare_distance_to_envelope(Geometry& g,
const Xy_monotone_surface_3& s1,
const Xy_monotone_surface_3& s2) const
{
// check that s1 and s2 do not intersect
Intersections_list inter_list;
parent.construct_projected_intersections_2_object()(s1, s2,
std::back_inserter(inter_list));
// if they do not intersect, we can use the cache
if (inter_list.empty())
{
// then we should check the cache of compare_distance, and only if it's empty
// use the traits
Surface_pair spair(s1, s2);
typename Compare_cache::iterator comp_cache_iter;
comp_cache_iter = compare_cache.find(spair);
if (comp_cache_iter == compare_cache.end())
{
Comparison_result res =
parent.Base_traits_3::compare_distance_to_envelope_3_object()(g, s1, s2);
compare_cache[spair] = res;
return res;
}
else
return (*comp_cache_iter).second;
}
else
// they intersect, so must use the traits
return parent.Base_traits_3::compare_distance_to_envelope_3_object()(g, s1, s2);
}
};
/*! Get a Compare_distance_to_envelope_3 functor object. */
Compare_distance_to_envelope_3
compare_distance_to_envelope_3_object() const
{
return Compare_distance_to_envelope_3(this, compare_cache);
}
Envelope_caching_traits_3() : Base_traits_3(), intersections_number(0)
{}
virtual ~Envelope_caching_traits_3()
{
reset();
}
// methods for benchmarks
void reset()
{
intersections_number = 0;
inter_cache.clear();
compare_cache.clear();
}
void print_bench() const
{
std::cout << intersections_number;
}
void print_bench_header() const
{
std::cout << "projected intersections# ";
}
void print_statistics() const
{
std::cout << "number of projected intersection found: "
<< intersections_number << std::endl;
}
protected:
mutable Intersections_cache inter_cache;
mutable unsigned int intersections_number;
mutable Compare_cache compare_cache;
};
CGAL_END_NAMESPACE
#endif