History and design
There was a great need for a canvas in the wxWidgets Library. Robert Roebling started something called wxCanvas and soon I took over. The original wxCanvas was pixel based and the idea was to render the primitives directly into an RGB buffer. However I realized that this path would be difficult to follow.
Abstract Drawing Context for vector drawings
I therefore decided to create an abstract Drawing Context that uses the native API for drawing. It is implemented in a way that implementing different drawing methods is easy. So now it is a matter of implementing another derived drawing context in order to draw to a different device, window or pixel buffer. The drawing context is specifically designed for drawing vectors in relative world coordinates. Relative here means that an affine transform can be set to the drawing context. Everything drawn will be transformed with that matrix first. To achieve speed, this is combined with the world to device coordinates transformation. The style properties of primitives are smart pointer based, reference counted and derived from abstract classes. This makes it easy to add new style types. More importantly style changes can be quickly compared, and updated if a change in style is required.
Multi Document Multi View
After a while I wanted to use the a2dCanvas as part of the wxWidgets DocView classes, but soon realized, I would not be able to do that with the existing wxWidgets DocView classes. After a lot of developent and experimentation the a new wxArt2D document/view/commandprocessor framework came to life. This change made it possible to add views like a2dCanvasView to a library, and let the user application display a desired View to a Window. Moreover, an extensive range of events are distributed, which help the application in having them handled within the framework. The main idea of the DocView framework, is that the drawing primitives are stored in a document and that several views can be created to view desired parts of the document. The a2dCanvasDocument is a document containing the graphical data and consists of a list of graphical primitives stored in one or more a2dDrawing. Each Graphical object is derived from a a2dCanvasObject class, and this class can have child objects and properties. A document contains one a2dDrawing, and the rest of the document's graphical content is included by adding nested children to this root drawing. Each a2dCanvasObject has a transform matrix to place itself in the world coordinate system relative to its parent object, with each child object placed relative to the object itself.
The drawing context, is used to draw what is in a a2dDrawing. Which part of the drawing will be visible in a canvas window, is defined in a2dDrawingPart. Changed objects in the drawing are redrawn automatically and efficiently. The bounding boxes which are maintained throughout the drawing hierarchy, and used to optimize redraws. Only objects overlapping the drawing boxes of the changed objects will be redrawn.
Another requirement was to be able to draw the same sub drawing in several places, without having to duplicate the drawing, this is achieved by reference counting pointers to a2dCanvasObject. Therefore it is possible to add the same a2dCanvasObject ( and its children) to two parent objects. During the rendering, paths from both parents will be followed and this will result in the same object being drawn at two positions.
The same reference counting system is used for properties to a2dCanvasObjects. All style properties like color for filling and stroking are implemented as dynamic properties, and objects that have no properties will not use memory space for them.
From the beginning, I wanted to be able to place objects on layers, and have the layers drawn in a set order. In this way the layer order defines how objects are stacked. All objects on a layer (and nested objects if desired) are drawn in a row, followed by the next layer etc.
Every a2dCanvas which displays part of a drawing, can have tools plugged into it. The events are redirected from the canvas to the tools. There is a broad range of tools to interactively draw primitives and change views. They are stack based, making it possible to pan and zoom while busy drawing.
Object can have editing implemented, all editing data needed is implemented using dynamic properties, and therefore only uses memory space when the object is being edited. Because of the stack based nature of the tools, editing tools can also recursively edit children of a2dCanvasObject. This makes it possible to implement editing of complex object like curves in a plot.