? install-sh ? missing ? mkinstalldirs ? releases ? cairomm/.context.cc.swp ? cairomm/.context.h.swp ? cairomm/.path.h.swp ? examples/path-iter Index: configure.in =================================================================== RCS file: /cvs/cairo/cairomm/configure.in,v retrieving revision 1.14 diff -u -5 -p -r1.14 configure.in --- configure.in 9 May 2006 01:50:57 -0000 1.14 +++ configure.in 12 May 2006 02:45:00 -0000 @@ -129,10 +129,11 @@ AC_CONFIG_FILES( examples/png_file/Makefile examples/pdf-surface/Makefile examples/ps-surface/Makefile examples/svg-surface/Makefile examples/text-rotate/Makefile + examples/path-iter/Makefile cairomm-1.0.pc ) AC_OUTPUT() Index: cairomm/path.cc =================================================================== RCS file: /cvs/cairo/cairomm/cairomm/path.cc,v retrieving revision 1.4 diff -u -5 -p -r1.4 path.cc --- cairomm/path.cc 6 Mar 2006 17:55:51 -0000 1.4 +++ cairomm/path.cc 12 May 2006 02:45:01 -0000 @@ -91,8 +91,63 @@ bool Path::operator==(const Path& src) c { return cairo_path_equal(m_cobject, src.cobj()); } */ + +/*************************************************** + * Path::Element + ***************************************************/ + +Path::Element::Element(cobject* pData) : + m_cobject(pData) +{} + + +int Path::Element::size(void) +{ + // we only want the count of data points so subtract one to ignore the header + return (m_cobject->header.length) - 1; +} + + +Path::Element::Point Path::Element::operator[](unsigned int idx) +{ + if (idx >= size()) + { + throw std::out_of_range("Invalid array index"); + } + /* since this is zero-based, and the zero-th element of the underlying C array + * is actually the header element, we need to add one to the idx to access the + * correct member of the array */ + cobject* p = m_cobject + (idx + 1); + Point pt = {p->point.x, p->point.y}; + return pt; +} + + +/*************************************************** + * Path::iterator + ***************************************************/ +Path::iterator::iterator(cairo_path_data_t* path_data) : + m_node(path_data) +{} + + +Path::iterator& Path::iterator::operator++(void) // pre-increment +{ + // need to add one more than size() in order to skip the header as well. + m_node.reset(m_node.cobj() + m_node.size() + 1); + return *this; +} + + +Path::iterator Path::iterator::operator++(int) // post-increment +{ + iterator tmp = *this; + operator++(); + return tmp; +} + } //namespace Cairo // vim: ts=2 sw=2 et Index: cairomm/path.h =================================================================== RCS file: /cvs/cairo/cairomm/cairomm/path.h,v retrieving revision 1.7 diff -u -5 -p -r1.7 path.h --- cairomm/path.h 9 May 2006 03:38:35 -0000 1.7 +++ cairomm/path.h 12 May 2006 02:45:01 -0000 @@ -17,10 +17,13 @@ */ #ifndef __CAIROMM_PATH_H #define __CAIROMM_PATH_H +#include +#include + #include #include #include @@ -29,23 +32,32 @@ namespace Cairo /** A data structure for holding a path. * Use Context::copy_path() or Context::copy_path_flat() to instantiate a new * Path. The application is responsible for freeing the Path object when it is * no longer needed. - * - * \todo There's currently no way to access the path data without reverting to - * the C object (see cobj()) + * To access the path data, use begin() and end() to iterate through the Path + * Elements + * \sa Path::Element, Path::iterator */ class Path { public: + class iterator; //Path(); explicit Path(cairo_path_t* cobject, bool take_ownership = false); //Path(const Path& src); virtual ~Path(); + /** Returns an iterator pointing to the first Element of the Path + */ + inline iterator begin() const { return iterator(m_cobject->data); } + + /** Returns an iterator that is one past the last Element of the Path + */ + inline iterator end() const { return iterator(m_cobject->data + m_cobject->num_data); } + //Path& operator=(const Path& src); //bool operator ==(const Path& src) const; //bool operator !=(const Path& src) const; @@ -61,10 +73,115 @@ public: #endif //DOXYGEN_IGNORE_THIS protected: cobject* m_cobject; + +public: + typedef enum + { + MOVE_TO = CAIRO_PATH_MOVE_TO, + LINE_TO = CAIRO_PATH_LINE_TO, + CURVE_TO = CAIRO_PATH_CURVE_TO, + CLOSE_PATH = CAIRO_PATH_CLOSE_PATH, + } ElementType; + + + /** A single element of a path. Each element has a 'type', which determines + * how many Points are contained in this element. use the subscript operator + * [] to access the sub-points + * + * Note that most people will rarely need access to the underlying path data, + * so this will not be needed very often. + */ + class Element + { + public: + /** The base C cairo type */ + typedef cairo_path_data_t cobject; + + Element(cobject* pData); + + /** reset this Element to use the base C cairo type specified by pData + * This is ugly, I know. Hopefully I'll find a better way to do it soon. + * The reason I've implemented it this way is so that the iterator can + * contain a single Element instance and just shift what it's pointing at + * instead of creating new Element objects whenever the iterator is + * incremented. + * I thought about just storing a pointer to the base C type in the + * iterator, but the problem is that operator* needs to return a reference + * type, so you need to have a Element object to return a reference to... + */ + inline void reset(cobject* pData) { m_cobject = pData; } + + /** get a pointer to the base cairo type */ + inline cobject* cobj() { return m_cobject; } + /** get a const pointer to the base cairo type */ + inline const cobject* cobj() const { return m_cobject; } + + /** A simple structure for holding an X and Y coordinate pair */ + struct Point + { + double x, y; + }; + + /** You can access the datapoints that make up a path Element by using + * array notation. The index is zero-based, so element[0] gives you the + * first point + * \throw out_of_range on invalid idx + */ + Point operator[](unsigned int idx); + + /** Get the number of points in this path element. This is tightly + * coupled with the type of Path Element that it is. MOVE_TO and + * LINE_TO both have a single data point, CURVE_TO has three + * data points, and CLOSE_PATH has none + */ + int size(void); + + /** Gets the type of element for this path element + */ + ElementType type(void) + { return static_cast(m_cobject->header.type); } + + protected: + cobject* m_cobject; + + }; + + /** A custom iterator for iterating over a Path. This is made slightly + * complicated because each element can have different numbers of + * sub-elements, so advancing the iterator must advance the base pointer a + * different amount based on the current element. + * + * Also, because of the way the base cairo path structure is set up, you can + * only traverse the list forward, because the only guarantee about the + * structure is that the first element is a header type which tells the + * location of the next header. + */ + class iterator : public std::iterator + { + friend class Path; + public: + inline bool operator==(const iterator& iter) const + { return m_node.cobj() == iter.m_node.cobj(); } + inline bool operator!=(const iterator& iter) const + { return ! (*this == iter); } + iterator& operator++(void); // pre-increment + + iterator operator++(int); // post-increment + + inline reference operator*() { return m_node; } + inline pointer operator->() { return &m_node; } + + protected: + iterator(cairo_path_data_t* path_data); + + value_type m_node; + + }; + }; } // namespace Cairo #endif //__CAIROMM_PATH_H Index: examples/Makefile.am =================================================================== RCS file: /cvs/cairo/cairomm/examples/Makefile.am,v retrieving revision 1.4 diff -u -5 -p -r1.4 Makefile.am --- examples/Makefile.am 15 Mar 2006 01:42:52 -0000 1.4 +++ examples/Makefile.am 12 May 2006 02:45:01 -0000 @@ -1,3 +1,3 @@ -SUBDIRS = png_file pdf-surface ps-surface svg-surface text-rotate +SUBDIRS = png_file pdf-surface ps-surface svg-surface text-rotate path-iter EXTRA_DIST = README Makefile.am_fragment