geometry_iterator code documentation.

This commit is contained in:
Carlos López 2011-02-07 01:45:29 +00:00
parent 4720303507
commit 6f6b161c7c
2 changed files with 69 additions and 7 deletions

View file

@ -33,6 +33,20 @@
namespace mapnik { namespace mapnik {
/*
* @brief Iterator class used to iterate over geometry vertexes.
* Since mapnik::geometry provides access to the components of
* a vertex only through variables passed by reference,
* geometry_iterator retrieves these components (command, x coord,
* and y coord) and makes them available inside tuples.
*
* This iterator exposes the behavior of a forward iterator and
* subclasses boost::iterator_adaptor, which already implements
* several iterator operations, such as dereferencing.
*
* @tparam Value the type of sequence element dereferenced.
* @tparam Container the sequence over which it iterates.
*/
template <typename Value, typename Container=geometry_type> template <typename Value, typename Container=geometry_type>
class geometry_iterator class geometry_iterator
: public boost::iterator_adaptor<geometry_iterator<Value, Container>, : public boost::iterator_adaptor<geometry_iterator<Value, Container>,
@ -44,14 +58,32 @@ public:
typedef Value value_type; typedef Value value_type;
typedef Container container_type; typedef Container container_type;
/*!
* @brief Constructor that initializes the reference to the current element to null.
* This constructor is suitable to mark the end of the iterator (analogous to
* calling end_iterator() in an STL container).
*
* @param geometry the geometry that handles the vector of vertexes.
*/
geometry_iterator(Container const& geometry) geometry_iterator(Container const& geometry)
: geometry_iterator::iterator_adaptor_(0), : geometry_iterator::iterator_adaptor_(0),
geometry_(geometry), geometry_(geometry),
first_value_(new Value(0,0,0,0,0)) first_value_(new Value(0,0,0,0,0))
{} {}
explicit geometry_iterator(Value* p, Container const& geometry) /*!
: geometry_iterator::iterator_adaptor_(p), * This constructor receives the first element of the sequence as a pointer.
* Since the container type will likely be a mapnik::geometry, this
* first element would need to be obtained in a similar way as the increment
* method below. For this reason, most of the time this constructor will
* be called with a null pointer. The body of the constructor makes a call
* to increment() in order to obtain this first element from the container.
*
* @param p pointer to the first element of the sequence.
* @param geometry the geometry that handles the vector of vertexes.
*/
explicit geometry_iterator(Value* first_element, Container const& geometry)
: geometry_iterator::iterator_adaptor_(first_element),
geometry_(geometry), geometry_(geometry),
first_value_(new Value(0,0,0,0,0)) first_value_(new Value(0,0,0,0,0))
{ {
@ -60,6 +92,10 @@ public:
struct enabler {}; struct enabler {};
/*!
* @brief Constructor that enables operation between const and non-const iterators.
* @sa http://www.boost.org/doc/libs/1_45_0/libs/iterator/doc/iterator_facade.html#interoperability
*/
template <typename OtherValue> template <typename OtherValue>
geometry_iterator(geometry_iterator<OtherValue> const& other, geometry_iterator(geometry_iterator<OtherValue> const& other,
typename boost::enable_if<boost::is_convertible<OtherValue*, Value*>, typename boost::enable_if<boost::is_convertible<OtherValue*, Value*>,
@ -67,29 +103,55 @@ public:
: geometry_iterator::iterator_adaptor_(other.base()) {} : geometry_iterator::iterator_adaptor_(other.base()) {}
private: private:
// grant access to iterator_adaptor to handle iteration properly.
friend class boost::iterator_core_access; friend class boost::iterator_core_access;
/*!
* @brief Advance the iterator.
*/
void increment() void increment()
{ {
// variables used to extract vertex components.
geometry_type::value_type x; geometry_type::value_type x;
geometry_type::value_type y; geometry_type::value_type y;
// extract next vertex components.
unsigned cmd = geometry_.vertex(&x, &y); unsigned cmd = geometry_.vertex(&x, &y);
if(cmd == SEG_END) if(cmd == SEG_END)
{ {
// if the end of the sequence is reached, set the reference
// to the current element to null, so it matches the value
// that marks the end of the sequence as defined in the
// "end_iterator" constructor.
this->base_reference() = 0; this->base_reference() = 0;
} }
else if(this->base_reference() == 0) else if(this->base_reference() == 0)
{ {
// the first element of the container is stored in the
// member variable 'first_value_' and later assigned
// to the reference that boost::iterator_adaptor stores
// to track the current element.
//
// 'first_value_' is used as intermediate storage
// because the compiler prohibits the assignment of the
// address of a temporary object (&Value(...)).
*first_value_ = Value(cmd, x, y, x, y); *first_value_ = Value(cmd, x, y, x, y);
this->base_reference() = first_value_.get(); this->base_reference() = first_value_.get();
} }
else else
{ {
// point the reference to the current element to the next.
*(this->base_reference()) = Value(cmd, x, y, x, y); *(this->base_reference()) = Value(cmd, x, y, x, y);
} }
} }
/*!
* @brief Test whether the current element is equal to 'other'.
* @tparam OtherValue the value type of the other iterator (it may be const or non-const).
* @param other iterator to compare to current element.
*/
template <typename OtherValue> template <typename OtherValue>
bool equal(geometry_iterator<OtherValue, Container> const& other) const bool equal(geometry_iterator<OtherValue, Container> const& other) const
{ {
@ -100,6 +162,11 @@ private:
boost::shared_ptr<Value> first_value_; boost::shared_ptr<Value> first_value_;
}; };
/*!
* @brief Specialization of geometry_iterator, as needed by mapnik::svg::svg_path_data_grammar.
* The Value type is a boost::tuple that holds 5 elements, the command and the x and y coordinate.
* Each coordinate is stored twice to match the needs the grammar.
*/
typedef geometry_iterator<boost::tuple<unsigned, geometry_type::value_type, geometry_type::value_type, geometry_type::value_type, geometry_type::value_type>, geometry_type> geometry_iterator_type; typedef geometry_iterator<boost::tuple<unsigned, geometry_type::value_type, geometry_type::value_type, geometry_type::value_type, geometry_type::value_type>, geometry_type> geometry_iterator_type;
} }

View file

@ -102,18 +102,15 @@ namespace boost { namespace spirit { namespace traits {
template <> template <>
struct container_iterator<mapnik::geometry_type const> struct container_iterator<mapnik::geometry_type const>
{ {
//typedef mapnik::geometry_type::iterator type;
typedef mapnik::geometry_iterator_type type; typedef mapnik::geometry_iterator_type type;
}; };
template <> template <>
struct begin_container<mapnik::geometry_type const> struct begin_container<mapnik::geometry_type const>
{ {
//static mapnik::geometry_type::iterator
static mapnik::geometry_iterator_type static mapnik::geometry_iterator_type
call(mapnik::geometry_type const& g) call(mapnik::geometry_type const& g)
{ {
//return g.begin();
return mapnik::geometry_iterator_type(0, g); return mapnik::geometry_iterator_type(0, g);
} }
}; };
@ -121,11 +118,9 @@ namespace boost { namespace spirit { namespace traits {
template <> template <>
struct end_container<mapnik::geometry_type const> struct end_container<mapnik::geometry_type const>
{ {
//static mapnik::geometry_type::iterator
static mapnik::geometry_iterator_type static mapnik::geometry_iterator_type
call(mapnik::geometry_type const& g) call(mapnik::geometry_type const& g)
{ {
//return g.end();
return mapnik::geometry_iterator_type(g); return mapnik::geometry_iterator_type(g);
} }
}; };