Now it's all about path_storage and the internal containers. I've got fair criticism that it was too expensive to create many path_storage objects. Each of them allocated memory for at least 256 vertices. That's true and in certain cases it caused huge memory overhead. Now I separated the path_storage functionality from used containers so that, you can use std::vector or std::deque if you wish. Now path_storage is declared as: typedef path_base<vertex_block_storage<double> > path_storage; And it has exactly the same functionality and behaviour as the former path_storage. But now it's much more flexible. path_base is just a wrapper over some vertex container that provides traditional path interface (move_to/line_to/etc) and the VertexSource interface. vertex_block_storage is what was embedded in the path_storage. Now it's a template: template<class T, unsigned BlockShift=8, unsigned BlockPool=256> class vertex_block_storage . . . It means you can use floats or even integers for coordinates. Besides, you can change the block size. For example:
It means you can use floats or even integers for coordinates. Besides, you can change the block size. For example: typedef path_base<vertex_block_storage<float, 4, 16> > path_storage; will allocate memory for 16 vertices in floats and 16 pointers. But it's not only that. You can use any available container: struct vertex { typedef float value_type; float x,y; unsigned cmd; vertex() {} vertex(float x_, float y_, unsigned cmd_) : x(x_), y(y_), cmd(cmd_) {} }; typedef path_base<vertex_stl_storage<std::vector<vertex> > > path_storage; Here std::vector<vertex> will be used. vertex_stl_storage is an adaptor that provides the necessary functionality for path_base. The container must be compatible with random access STL one (std::list won't work) and have the following traits:
typedef "vertex_type" value_type; void clear(); void push_back(vertex_type); vertex_type& operator [] (unsigned idx); I have modified the internal AGG containers so that they are compatible with STL too. You can use: typedef path_base<vertex_stl_storage<pod_bvector<vertex> > > path_storage; The main difference between vertex_block_storage and vertex_stl_storage is in memory allocation strategy. vertex_block_storage is compact, but has constant memory overhead of at most 1<<BlockShift vertices. Also, it never reallocates memory, it only allocates new blocks of a constant size. But it's not a good idea to create thousands of path_storage objects, because that very "constant memory overhead" becomes significant. On the other hand you can use struct vertex { double x,y; unsigned char cmd; };
and std::vector<vertex>. But there is another problem. Struct vertex is aligned to the size of double and in general there's no way to avoid it. It means that instead of 17 bytes (8+8+1) it will have sizeof(vertex)=24. If you have one million vertices stored in one path, the difference becomes significant: 17 megs or 24 megs - it's about 40%. In this case it's much better to use vertex_block_storage and increase the block size: vertex_block_storage<double, 12> Here we will have blocks of 1<<12=4096 vertices. The bottom line is. If you want to create one path_storage with huge number of vertices it's better to use vertex_block_storage. If you want to create many objects with just few vertices it's better to use vertex_stl_storage adaptor. But there's no universal solution, it all depends on the container. Well, you can also write your own container. Also, there's a way to use a very lightweight container that will not allocate any memory in heap: // Here we declare a very cheap-in-use path storage. // It allocates space for at most 20 vertices in stack and // never allocates memory. But be aware that adding more than // 20 vertices is fatal! //------------------------ typedef agg::path_base< agg::vertex_stl_storage< agg::pod_auto_vector< agg::vertex_d, 20> > > path_storage_type; path_storage_type path; pod_auto_vector allocates memory in stack and if you are absolutely sure you never add more than 20 vertices you can use it. It can be important in some wrappers for basic shapes that expose the VertexSource interface. It's all may be important in embedded programming, for example. =========================
Another change is with add_path. It was very confusing. Now there're are two functions: concat_path(path, path_id); join_path(path, path_id); The first one just adds the path "as is" and it's equivalent to former add_path(path, 0, false); The second one joins the vertices, that is, continues the path ignoring "move_to" commands. It works as if you had a protter with broken pen mechanism and the pen was always down. Besides, join_path removes the first vertex if it coincides with the last one in the existing path. It's important in "arc_to" Stephan noticed. Both functions are important and thre was some confusion. Also, I have added some utility classes: poly_plain_adaptor line_adaptor It's not that considerable, but might be useful in some cases. For example, methods concat_poly and join_poly use this poly_plain_adaptor internally. ============================= Renames: I have renamed container classes. pod_deque -> pod_bvector Deque is a neologism that refers to "Double End QUEue". agg::pod_deque was a container that was organized in a similar way as std::deque, but it hadn't method push_front. So, it's just a block container that never reallocates memory. There's no analog in STL. Other renames: pod_array -> pod_vector pod_heap_array -> pod_array And added pod_auto_vector.
The difference between "vector" and "array" is that vector requires to call add(element) to increase the size (std::vector-like behaviour). "array" has always constant size and it basically is a simple wrapper over memory allocation. Note: I don't want to discuss "reinventing the wheel" issues. Mostly because STL doesn't have adequate containers. BOOST has them, but it's not a standard. BOOST is the last resort for AGG. As soon as AGG depends on BOOST you can bury it. :-) ============================== Qestions: 1. I don't like name path_base. Could you suggest some other one? 2. path_storage is defined as it was before (same behaviour and functionality). I feel there can be several different pre-defined (typedefed) storages. Please suggest some. It also makes sense to rename path_storage. What would be the best name for a "path storage that allocates memory in blocks of 256 vertices and keeps data compact"? 3. Do you feel comfortable with concat_path/join_path? 4. Any other suggestions about all that stuff?