diff --git a/include/mapnik/geometry_iterator.hpp b/include/mapnik/geometry_iterator.hpp index 29a2d2d7c..f12fda8d8 100644 --- a/include/mapnik/geometry_iterator.hpp +++ b/include/mapnik/geometry_iterator.hpp @@ -33,6 +33,20 @@ 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 class geometry_iterator : public boost::iterator_adaptor, @@ -44,14 +58,32 @@ public: typedef Value value_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::iterator_adaptor_(0), geometry_(geometry), 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), first_value_(new Value(0,0,0,0,0)) { @@ -60,6 +92,10 @@ public: 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 geometry_iterator(geometry_iterator const& other, typename boost::enable_if, @@ -67,29 +103,55 @@ public: : geometry_iterator::iterator_adaptor_(other.base()) {} private: + + // grant access to iterator_adaptor to handle iteration properly. friend class boost::iterator_core_access; + /*! + * @brief Advance the iterator. + */ void increment() { + // variables used to extract vertex components. geometry_type::value_type x; geometry_type::value_type y; + + // extract next vertex components. unsigned cmd = geometry_.vertex(&x, &y); 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; } 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); this->base_reference() = first_value_.get(); } else { + // point the reference to the current element to the next. *(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 bool equal(geometry_iterator const& other) const { @@ -100,6 +162,11 @@ private: boost::shared_ptr 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, geometry_type> geometry_iterator_type; } diff --git a/include/mapnik/svg/svg_output_grammars.hpp b/include/mapnik/svg/svg_output_grammars.hpp index d25295ea8..bce3f1603 100644 --- a/include/mapnik/svg/svg_output_grammars.hpp +++ b/include/mapnik/svg/svg_output_grammars.hpp @@ -102,18 +102,15 @@ namespace boost { namespace spirit { namespace traits { template <> struct container_iterator { - //typedef mapnik::geometry_type::iterator type; typedef mapnik::geometry_iterator_type type; }; template <> struct begin_container { - //static mapnik::geometry_type::iterator static mapnik::geometry_iterator_type call(mapnik::geometry_type const& g) { - //return g.begin(); return mapnik::geometry_iterator_type(0, g); } }; @@ -121,11 +118,9 @@ namespace boost { namespace spirit { namespace traits { template <> struct end_container { - //static mapnik::geometry_type::iterator static mapnik::geometry_iterator_type call(mapnik::geometry_type const& g) { - //return g.end(); return mapnik::geometry_iterator_type(g); } };